Az NVIDIA Dynamo új, előnézeti (preview) funkciója, a „shadow engine recovery” (árnyékmotor-helyreállítás) azt célozza, hogy a nagy nyelvi modelleket (LLM) kiszolgáló motorok hibája után ne kelljen perceket várni a szolgáltatás visszaállására. A megközelítés lényege egy teljesen inicializált, de inaktív árnyékmotor fenntartása ugyanazon GPU-kon, valamint a GPU Memory Service (GMS) révén a súlyok (weights) megosztása anélkül, hogy új HBM-másolat jönne létre. Ennek hatására a sérült folyamat helyett a shadow engine másodpercek alatt átveheti a forgalmat.
Miért lassú a hagyományos helyreállítás?
A rutinszerű helyreállítás hideg újraindítást (cold restart) jelent: a súlyok betöltése a háttértárról a HBM-be, kernelfordítások, és NVIDIA CUDA-graphok újrafogása. Nagy modellek esetén ez percekig is eltarthat, miközben a még élő munkásoknak át kell venniük az összes forgalmat. Két alapvető probléma áll a hátráltatás mögött:
- A súlyok (weights) életideje az engine folyamathoz kötődik: amikor a folyamat kilép, a CUDA-kontextet és a HBM-ben lévő erőforrásokat a driver felszabadítja, így az új folyamatnak újra be kell töltenie a súlyokat.
- Egyes inicializációs állapotok átruházhatatlanok: NCCL és torch.distributed kommunikátorok, valamint a CUDA graphok a futó folyamat virtuális címtartományához kötődnek, ezért ezeket minden újraindításnál újra kell létrehozni.
Hogyan oldja meg a shadow engine recovery a problémákat?
A megoldás két fő optimalizáción nyugszik: a súlyok életidejének leválasztása az engine folyamatról, valamint az átruházhatatlan inicializáció előre elvégzése egy tartalékmotoron.
GPU Memory Service (GMS)
A GPU Memory Service egy per-GPU sidecar folyamat, amely fizikailag fenntart speciális memóriaallokációkat (például a súlyoké) az engine folyamatoktól függetlenül. A GMS kezelésében lévő fizikai oldalakhoz foglalásokat (handles) ad ki; az engine-ek ezeket importálják és saját CUDA-kontextjeikben virtuális címekre térképezik. A CUDA Virtual Memory Management API lehetővé teszi, hogy a fizikai GPU memória és a virtuális címek élettartama külön legyen, így a fizikai allokációk túlélnek egy engine kilépését, amíg bármelyik folyamat tartja a leképezést. Fontos: a GMS maga nem ül közbe az engine és a memória olvasása közé — két engine ugyanazt a fizikai bájtot olvassa a saját virtuális címein keresztül, ezért az olvasás költsége megegyezik az engine-által allokált súlyok olvasásával.
Shadow engine: előmelegített tartalék
A shadow engine egy teljesen inicializált, de inaktív folyamat, amely ugyanazon GPU-kon lakik, mint az aktív engine. A GMS-nek köszönhetően a shadow nem igényel külön HBM-másolatot a súlyokból, így a memóriahasználat megengedi két engine egyidejű jelenlétét. A shadow ugyanazt a kezdési útvonalat futtatja végig: csatlakozás GMS-hez, súlyok importja, kommunikátorok (NCCL, NIXL) létrehozása, CUDA graphok rögzítése, szükséges melegítések. A befejezés után a shadow „parkol”: felszabadítja a materializálható memóriarészeket (például a KV cache-t), és várakozik a záron. A parkolt shadow előre kiszámolt elemei:
- CUDA-kontext, rögzített graphok, kommunikátorok (átörökíthetetlenek, ezért előre kell létrehozni őket),
- a GMS-sel importált súlyhozzárendelések (handles).
Halasztott elem: a KV cache fizikai materializálása; a shadow fenntartja a címtartományt, de a cache-t csak aktiváláskor tölti fel.
A munkás (worker) felépítése és működése
Egy worker-podon belül két engine-konténer, egy GMS sidecar és egy megosztott zár (lock) működik együtt. Állapotban az egyik engine birtokolja a zárat és aktív: materializált KV cache-sel, regisztrálva a frontend routernél. A másik engine teljesen inicializált, csatlakozva a GMS-hez, de blokkolva a záron és KV cache nélkül. A zár POSIX flockon alapul egy megosztott fájlon — így ha az aktív folyamat kilép (shutdown, SIGKILL, vagy kernel által reap), a kernel lezárja a fájlleírókat és a shadow át tudja venni a zárolást, majd ébred és szolgálni kezd.
Helyreállítási menetrend
A worker négy fázison megy keresztül a steady state visszaállításáig:
- T0 Steady: Engine A aktív és regisztrált, Engine B parkolt.
- T1 Failure: Engine A folyamata kilép; a worker rövid ideig nem elérhető, amíg a shadow be nem regisztrál.
- T2 Cutover: Engine B megszerzi a zárolást, felébred, remap-peli a súlyokat a GMS-ről, materializálja a KV cache-t, és újra regisztrál a routernél. Engine A konténerét az orchestrator újraindítja.
- T3 Restarted: Engine A befejezi az inicializációt és parkol; a szerepek felcserélődnek, a rendszer visszatér steady state-be. A kritikus útban csak a zárolás megszerzése, a súlyok remappelése és a KV cache materializálása marad — emiatt a cutover másodpercek alatt megtörténhet.
Memória- és szinkronizációs megfontolások
A parkolt shadow tartós költsége tartalmazza a CUDA-kontextet, rögzített graphokat és kommunikátorokhoz szükséges pufferállományokat; ezek a költségek meg kell, hogy férjenek a HBM-ben az aktív engine mellett. A súlyok egyszer allokáltak a GMS-ben, és minden engine olvasásra csak leképezi őket, a KV cache pedig csak az aktív engine-hez materializálódik és hal ki az engine halálával.
Benchmark: GLM-5.2 két-worker összehasonlítás
A csapat összehasonlította a shadow engine recovery-t egy hideg újraindítással egy két-worker GLM-5.2 telepítésen. A beállítások: GLM-5.2 kvantálva NVFP4-re, NVIDIA B200 node-ok, egy worker per node, TP=8, 200K maximális kontextus, FP8 KV cache. A terhelés szintetikus: per kérés 32,000 input token és 1,000 output token, 0.7 kérés/s sebességgel. Egy frontend round-robin módon osztotta a kéréseket két worker között. A hibinjectálás: amikor a rendszer steady state-ben volt, egy SIGKILL-el megöltek egy worker-t, majd 600 másodpercig megfigyelték az állapotot. Egy worker kiesése esetén az élő worker minden forgalmat kiszolgált, míg a partner vissza nem tért.
Mérési eredmények (ablak a hiba utáni időszakra):
- Idő, amíg újra megjelenik a második worker:
- Cold restart (alapvonal): 283 s
- Shadow engine recovery: 7.3 s (1.7 s hibadetektálás + 5.6 s promotálás)
- TTFT p50, a hibát követően:
- Cold restart: 23,815 ms
- Shadow: 1,311 ms
- Decode rate p50, a hibát követően:
- Cold restart: 12 tok/s/felhasználó
- Shadow: 46 tok/s/felhasználó
- Kérések, amelyek 5 s fölöttig vártak első tokenre a megfigyelt ablakban:
- Cold restart: 201 of 399
- Shadow: 1 of 398 Ezek alapján a shadow megközelítés közel 39× gyorsabb visszaállást hozott a referencia hideg újraindításhoz képest, és jelentősen csökkentette a szolgáltatásminőség romlását.
Jelenlegi korlátok és következő lépések
A funkció jelenleg preview állapotban van, és több korlátozással:
- Csak processz-szintű, helyrehozható szoftverhibákra fókuszál; hardver-, node- vagy többnode-os meghibásodások továbbra is hagyományos ütemezést igényelnek.
- Kubernetes DRA (Dynamic Resource Allocation) szükséges: a klaszternek Kubernetes 1.34+-nak kell lennie DRA engedélyezéssel és az NVIDIA GPU DRA drivert telepítve.
- Jelenleg a preview nem támogatja a KV cache megosztását a GMS-en keresztül; ezen a területen aktívan dolgoznak, hogy a promovált shadow a kieső engine cache-ét tudja leképezni ahelyett, hogy újraépítené azt forgalom alatt.
- vLLM a primer támogatott backend.
A csapat célja a megoldás stabilizálása és további munkaterhelések támogatása a következő hónapokban. A Dynamo Snapshot funkció összekomponálható a recovery-vel, hogy csökkentse a contentiont az árnyék inicializációja alatt.
Kipróbálás és hozzájárulás
A Shadow Engine Recovery kipróbálásához a Kubernetes quickstarttal indítsanak egy telepítést, majd kövessék a Shadow Engine Recovery deployment workflow-t; a vLLM failover példa teljes manifestumként használható. A részletek, kérdések és hibajelentések az ai-dynamo/dynamo repository-ban találhatók.
Miért számít ez?
A shadow engine recovery egy gyakorlati optimalizáció a latency- és SLA-követelményű LLM-inferencia rendszerben: a súlyok külön élettartama és az előre inicializált parkolt tartalékok révén a szolgáltatás kiesése másodpercekre csökkenthető a percek helyett. Ez különösen fontos nagy modellek és szigorú válaszidő-szintek esetén, amikor egy-egy worker kiesése jelentős felhasználói hatással járhat.



