A lecke végére el tudod magyarázni a timeout és a deadline különbségét, meg tudod mondani, mikor biztonságos ismételni egy hívást, és hogyan teszi biztonságossá az idempotencia az ismétlést.
Miért kell?
A távoli hívás kimenete lehet ismeretlen (6.1). Hibatűrés szempontjából az a kérdés, mennyit érdemes várni, mikor kell ismételni, és hogyan őrizhető meg az üzleti állapot helyességét bizonytalan eredmény mellett. Az ismétlés a leggyakoribb védekezés és egyben a leggyakoribb hibaforrás.
Timeout és deadline
A timeout egy várakozás időtartama. A deadline időpont: ameddig a hívó a választ még megvárja. A gRPC dokumentációja szerint a timeout a hívás maximális időtartama, és úgy lesz belőle deadline, hogy hozzáadják a hívás indulási idejéhez. A gRPC alapértelmezetten nem állít be deadline-t, ezért a kliensben mindig explicit, reális határidőt kell megadni.
Láncolt hívásoknál a deadline-t tovább kell adni: ha a kliens időkerete véges, egy belső hívás nem kaphat újra a teljes keretet. A gRPC a hátralevő időt továbbítja, nem az abszolút időpontot, így nincs óraeltérési probléma. A lejárat után a szerver oldalán a hívás megszakadhat, de a már elindított munkát az alkalmazásnak kell leállítania; a már végrehajtott változást a megszakítás nem vonja vissza.
Mely hibát kell ismételni?
Átmeneti hálózati hiba vagy túlterhelés később javulhat. Hibás bemenet, hiányzó jogosultság és üzleti elutasítás ismétléssel nem javul. Az automatikus ismétlés csak a megállapodott hibaosztályra, korlátozott számban és időkereten belül történjen.
Az RFC 9110 szerint egy metódus idempotens, ha több azonos kérés szándékolt hatása ugyanaz, mint egyé; a szabványban a PUT, a DELETE és a biztonságos metódusok ilyenek. Az idempotens kérést automatikusan meg lehet ismételni, ha a kapcsolati hiba a válasz elolvasása előtt történik. Egy nem idempotens metódusú kérést a kliens nem ismételhet automatikusan, hacsak nem tudja, hogy a kérés szemantikája mégis idempotens, vagy nem tudja kideríteni, hogy az eredeti kérés nem hajtódott végre.
Idempotenciakulcs
Módosító kérésnél a kliens ugyanahhoz a logikai művelethez azonos idempotenciakulcsot küldhet. A szerver tartósan tárolja a kulcsot, a kérés jelentését és az eredményt; ismétléskor nem hajtja végre újra, hanem a korábbi eredményt adja. Az AWS leírása is hangsúlyozza: mellékhatással járó API-t csak akkor biztonságos ismételni, ha idempotens.
flowchart TD
A["Módosító kérés + kulcs"] --> B{"A kulcs már ismert?"}
B -->|"Nem"| C["Atomi felvétel és végrehajtás"]
C --> D["Eredmény tartós rögzítése"]
B -->|"Igen"| F{"Ugyanaz a kérés?"}
F -->|"Nem"| G["Kulcsütközés: elutasítás"]
F -->|"Igen"| H["Korábbi eredmény visszaadása"]
A kulcs hatóköre számít (felhasználóhoz és művelettípushoz köthető). Azonos kulccsal eltérő tartalmat el kell utasítani. A párhuzamos első kéréseket atomi egyediségi kulcs védi, nem egy előzetes olvasás. Az „éppen fut” állapotot is meg kell tervezni, és a kulcs lejárata utáni ismétlésre már nincs védelem, ezért a megőrzési idő a szerződés része. Az IETF Idempotency-Key fejléc-szabványa jelenleg vázlat (draft), nem kiadott szabvány.
Ismétlés késleltetéssel: backoff és jitter
Azonnali, korlátlan ismétlés ront a helyzeten. Exponenciális backoff esetén az ismétlések közti várakozás minden próbálkozással nő, jitter véletlenszerűen szórja a várakozást, hogy a kliensek ne egyszerre próbálkozzanak újra. Az AWS leírása szerint érdemes korlátot szabni a várakozásnak és a próbálkozások számának. Egy lehetséges szemléltető szabály: véletlen várakozás 0 és min(maximum, alap × 2^próbálkozás) között; a paramétereket nem általános receptből, hanem a függőség és az igény alapján kell választani.
Retry storm és a felelős réteg
Ha a kliens, az átjáró és a szolgáltatás mind ismétel, a terhelés megsokszorozódik. Az AWS példája szerint rétegenként három próbálkozás öt rétegen át a mélyen levő adatbázis terhelését akár 3⁵ = 243-szorosára növelheti. Ezért az AWS szerint alacsony költségű műveleteknél egyetlen ponton érdemes ismételni a hívási láncban, és csak akkor, ha a függőség egészségesnek látszik. Ha a kiszolgáló túlterhelés miatt 503-at ad, a Retry-After fejléc javasolhat várakozási időt.
Gyakori tévhitek
Állítás
Pontosítás
„A retry mindig növeli a megbízhatóságot.”
Túlterhelésnél a terhelést növeli; rétegenként szorzódik.
„A timeout után a kérés nem történt meg.”
Lehet, hogy végrehajtódott.
„Az idempotens művelet ugyanazt a választ adja.”
A hatás ugyanaz, a válasz eltérhet (például első 204, később 404 törlésnél).
„A kérésazonosító egyben idempotenciakulcs.”
Csak ha a szerver ilyen szabályt implementál.
Röviden
A deadline időpont, a timeout időtartam; láncban a hátralevő időt kell továbbadni.
Automatikusan csak átmeneti hibát és idempotens műveletet szabad ismételni.
Az idempotenciakulcs tartós, atomi, hatókörhöz kötött, lejáratú.
Backoff és jitter szórja az ismétléseket; egyetlen réteg felelős az ismétlésért.
Ellenőrző kérdések
Miért nem ismételhető automatikusan egy nem idempotens kérés?
Mi történjen azonos kulccsal eltérő bemenetnél?
Hogyan szorzódik a terhelés több réteg független ismétlésénél?
Időkeret, ismétlés és idempotencia
Célok
A lecke végére el tudod magyarázni a timeout és a deadline különbségét, meg tudod mondani, mikor biztonságos ismételni egy hívást, és hogyan teszi biztonságossá az idempotencia az ismétlést.
Miért kell?
A távoli hívás kimenete lehet ismeretlen (6.1). Hibatűrés szempontjából az a kérdés, mennyit érdemes várni, mikor kell ismételni, és hogyan őrizhető meg az üzleti állapot helyességét bizonytalan eredmény mellett. Az ismétlés a leggyakoribb védekezés és egyben a leggyakoribb hibaforrás.
Timeout és deadline
A timeout egy várakozás időtartama. A deadline időpont: ameddig a hívó a választ még megvárja. A gRPC dokumentációja szerint a timeout a hívás maximális időtartama, és úgy lesz belőle deadline, hogy hozzáadják a hívás indulási idejéhez. A gRPC alapértelmezetten nem állít be deadline-t, ezért a kliensben mindig explicit, reális határidőt kell megadni.
Láncolt hívásoknál a deadline-t tovább kell adni: ha a kliens időkerete véges, egy belső hívás nem kaphat újra a teljes keretet. A gRPC a hátralevő időt továbbítja, nem az abszolút időpontot, így nincs óraeltérési probléma. A lejárat után a szerver oldalán a hívás megszakadhat, de a már elindított munkát az alkalmazásnak kell leállítania; a már végrehajtott változást a megszakítás nem vonja vissza.
Mely hibát kell ismételni?
Átmeneti hálózati hiba vagy túlterhelés később javulhat. Hibás bemenet, hiányzó jogosultság és üzleti elutasítás ismétléssel nem javul. Az automatikus ismétlés csak a megállapodott hibaosztályra, korlátozott számban és időkereten belül történjen.
Az RFC 9110 szerint egy metódus idempotens, ha több azonos kérés szándékolt hatása ugyanaz, mint egyé; a szabványban a PUT, a DELETE és a biztonságos metódusok ilyenek. Az idempotens kérést automatikusan meg lehet ismételni, ha a kapcsolati hiba a válasz elolvasása előtt történik. Egy nem idempotens metódusú kérést a kliens nem ismételhet automatikusan, hacsak nem tudja, hogy a kérés szemantikája mégis idempotens, vagy nem tudja kideríteni, hogy az eredeti kérés nem hajtódott végre.
Idempotenciakulcs
Módosító kérésnél a kliens ugyanahhoz a logikai művelethez azonos idempotenciakulcsot küldhet. A szerver tartósan tárolja a kulcsot, a kérés jelentését és az eredményt; ismétléskor nem hajtja végre újra, hanem a korábbi eredményt adja. Az AWS leírása is hangsúlyozza: mellékhatással járó API-t csak akkor biztonságos ismételni, ha idempotens.
flowchart TD A["Módosító kérés + kulcs"] --> B{"A kulcs már ismert?"} B -->|"Nem"| C["Atomi felvétel és végrehajtás"] C --> D["Eredmény tartós rögzítése"] B -->|"Igen"| F{"Ugyanaz a kérés?"} F -->|"Nem"| G["Kulcsütközés: elutasítás"] F -->|"Igen"| H["Korábbi eredmény visszaadása"]A kulcs hatóköre számít (felhasználóhoz és művelettípushoz köthető). Azonos kulccsal eltérő tartalmat el kell utasítani. A párhuzamos első kéréseket atomi egyediségi kulcs védi, nem egy előzetes olvasás. Az „éppen fut” állapotot is meg kell tervezni, és a kulcs lejárata utáni ismétlésre már nincs védelem, ezért a megőrzési idő a szerződés része. Az IETF
Idempotency-Keyfejléc-szabványa jelenleg vázlat (draft), nem kiadott szabvány.Ismétlés késleltetéssel: backoff és jitter
Azonnali, korlátlan ismétlés ront a helyzeten. Exponenciális backoff esetén az ismétlések közti várakozás minden próbálkozással nő, jitter véletlenszerűen szórja a várakozást, hogy a kliensek ne egyszerre próbálkozzanak újra. Az AWS leírása szerint érdemes korlátot szabni a várakozásnak és a próbálkozások számának. Egy lehetséges szemléltető szabály: véletlen várakozás 0 és min(maximum, alap × 2^próbálkozás) között; a paramétereket nem általános receptből, hanem a függőség és az igény alapján kell választani.
Retry storm és a felelős réteg
Ha a kliens, az átjáró és a szolgáltatás mind ismétel, a terhelés megsokszorozódik. Az AWS példája szerint rétegenként három próbálkozás öt rétegen át a mélyen levő adatbázis terhelését akár 3⁵ = 243-szorosára növelheti. Ezért az AWS szerint alacsony költségű műveleteknél egyetlen ponton érdemes ismételni a hívási láncban, és csak akkor, ha a függőség egészségesnek látszik. Ha a kiszolgáló túlterhelés miatt
503-at ad, aRetry-Afterfejléc javasolhat várakozási időt.Gyakori tévhitek
204, később404törlésnél).Röviden
Ellenőrző kérdések
Források