Röviden: A hidegindítás évekig a serverless legfőbb ellenérve volt. Provisioned concurrency, SnapStart és karcsúbb futtatókörnyezetek után viszont érdemes újra feltenni a kérdést: kit és mikor zavar egyáltalán?
A hidegindítás sokáig a serverless architektúrák első számú mumusa volt: minden bemutatón előkerült, minden döntési megbeszélésen elhangzott, és nem ritkán ezen bukott el egy-egy Lambda-alapú javaslat. 2025-re a kép jóval árnyaltabb. A provisioned concurrency, a SnapStart, a könnyebb futtatókörnyezetek és a jobb tooling együtt oda vezettek, hogy a cold start ma inkább egy megoldható mérnöki részlet, mint sorsdöntő korlát.
Ez nem azt jelenti, hogy a hidegindítás megszűnt. Azt jelenti, hogy a kérdést pontosabban kell feltenni: nem azt, hogy "van-e cold start", hanem azt, hogy "ezt a konkrét forgalmi mintát és ezt a konkrét felhasználói elvárást zavarja-e, és ha igen, mennyibe kerül elkerülni".
Mi történik valójában hidegindításkor?
Amikor egy Lambda-hívás olyan futtatókörnyezetet igényel, ami épp nem áll készen, az AWS-nek elő kell készítenie egy új környezetet: le kell húzni a kódot vagy a konténerképet, el kell indítani a runtime-ot, majd le kell futtatni az inicializáló szakaszt. Ez utóbbi a te kódod: a handleren kívüli rész, ahol SDK-klienseket építesz, kapcsolatokat nyitsz, konfigurációt töltesz.
A tapasztalat az, hogy a hidegindítás érzékelt költségének nagy részét nem a platform adja, hanem a saját init-fázis. Egy nehéz dependency-fa, egy lusta helyett mohó módon betöltött SDK, egy szinkron hálózati hívás az inicializálásban — ezek jellemzően többet nyomnak a latba, mint maga a környezet-előkészítés.
Hol fáj, és hol nem
Egy aszinkron feldolgozó, ami SQS-ből olvas, jellemzően nem érzi meg: pár száz milliszekundum plusz egy üzenetnél nem számít. Egy éjszakai batch, egy webhook-fogadó, egy belső admin API ugyanígy tolerálja. Ahol viszont fáj: felhasználó által közvetlenül várt szinkron kérés, különösen ha a hívási lánc több Lambdán fut végig, és a hidegindítások összeadódnak.
A három fő eszköz és az áruk
A platform ma három érdemi mechanizmust kínál, és mindegyiknek más a jellege és a költségprofilja.
| Eszköz | Mit old meg | Ára jellege |
|---|---|---|
| Provisioned concurrency | Előre melegen tartott környezetek | Folyamatos, akkor is fizetsz, ha nincs forgalom |
| SnapStart | Inicializált állapot pillanatképéből indít | Elsősorban bizonyos runtime-oknál, kevés extra díj |
| Kód- és csomagoptimalizálás | Rövidebb init-fázis | Egyszeri mérnöki munka |
A provisioned concurrency a legkézenfekvőbb, de egyben a legdrágább is: lényegében megveszed a "mindig kész" állapotot, és a nem használt kapacitásért is fizetsz. Kiszámítható, csúcsos forgalomnál (például minden munkanap reggel 9-kor beeső terhelés) megéri, autoscalinggel a napszakhoz igazítva.
A SnapStart más filozófia: az inicializált környezetről készít pillanatképet, és abból éleszt új példányokat. Ahol elérhető és a kód pillanatkép-barát, ott a hidegindítás jelentős része eltűnik anélkül, hogy folyamatosan kapacitást vennél. Cserébe figyelni kell arra, hogy a snapshotba be ne fagyjon olyasmi, aminek példányonként egyedinek kell lennie — például egy előre legenerált véletlenszám-mag vagy egy adott időpontra sült érték.
Először a saját kódnál kezdd
Mielőtt bármelyik fizetős kapcsolót bekapcsolnád, érdemes a legolcsóbb helyen keresni: a saját inicializálásban. A gyakorlati sorrend jellemzően ez:
- Mérj: nézd meg az
Init Durationértéket a logokban, ne tippelj. - Csökkentsd a csomagméretet: csak azt húzd be, amit tényleg használsz.
- Töltsd lustán: amit nem minden híváshoz kell, azt ne az init-ben építsd.
- Kerüld a szinkron hálózatot az init-fázisban, ahol lehet.
- Csak ezután dönts provisioned concurrency vagy SnapStart mellett.
Egy tipikus init-blokk, ahol a kliens a handleren kívül, egyszer épül fel, de a nehéz munka a hívásig halasztódik:
const client = buildLightClient();
let heavy;
exports.handler = async (event) => {
heavy = heavy ?? (await buildHeavyThing());
return process(client, heavy, event);
};Mikor ne foglalkozz vele egyáltalán?
Van egy csapda: a hidegindítás optimalizálása könnyen öncélúvá válik. Ha a szolgáltatásod P99 válaszideje amúgy is bőven a felhasználói tűréshatár alatt van, akkor a cold start elleni küzdelem tiszta ráfordítás megtérülés nélkül. Az uralkodó forgalmi mintát nézd: ha a függvény gyakorlatilag folyamatosan meleg marad, mert van elég állandó forgalom, a hidegindítás statisztikai zaj lesz csupán.
Fordítva is igaz: egy ritkán, de kritikus pillanatban hívott függvénynél (például egy fizetési visszahívás) a ritkaság maga a probléma, mert szinte mindig hidegen fut. Itt a provisioned concurrency vagy a rendszeres "melegen tartó" hívás közötti választás nem teljesítmény-, hanem üzleti kockázati döntés.
A memória mint rejtett gyorsítógomb
Kevesen tudják, hogy a Lambda-nál a memória beállítása nem csak a memóriát szabályozza, hanem a hozzárendelt CPU-t is. Több memória arányosan több számítási kapacitást jelent, ami az inicializálást és a feldolgozást is gyorsítja. Így paradox módon egy nagyobb memóriájú, drágábbnak tűnő függvény összességében olcsóbb lehet, mert hamarabb végez, és rövidebb ideig fut.
Érdemes ezt méréssel belőni: futtasd a függvényt több memóriabeállítással, és nézd a futási időt és a teljes költséget együtt. Gyakran van egy édespont, ahol a magasabb memória rövidebb futásidőt és alacsonyabb végösszeget ad. A puszta „állítsuk a lehető legkevesebbre a spórolásért” reflex itt félrevezet.
A VPC-be helyezett függvény esete
Ha a függvényed egy VPC-ben fut (mert privát adatbázist vagy belső erőforrást ér el), az régen komoly hidegindítási büntetést jelentett a hálózati interfész felállítása miatt. Ez az idők során sokat javult, de a hálózati konfiguráció így is befolyásolja az indulást. Ha VPC-ben futtatsz, ellenőrizd, hogy a beállítás indokolt-e, és hogy a downstream elérés nem ad-e felesleges latenciát minden híváshoz.
Provisioned concurrency: mikor tényleg
A provisioned concurrency akkor a helyes eszköz, amikor a hidegindítási csúcs előre jelezhető: napi kampányindítás, ismert forgalmi minta, tervezett terhelés. Ilyenkor a melegen tartott kapacitás garantálja a kiszámítható latenciát. De ha a forgalmad kiszámíthatatlanul lökésszerű, a provisioned concurrency vagy alultervezett lesz (nem elég a csúcsra), vagy pazarló (feleslegesen fizeted a tétlen készenlétet). Az automatikus, ütemezett skálázása segíthet, ha a mintázat ismétlődő.
Mit jelent ez neked?
A hidegindítás 2025-ben ritkán ok arra, hogy elvesd a serverlesst — sokkal inkább egy méréssel eldönthető részletkérdés. Kezdd a saját init-fázis megmérésénél és karcsúsításánál, mert az a legolcsóbb nyereség, és csak utána nyúlj a provisioned concurrency vagy a SnapStart fizetős, illetve korlátozott megoldásaihoz. A lényeg, hogy a konkrét forgalmi minta és a felhasználói elvárás döntsön, ne a régi reflex.