Özet:
- Sorun durumu: vLLM’in Prefill/Decode ayrıştırılmış (disaggregated) servis ortamında dakikada 400 MB sistem belleği (RSS) sızıntısı oluşuyordu, ancak sıradan Python profilleyicileri bunu tespit edemiyordu.
- Neden analizi: Heaptrack ve pmap ile sızıntının heap’te değil, anonim bellek eşlemelerinde (
mmap) olduğunu doğruladılar; ardından BPFtrace ve otomatikleştirilmiş GDB betikleriyle nedeni izlediler. - Suçlunun tespiti: Yüksek performanslı iletişim kütüphanesi UCX, optimizasyon için
mmap/munmapçağrılarını yakalıyordu; serbest bırakılan belleği hemen geri vermek yerine sınırsız biçimde bir kuyrukta biriktirmesi sorunun kaynağıydı. - Çözüm:
UCX_MEM_MMAP_HOOK_MODE=noneortam değişkeni ayarlanarak UCX’in bellek hook özelliği devre dışı bırakıldı ve sorun çözüldü.
Ayrıntılı özet:
1. Gizemli bellek sızıntısı
Mistral AI ekibi, vLLM kullanılan Prefill/Decode ayrıştırılmış servis (NIXL tabanlı) ortamında sistem belleğinin dakikada 400 MB doğrusal olarak arttığını fark etti.
- Belirti: Python heap belleği kararlıydı, ancak işletim sistemi düzeyindeki RSS (Resident Set Size) sürekli artıyor ve sonunda OOM’a (Out of Memory) yol açıyordu.
- İlk denemelerin başarısızlığı:
Memray,Guppy 3gibi Python araçları her şeyin normal olduğunu gösterdi; standartGDBsüreci çökertti,Valgrindise kullanılmayacak kadar yavaştı.
2. Kernel seviyesinde derin analiz
Sorunun nedeninin uygulama seviyesi (Python/C++) değil, daha alt bir katman olduğunu sezerek sistem araçlarını kullandılar.
- Heaptrack: Heap tahsislerinin (
malloc/free) kararlı kaldığını, buna karşın RSS’nin arttığını görsel olarak doğruladı. Bu da sızıntınınglibcheap yönetiminin dışında, anonim bellek eşlemelerinde (anonymous memory mappings) gerçekleştiğine işaret ediyordu. - pmap:
/proc/<pid>/mapsizlenerek belirli bir anonim eşleme alanının sürekli büyüdüğü ve adresinin değiştiği görüldü. Bu,mremapveyamunmapsonrasımmapdöngüsünün tekrarlandığı anlamına geliyordu. - BPFtrace:
LD_PRELOADile de yakalanamayan (glibc’yi atlayan) sistem çağrılarını izlemek için BPFtrace kullanıldı. Sonuçtammapçağrılarının doğrudansyscallüzerinden gerçekleştiği doğrulandı.
3. Suçlunun yakalanması: otomatik GDB betikleme
BPFtrace ile sorunlu sistem çağrısının adresi belirlendikten sonra, GDB kullanılarak yalnızca ilgili adreste (SYS_mmap) duracak şekilde bir betik yazıldı.
Kullanılan GDB betiği örneği:
# mmap sistem çağrısı (numara 9) için koşullu breakpoint ayarla
break syscall if $rdi == 9
commands
silent
# Sistem çağrısı dönüş noktasına geçici breakpoint ayarla
tbreak *0x00007ffff7d9525d
commands
silent
# Stack trace ve dönen adresi yazdır
bt
printf "Syscall returned: rax = 0x%012lx\n", $rax
continue
end
continue
end
Bu stack trace sayesinde UCX (Unified Communication X) kütüphanesinin Python’un mmap/munmap çağrılarını arada yakaladığına (intercept) dair kritik ipucu bulundu.
4. Neden: UCX’in aşırı optimizasyonu
UCX, InfiniBand aktarım performansını artırmak için bellek tahsisi/serbest bırakmayı hook’lar.
- Mekanizma:
munmapçağrıldığında belleği hemen işletim sistemine geri vermek yerine, daha sonra yeniden kullanmak veya temizlemek için bir "geçersiz kılma kuyruğuna (invalidation queue)" koyar. - Hata: Varsayılan ayar (
UCX_RCACHE_MAX_UNRELEASED=inf) nedeniyle bu kuyruk sonsuza kadar büyüyebiliyordu ve vLLM’in belirli kullanım desenlerinde temizleme mantığı (ucp_worker_progress) düzgün çalışmadığından bellek sadece birikmeye devam ediyordu.
5. Çözüm yolu
vLLM durumunda yalnızca devasa bir KVCache bellek bölgesinin kaydedilmesi gerektiği için, UCX’in karmaşık bellek hook mekanizmasına aslında ihtiyaç yoktu.
- Anlık çözüm:
UCX_MEM_MMAP_HOOK_MODE=noneortam değişkeni ayarlanarak UCX’in bellek hook işlevi tamamen kapatıldı ve sızıntı önlendi. - Alternatif:
UCX_RCACHE_MAX_UNRELEASED=1024gibi bir ayarla kuyruk boyutu sınırlandırılarak temizliğin zorla tetiklenmesi de mümkün. - Atılan adım: İlgili düzeltme vLLM topluluğu için birleştirildi; gelecekteki NIXL sürümlerinde de varsayılan davranışın iyileştirilmesi planlanıyor.
2 yorum
İnsan nasıl bir hayat yaşamalı da… bu düzeye
erişebilsin
Bu insanların birikiminin ne düzeyde olduğunu gerçekten kestiremiyorum.