Przejdź do treści
INDEKS ANALIZ BREACHROAD / NOTA TECHNICZNA

400 MB na minutę: jak Mistral znalazł wyciek pamięci poza stertą vLLM

Mistral opisał debugowanie wycieku RSS w disaggregated serving vLLM, NIXL i UCX. Heaptrack nie widział problemu; pomogły pmap, eBPF i GDB.

MATERIAŁ PUBLICZNY
AUTOR
/ CEO Breachroad · OSCP · PNPT
PUBLIKACJA
21 stycznia 2026
CZAS CZYTANIA
14 min czytania
TEMAT
Bezpieczeństwo AI
400 MB na minutę: jak Mistral znalazł wyciek pamięci poza stertą vLLM

21 stycznia 2026 roku Mistral opublikował analizę wycieku pamięci w przedprodukcyjnym środowisku vLLM. Przy Mistral Medium 3.1, kompilacji grafu i rozdzieleniu faz prefill/decode pamięć systemowa procesu decode rosła o około 400 MB na minutę pod ruchem zbliżonym do produkcyjnego. Po kilku godzinach kończyło się to OOM.

To nie był uniwersalny błąd każdej instalacji vLLM. Pojawiał się w konkretnym disaggregated serving z NIXL, który korzystał z UCX do transferu KV cache przez szybkie połączenia. Właśnie precyzyjne zawężenie konfiguracji jest największą wartością tej historii.

Dlaczego profiler „nie widział” wycieku

Memray i Guppy nie pokazały problemu. Heaptrack widział prawidłową równowagę malloc/free, mimo że RSS stale rósł. Powód: pamięć nie ginęła na klasycznej stercie. pmap pokazał rosnące anonimowe mapowania, a BPFtrace ujawnił bezpośrednie wywołania mmap przez surowy syscall, omijające hooki glibc.

Zautomatyzowany GDB zatrzymywał tylko konkretne wywołanie mmap i zebrał pełny stos. Ślad prowadził przez UCX. Biblioteka przechwytywała mapowania pamięci na potrzeby RDMA i po munmap umieszczała regiony w kolejce unieważnienia, zamiast od razu je zwolnić. Pula tej kolejki rosła, a domyślna wartość UCX_RCACHE_MAX_UNRELEASED=inf nie wymuszała porządkowania w obserwowanym edge case.

Naprawa i obejście

W konfiguracji vLLM transfer dotyczył jednego dużego, ciągłego obszaru KV cache, więc wyłączenie hooków mmap rozwiązało wyciek bez mierzalnej straty wydajności według Mistrala. Alternatywnie ustawienie UCX_RCACHE_MAX_UNRELEASED=1024 ograniczało kolejkę i wymuszało cleanup. Zespół vLLM połączył poprawkę, a zespoły UCX/NIXL planowały zmianę zachowania w przyszłym wydaniu.

Nie należy kopiować zmiennej środowiskowej bez testu. Limit wpływa na zachowanie cache rejestracji pamięci i w innym wzorcu RDMA może zmienić wydajność. Poprawna kolejność to reprodukcja na canary, obserwacja RSS i przepustowości, aktualizacja zależności, test soak oraz dopiero rollout.

Runbook obserwowalności inference

Monitoruj osobno VRAM, RSS, anonymous mappings, open file descriptors i pamięć cgroup. Alarm oparty tylko na stercie Pythona pominie biblioteki C/C++, sterowniki i RDMA. Dla soak testu użyj realnego rozkładu długości promptu, równoległości i transferów KV cache.

Zapisuj dokładne wersje vLLM, NIXL, UCX, PyTorch, sterownika i firmware. Bez tego incydent staje się „czasem rośnie pamięć” i jest niemożliwy do odtworzenia. Szerszy model obserwowalności opisujemy w monitoringu agentów AI z OpenTelemetry.

Ta historia pokazuje, że „wyciek pamięci” może być w kolejce invalidation biblioteki RDMA, a nie w Pythonie. Przegląd produkcyjnego AI powinien obejmować testy długotrwałe i pełny stos natywnych zależności.

Jak rozróżnić leak, cache i fragmentację

Rosnący RSS nie zawsze oznacza, że pamięć jest nieosiągalna. Cache może celowo utrzymywać regiony, allocator może ich nie zwracać kernelowi, a fragmentacja pozostawia wolne kawałki, których nie da się połączyć. Wykonaj eksperyment: zatrzymaj ruch, wymuś okres bezczynności i obserwuj, czy pamięć osiąga plateau lub spada po kontrolowanym cleanup.

Porównaj VmRSS, RssAnon, RssFile, mapowania z /proc/<pid>/smaps_rollup i pamięć cgroup. W GPU osobno mierz pamięć zaalokowaną oraz zarezerwowaną przez framework. Dopiero trend pod stałym workloadem i brak odzyskania po zakończeniu żądań uzasadniają hipotezę wycieku.

Soak test, który ma wartość

Krótki benchmark throughputu może nie ujawnić wzrostu 400 MB/min, jeśli proces kończy się po kilku minutach. Soak powinien trwać dłużej niż oczekiwany czas do OOM przy realnym limicie cgroup i mieć fazy: narastanie, steady state, spadek ruchu oraz pełny idle. Zapisuj slope pamięci, nie tylko maksimum.

Wprowadzaj jedną zmianę naraz: model, graph compilation, P/D disaggregation, backend KV transfer i wersję UCX. Macierz eksperymentów pozwoli wskazać warunek konieczny. Canary powinien reprezentować ten sam NUMA, RDMA i kernel co produkcja.

Wpływ operacyjny OOM

OOMKill może usunąć worker w połowie odpowiedzi, a retry zwiększyć ruch na pozostałych. Ustaw readiness tak, by proces z krytycznym trendem pamięci przestał przyjmować nowe zadania przed awarią. Router powinien odróżnić retry bezpieczny od zadania z wykonanym narzędziem.

Dlaczego zwykły APM nie wystarczył? Agenty APM zwykle widzą runtime aplikacji i klasyczne alokacje, nie surowe syscalls oraz wewnętrzne pule UCX. Potrzebna jest obserwowalność systemowa.

Lekcja dla postmortem

Postmortem powinien oddzielić objaw, warunek, mechanizm i poprawkę. Objawem był liniowy RSS, warunkiem konkretny P/D z NIXL, mechanizmem kolejka UCX, a poprawką zmiana hooków lub limitu. Takie rozdzielenie zapobiega błędnemu wnioskowi „vLLM zawsze wycieka”. Do raportu dołącz wykres slope, macierz eksperymentów i wersję każdej zależności.


Źródło pierwotne: Mistral AI — Heaps do lie: debugging a memory leak in vLLM.

UDOSTĘPNIJ / KOPIUJ