GPU profili oluşturma (Önizleme) ile Azure Kubernetes Service (AKS) üzerinde GPU iş yüklerini iyileştirme

Yapay zeka çıkarım hizmetleri gibi GPU tabanlı iş yükleri bellek yoğunluklu olabilir ve GPU'nin gerçekte ne yaptığına ilişkin derin görünürlük olmadan iyileştirmesi ve hatalarını ayıklaması zor olabilir. Bellek yetersiz (OOM) hataları, beklenmeyen gecikme süresi artışları veya artan GPU bellek baskısı görebilirsiniz, ancak geleneksel Kubernetes ölçümleri size kodun neresinde belleğin ayrıldığını söylemez. Profil oluşturma, GPU bellek kullanımından sorumlu tam işlevleri anlamanıza yardımcı olur.

Important

AKS önizleme özellikleri self servis ve kabul temelinde kullanılabilir. Önizlemeler "olduğu gibi" ve "mevcut olduğu şekilde" sağlanmakta olup, hizmet seviyesi anlaşmalarına ve sınırlı garantilere dahil edilmemektedir. AKS önizlemeleri, müşteri desteği ekibi tarafından maksimum çaba gösterilerek kısmen ele alınmaktadır. Bu nedenle, bu özellikler üretim kullanımı için tasarlanmamıştır. Daha fazla bilgi için aşağıdaki destek makalelerine bakın:

Bu makale, AKS'de GPU gözlemlenebilirliğini kullanma konusunda size yol gösterir:

  1. Gerçek zamanlı GPU gözlemlenebilirlik aracısını dağıtın; GPU bellek ayırmalarını izlemek ve profillerini almak için eBPF tabanlı izleme kullanın.
  2. Alev grafiklerini okuyun: En fazla GPU belleği kullanan tam işlevleri bulmak için profil oluşturma çıkışını nasıl yorumlayacağınızı öğrenin.

Important

AKS dokümantasyonu ve örneklerinde açık kaynaklı yazılımdan bahsedilmektedir. Dağıttığınız yazılım, AKS hizmet düzeyi anlaşmalarından, sınırlı garanti ve Azure desteğinden hariç tutulur. AKS ile birlikte açık kaynak teknolojisini kullanırken, bir plan geliştirmek için ilgili topluluklar ve proje sorumlularından mevcut olan destek seçeneklerine danışın.

Microsoft, AKS üzerinde dağıttığımız açık kaynak paketlerinin oluşturulmasından sorumluluk alır. Bu sorumluluk, yapı, tarama, imzalama, doğrulama ve hızlı düzeltme sürecinin tam sahipliğini içermenin yanı sıra, konteyner görüntülerindeki ikili dosyaların kontrolünü de kapsar. Daha fazla bilgi için AKS için güvenlik açığı yönetimi ve AKS destek kapsamı başlıklarına bakın.

GPU gözlemlenebilirliğini dağıtma - AKS üzerinde GPU bellek profili oluşturma

Prerequisites

  • En az bir GPU etkin düğüm havuzuna sahip bir AKS kümesi.
  • Azure CLI sürüm 2.72.0 veya üzeri yüklü. Denetlemek için komutunu çalıştırın az --version .
  • Azure CLI k8s-extension eklentisi yüklendi. Yüklemek için komutunu çalıştırın az extension add --name k8s-extension .
  • Helm sürüm 3.x veya üzeri yüklü. Denetlemek için komutunu çalıştırın helm version .
  • Azure İzleyici (isteğe bağlı olarak, tercih ederseniz kendi izleme kurulumunuzu kullanabilir).
  • Azure Managed Grafana (görselleştirme için isteğe bağlı).

1. Adım: Inspektor Aracı uzantısı aracılığıyla GPU profili oluşturmayı etkinleştirme

Inspektor Gadget, Kubernetes için açık kaynak eBPF tabanlı bir gözlemlenebilirlik çerçevesidir. GPU profillemesi için, kod değişiklikleri, sidecar'lar veya pod yeniden başlatmaları gerektirmeden Compute Unified Device Architecture (CUDA) bellek ayırma çağrılarını izler. Aşağıdaki uzantı komutunu çalıştırarak AKS kümenizde GPU profili oluşturmayı etkinleştirin:

az k8s-extension create \
  --extension-type microsoft.inspektorgadget \
  --subscription <your-subscription-id> \
  -g <your-resource-group> \
  -c <your-cluster-name> \
  -t managedClusters \
  --release-train preview \
  -n inspektor-gadget \
  --configuration-settings gpuObservability.enabled=true \
  --configuration-settings azureMonitor.enabled=true \

Uyarı

Bu adımda AKS kümenizde Azure İzleyici zaten etkinleştirdiğiniz varsayılır. Kendi Prometheus kurulumunuzu kullanmayı planlıyorsanız kaldırın --configuration-settings azureMonitor.enabled=true.

Podların çalıştığını doğrulayın:

kubectl get pods -n gadget -l k8s-app=gadget

Tavsiye

GPU bellek profillemesi, bellek ayırma olaylarını meydana geldikçe yakalar. İş yükünüz GPU profili oluşturma etkinleştirilmeden önce GPU belleği ayırırsa, profil oluşturucu bu ayırma olaylarını yakalamaz. Başlatma sırasında GPU belleğini önceden ayıran vLLM gibi iş yükleri için, iş yükünü dağıtmadan önce GPU profili oluşturmayı etkinleştirin veya ilk bellek ayırma yollarını yakalamak için iş yükünü yeniden başlatın.

2. Adım: Pyroscope ile profil görselleştirmeyi etkinleştirme

Uyarı

Kümenizde mevcut bir Grafana/Pyroscope yığını varsa bu adımı atlayabilirsiniz.

Piroskop, bellek iyileştirme ve sorun giderme için gereken performans profillerini görselleştirmenize ve depolamanıza olanak tanıyan açık kaynak bir projedir. Kümenize tek bir Pyroscope örneği dağıtmak için aşağıdaki komutu çalıştırın:

helm install pyroscope -n gadget \
  oci://ghcr.io/grafana/helm-charts/pyroscope \
  --version 1.15.0 \
  --set pyroscope.image.repository=grafana/pyroscope \
  --set-string pyroscope.image.tag=1.15.0 \
  --set pyroscope.replicaCount=1 \
  --set pyroscope.structuredConfig.self_profiling.disable_push=true \
  --set pyroscope.structuredConfig.storage.backend=filesystem \
  --set pyroscope.service.type=LoadBalancer \
  --set pyroscope.service.port=4040 \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-internal"=true \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-create"=true \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-name"=pyroscope-pls \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-proxy-protocol"=false \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-visibility"='*' \
  --set alloy.enabled=false \
  --set minio.enabled=false

Podların çalıştığını doğrulayın:

kubectl get pods -n gadget pyroscope-0

Uyarı

Yüksek oranda kullanılabilir bir Pyroscope kurulumu dağıtmak istiyorsanız yapılandırma seçenekleri için Pyroscope mikro hizmetleri belgelerine bakın .

3. Adım: Pyroscope'u Azure Managed Grafana bağlama

Tavsiye

Pyroscope kullanıcı arabirimine bağlanmak için kullanarak kubectl port-forward -n gadget pyroscope-0 4040:4040 iş yükü profillerinizi doğrudan görüntüleyebilirsiniz.

Pyroscope'u Azure Managed Grafana bağlamak Grafana panolarındaki GPU profillerini görselleştirmenizi sağlar. AMG'nin Kubernetes podu olarak çalışan Pyroscope'a bağlanması için güvenli bir yönteme ihtiyacımız var, bu nedenle Azure Özel Bağlantı kullanarak bağlantıyı kuracağız. Kümeyle ilgili ortam değişkenlerini ayarlayarak başlayın:

export RESOURCE_GROUP="<your-resource-group>"
export AKS_CLUSTER="<your-aks-cluster-name>"
export LOCATION="<your-aks-cluster-location>"
export GRAFANA_NAME="<your-azure-managed-grafana-name>"
export AKS_NODE_RG=$(az aks show -g "$RESOURCE_GROUP" -n "$AKS_CLUSTER" --query 'nodeResourceGroup' -o tsv)

Tavsiye

Mevcut bir Azure Managed Grafana örneğiniz yoksa, bir örnek oluşturmak için komutunu çalıştırınaz grafana create -n "$GRAFANA_NAME" -g "$RESOURCE_GROUP" --location "$LOCATION" -o none.

Pyroscope'u Azure Managed Grafana bağlamak için özel bir uç nokta oluşturun. Özel uç nokta için değişkenleri dışarı aktarma:

export PYROSCOPE_PLS="pyroscope-pls"
export PYROSCOPE_MPE="pyroscope-mpe"
export PYROSCOPE_PORT="4040"

Özel bağlantıyı oluşturun:

Uyarı

Özel bağlantının oluşturulması birkaç dakika sürebilir.

# Check amg extension version
ver=$(az extension show --name amg --query version -o tsv)
[[ "${ver%%.*}" -ge 3 ]] && MPE="managed-private-endpoint" || MPE="mpe"

# Ensure Pyroscope PLS is present
until az network private-link-service show -n "$PYROSCOPE_PLS" -g "$AKS_NODE_RG" -o none 2>/dev/null; do
  sleep 10
done

# Get the PLS resource ID
PYRO_PLS_ID=$(az network private-link-service show \
  -n "$PYROSCOPE_PLS" -g "$AKS_NODE_RG" --query 'id' -o tsv)

# Create the MPE in Grafana
az grafana $MPE create \
  --workspace-name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --name "$PYROSCOPE_MPE" \
  --private-link-resource-id "$PYRO_PLS_ID" \
  --location "$LOCATION" -o none

# Wait for MPE to be ready
sleep 30

# Find the pending connection created by Grafana
PYRO_CONN=$(az network private-link-service show \
  -n "$PYROSCOPE_PLS" -g "$AKS_NODE_RG" \
  --query "privateEndpointConnections[?privateLinkServiceConnectionState.status=='Pending' && starts_with(name, 'grafana-${GRAFANA_NAME}')].name | [0]" -o tsv)

# Approve it
az network private-link-service connection update \
  --name "$PYRO_CONN" \
  --service-name "$PYROSCOPE_PLS" \
  --resource-group "$AKS_NODE_RG" \
  --connection-status Approved -o none

# Refresh Grafana so it sees the approval
az grafana $MPE refresh \
  --workspace-name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" -o none

echo "Successfully created private-link"

veri kaynağını Azure Managed Grafana oluşturun:

# Check amg extension version
ver=$(az extension show --name amg --query version -o tsv)
[[ "${ver%%.*}" -ge 3 ]] && MPE="managed-private-endpoint" || MPE="mpe"

# Grab the private IP
PYRO_IP=$(az grafana $MPE show \
  --workspace-name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --name "$PYROSCOPE_MPE" \
  --query 'privateLinkServicePrivateIP' -o tsv)

# Prepare Pyroscope URL
export PYROSCOPE_URL="http://${PYRO_IP}:${PYROSCOPE_PORT}"

# Create Pyroscope data source in Grafana
az grafana data-source create -n "$GRAFANA_NAME" -g "$RESOURCE_GROUP" --definition "{
  \"name\": \"local-pyroscope\",
  \"uid\": \"local-pyroscope\",
  \"type\": \"grafana-pyroscope-datasource\",
  \"access\": \"proxy\",
  \"url\": \"${PYROSCOPE_URL}\",
  \"jsonData\": { \"keepCookies\": [\"pyroscope_git_session\"] }
}" -o none

echo "Successfully created local-pyroscope data-source"

Uyarı

Kümenizde mevcut bir Grafana/Pyroscope yığını varsa bu adımı atlayabilirsiniz.

Veri kaynağının geçerli bir URL'si olduğunu doğrulayın:

az grafana data-source show -n $GRAFANA_NAME --data-source local-pyroscope

4. Adım: Grafana'yı Prometheus için yönetilen Azure İzleyici hizmete bağlama

Uyarı

Bu adımlar, Prometheus Azure İzleyici yönetilen hizmetini Grafana'ya bağlamayı temel alır. Grafana'nın yönetilen kimliğinin özellikle farklı bir kaynak grubunda veya abonelikteyse Azure İzleyici çalışma alanında İzleme Veri Okuyucusu rolüne sahip olduğundan emin olun.

Gerekli değişkenleri dışarı aktarın:

export AMP_NAME="<your-amp-workspace-name>"
export AMP_RESOURCE_GROUP="<your-amp-resource-group>"

Tavsiye

Azure İzleyici çalışma alanı bilgilerini listelemek için komutunu çalıştırınaz resource list --resource-type Microsoft.Monitor/accounts -g $AMP_RESOURCE_GROUP -o table. Azure İzleyici çalışma alanı genellikle AKS kümenizden ve Azure Managed Grafana örneğinden farklı bir kaynak grubundadır; örneğin, Yönetilen Prometheus bölgesel MA_<region>_<…> bir kaynak grubunda bir çalışma alanını otomatik olarak oluşturduğunda veya merkezi platform ekibi paylaşılan bir çalışma alanına sahip olduğunda. Bunun yerine aboneliğin tamamında arama yapmak için -g öğesini atlayın ve az resource list --resource-type Microsoft.Monitor/accounts -o table komutunu çalıştırın.

# Get AMW endpoint
AMP_ENDPOINT=$(az resource show --resource-type Microsoft.Monitor/accounts \
  -n "$AMP_NAME" -g "$AMP_RESOURCE_GROUP" \
  --query properties.metrics.prometheusQueryEndpoint -o tsv)

# Create Prometheus data source with MSI auth
az grafana data-source create -n "$GRAFANA_NAME" -g "$RESOURCE_GROUP" \
  --definition "{
    \"name\": \"$AMP_NAME\",
    \"type\": \"prometheus\",
    \"access\": \"proxy\",
    \"url\": \"$AMP_ENDPOINT\",
    \"jsonData\": {
      \"httpMethod\": \"POST\",
      \"azureCredentials\": { \"authType\": \"msi\" }
    }
  }"

Veri kaynağını doğrulayın:

az grafana data-source show -n $GRAFANA_NAME --data-source $AMP_NAME

5. Adım: Grafana'da panoları ayarlama

az grafana dashboard create \
  -n "$GRAFANA_NAME" \
  -g "$RESOURCE_GROUP" \
  --definition "$(curl -sSL https://raw.githubusercontent.com/inspektor-gadget/grafana-dashboards/refs/heads/main/dashboards/gpu-observability/AdvancedGPUObservability.json)"

Panoya şu konumdan erişin:

GRAFANA_URL=$(az grafana show -n "$GRAFANA_NAME" -g "$RESOURCE_GROUP" --query properties.endpoint -o tsv)

echo "${GRAFANA_URL}/d/AdvancedGPUObservability"

Grafana'da gösterilen alev grafiklerini okuma hakkında daha fazla bilgi için bkz. Alev grafiklerini okuma.

Kaynakları temizle

Küme içi GPU gözlemlenebilirlik yığınını kaldırmak için:

helm uninstall inspektor-gadget -n gadget
helm uninstall pyroscope -n gadget
kubectl delete namespace gadget

Alev grafiklerini okuma

Profil oluşturma verileri Pyroscope ve Grafana'ya akıtıldıktan sonra hangi işlevlerin en fazla GPU belleği tükettiğine ilişkin alev grafiklerini görürsünüz. Aşağıdaki bölümlerde bu görselleştirmelerin nasıl okunduğu açıklanmaktadır.

Alev grafiği nedir?

Alev grafiği, profili oluşturulmuş çağrı yığınlarının görselleştirmesidir. Her çubuk bir fonksiyonu temsil eder ve hangi fonksiyonun hangisini çağırdığını gösteren çağrı zincirini göstermek için çubuklar üst üste yığılır. Her çubuğun genişliği, bu işlevden geçen ölçülen kaynağın miktarını (CPU süresi, ayrılan GPU belleği vb.) temsil eder.

Temel kural: Çubuk ne kadar genişse, ölçülen kaynağın o işlevden geçen miktarı o kadar fazla olur.

Aşağıdaki örnek alev grafikleri bir vLLM çıkarım iş yükünden yakalanır.

Gpu bellek ayırma çağrı yığınlarını temsil eden yığılmış çubukları gösteren vLLM iş yükü için Grafana'daki ilk daraltılmış alev grafiği görünümünün ekran görüntüsü.

Tavsiye

Grafana'nın alev grafiği panelinde, daraltmadan çağrı yığınının tamamını görmek için Tüm Grupları Genişlet seçeneğini kullanın. Belirli işlevleri veya anahtar sözcükleri bulmak için Arama kutusunu kullanın. Panelin yeniden daralmasını önlemek için, genişletilmiş alev grafiğini incelerken gösterge panosunun otomatik yenilemesini duraklatın (Grafana gösterge panosunun sağ üst köşesinde yenileme aralığını Kapalı olarak ayarlayın).

Tüm grupları genişlet'i seçtikten sonra, GPU bellek ayırmaları için tek tek işlev çerçeveleriyle birlikte tam çağrı yığınını gösteren vLLM iş yükü için Grafana'daki alev grafiğinin ekran görüntüsü.

Tavsiye

Belirli bir ayırma yoluna odaklanmak için Odak bloğunu kullanın.

Sembolleri okuma

Alev grafı etiketleri şu kurallara uyar:

Simge biçimi Anlamı
Foobar class Foo: method def bar()
Foo__init__ Foo sınıfının oluşturucusu
bar (tek başına) Bağımsız def bar() işlev
<interpreter trampoline> CPython ek yükü—yok say
<raw-address> Örneğin 0x7f151 Yerel C/CUDA kodu— kullanılabilir Python simgesi yok

Örnekler:

  • GPUModelRunner / _allocate_kv_cache_tensors—Bir sınıftaki bir yöntem. class GPUModelRunner: def _allocate_kv_cache_tensors(self) olarak okunur.
  • LlamaMLP / __init__—Oluşturucu. Nesne LlamaMLP(...) oluşturulurken çağrılır.
  • _compile_fx_inner—Herhangi bir sınıfın içinde olmayan tek başına bir modül düzeyi işlevi.

Kendini ve toplamı anlama

Bu anlayış, alev grafiklerini analiz ederken en önemli kavramdır.

  • Toplam: bir işlev tarafından tüketilen kaynak ve çağırdığı her şey. Bir işlevin toplam değeri yüksek olabilir, ancak kendisi hiçbir şey ayırmayabilir — bu yalnızca bir çağrı zincirinden ibarettir.
  • Kendisi—işlevin doğrudan tükettiği kaynak; alt öğeleri hariç. Yüksek bir self değeri, kaynağın gerçekten tüketildiği yerin bu işlev olduğunu gösterir.

Örnek: GPUModelRunner._allocate_kv_cache_tensors 55,1 GB kendi kendine sahiptir; KV önbellek tensorlarını oluşturmak için aslında torch.empty() öğesini çağıran işlevdir.

Gezinti ipuçları:

  • Yaprak düğümler (üstlerinde hiçbir şey bulunmayan çubuklar)—genişliklerinin tamamı kendilerinden kaynaklanır. Ayırma etkin noktalarını bulmak için buradan başlayın.
  • 0 self’e sahip geniş bir çubuk—yalnızca diğerlerini çağıran bir orkestratör işlev. Ayırmaları ararken atlayabilirsiniz.
  • Yüksek self’e sahip geniş çubuk — optimizasyon hedefiniz.

En büyük kaynak tüketicisini bulma

Etkin noktaları belirlemek için aşağıdaki adımları kullanın:

  • Grafiğin en üstündeki en geniş çubuklara bakın: Bunlar, belleğin gerçekten ayrıldığı yaprak işlevlerdir ve çubuk ne kadar genişse o kadar fazla tüketir.
  • Kendini ve toplamı kontrol edin: Alt self: 0 kısımdaki geniş çubuk yalnızca bir çağrı zinciridir. Yüksek kendi kendine ayırmaya sahip bir çubuk bulana kadar yukarı doğru izleyin.
  • Çağrı yığınını alttan üste okuma— Sıralama işlevin neden çağrıldığını bildirir. Örneğin:
      <raw-address> e.g 0x7f151               → native code entry
      <interpreter trampoline>                → CPython dispatch
      <module>                                → script top-level
      EngineCoreProc.run_engine_core          → vLLM engine startup
      EngineCore.__init__                     → engine initialization
      EngineCore._initialize_kv_caches        → KV cache setup
      Worker.initialize_from_config           → worker setup
      GPUModelRunner.initialize_kv_cache      → model runner
      GPUModelRunner._allocate_kv_cache_tensors → 💥 actual allocation
    
Goal Nelere dikkat etmeli
En çok ayrılan şey En geniş yaprak çubuğu (yığının en üstü)
En çok sorumlu olan şey En geniş çubuk (yığının en altındaki)
İyileştirme hedefleri Geniş benlikli çubuklar; kaynağın kullanıldığı yerdir
Yok sayılacak işlevler Kendisi 0 olan geniş çubuklar yalnızca diğerlerini çağırır

Sonraki Adımlar