Jobb újrapróbálkozások exponenciális hátralépés és Jitter segítségével

1. Áttekintés

Ebben az oktatóanyagban azt vizsgáljuk meg, hogyan javíthatjuk az ügyfelek újrapróbálkozásait két különböző stratégiával: exponenciális hátralépés és jitter.

2. Próbálja újra

Elosztott rendszerben a számos komponens közötti hálózati kommunikáció bármikor meghiúsulhat. Az ügyfélalkalmazások végrehajtásával kezelik ezeket a hibákatújrapróbálkozik.

Tegyük fel, hogy van egy kliens alkalmazásunk, amely távoli szolgáltatást hív meg - a PingPongService.

interfész PingPongService {String hívás (String ping) dobja a PingPongServiceException; }

Az ügyfélalkalmazásnak újra kell próbálkoznia, ha a PingPongService visszatér a PingPongServiceException. A következő szakaszokban megvizsgáljuk az ügyfélpróbálkozások megvalósításának módjait.

3. Resilience4j Próbálja újra

Például a Resilience4j könyvtárat fogjuk használni, különösen annak újrapróbálkozási modulját. Hozzá kell adnunk a resilience4j-retry modult a modulunkhoz pom.xml:

 io.github.resilience4j resilience4j-próbálkozzon újra 

Az újrapróbálkozások frissítéséhez ne felejtse el átnézni a Resilience4j útmutatónkat.

4. Exponenciális hátralépés

Az ügyfélalkalmazásoknak felelősségteljesen kell végrehajtaniuk az újrapróbálkozásokat. Amikor az ügyfelek várakozás nélkül próbálkoznak újra a sikertelen hívásokkal, túlterhelhetik a rendszert, és hozzájáruljon a már szorongatott helyzetű szolgáltatás további romlásához.

Az exponenciális hátralépés egy általános stratégia a sikertelen hálózati hívások újrapróbálkozásának kezelésére. Egyszerűen, az ügyfelek fokozatosan hosszabb intervallumokat várnak az egymást követő ismétlések között:

wait_interval = alap * szorzó ^ n 

hol,

  • bázis a kezdeti intervallum, vagyis várja meg az első újrapróbálkozást
  • n a bekövetkezett hibák száma
  • szorzó tetszőleges szorzó, amely bármilyen megfelelő értékkel helyettesíthető

Ezzel a megközelítéssel légzési teret biztosítunk a rendszernek, hogy felépüljön az időszakos kudarcokból vagy még súlyosabb problémákból.

A Resilience4j újrapróbálkozásában használhatjuk az exponenciális visszalépés algoritmust annak konfigurálásával IntervalFunction hogy elfogad egy kezdetiInterval és a szorzó.

A IntervalFunction az újrapróbálási mechanizmus alvási funkcióként használja:

IntervalFunction intervalFn = IntervalFunction.ofExponentialBackoff (INITIAL_INTERVAL, MULTIPLIER); RetryConfig retryConfig = RetryConfig.custom () .maxAtt kísérletek (MAX_RETRIES) .intervalFunction (intervalFn) .build (); Újrapróbálkozás = Retry.of ("pingpong", retryConfig); Funkció pingPongFn = Újrapróbálkozás .decorateFunction (újrapróbálkozás, ping -> service.call (ping)); pingPongFn.apply ("Hello"); 

Szimuláljunk egy valós forgatókönyvet, és tegyük fel, hogy több kliensünk hívja a PingPongService egyidejűleg:

ExecutorService végrehajtók = newFixedThreadPool (NUM_CONCURRENT_CLIENTS); Feladatok listája = nCopies (NUM_CONCURRENT_CLIENTS, () -> pingPongFn.apply ("Hello")); végrehajtók.invokeAll (feladatok); 

Nézzük meg a távoli meghívási naplókat NUM_CONCURRENT_CLIENTS egyenlő 4-vel:

[thread-1] 00: 37: 42.756 [thread-2] 00: 37: 42.756 [thread-3] 00: 37: 42.756 [thread-4] 00: 37: 42.756 [thread-2] 00: 37: 43.802 [menet-4] 00: 37: 43.802 [menet-1] 00: 37: 43.802 [menet-3] 00: 37: 43.802 [menet-2] 00: 37: 45.803 [ thread-1] 00: 37: 45.803 [menet-4] 00: 37: 45.803 [thread-3] 00: 37: 45.803 [thread-2] 00: 37: 49.808 [thread-3] 00 : 37: 49.808 [4. menet] 00: 37: 49.808 [1. menet] 00: 37: 49.808 

Itt világos mintát láthatunk - az ügyfelek exponenciálisan növekvő intervallumokra várnak, de mindegyikük pontosan ugyanabban az időben hívja a távoli szolgáltatást minden egyes újrapróbálkozáskor (ütközés).

A probléma csak egy részével foglalkoztunk - a távoli szolgáltatást már nem próbáljuk újrapróbálkozásokkal, de ahelyett, hogy a munkaterhelést idővel elosztanánk, a munkaidőszakokat több üresjárati idővel tarkítottuk. Ez a viselkedés hasonló a Mennydörgő csorda problémához.

5. A Jitter bemutatása

Korábbi megközelítésünk szerint az ügyfél várakozása fokozatosan hosszabb, de még mindig szinkronizált. A jitter hozzáadása lehetővé teszi az ügyfelek közötti szinkronizálás megszakítását, elkerülve ezzel az ütközéseket. Ebben a megközelítésben véletlenszerűséget adunk a várakozási időközökhöz.

wait_interval = (alap * 2 ^ n) +/- (random_interval) 

hol, random_interval hozzáadva (vagy kivonva) a kliensek közötti szinkronizálás megszakításához.

Nem fogunk foglalkozni a véletlenszerű intervallum kiszámításának mechanikájával, de a randomizálásnak el kell engednie a csúcsokat az ügyfélhívások sokkal egyenletesebb elosztásához.

A Resilience4j újrapróbálkozásánál használhatjuk az exponenciális hátrányt jitterrel egy exponenciális véletlenszerű visszalépés konfigurálásával IntervalFunction hogy elfogadja a randomizationFactor:

IntervalFunction intervalFn = IntervalFunction.ofExponentialRandomBackoff (INITIAL_INTERVAL, MULTIPLIER, RANDOMIZATION_FACTOR); 

Térjünk vissza a valós forgatókönyvhöz, és nézzük meg a távoli meghívási naplókat jitterrel:

[thread-2] 39: 21.297-nél [thread-4] 39: 21.297-nél [thread-3] 39: 21.297-nél [thread-1] 39: 21.297-nél [thread-2] 39: 21.918-on [thread-3] At 39: 21.868 [thread-4] at 39: 22.011 [thread-1] at 39: 22.184 [thread-1] at 39: 23.086 [thread-5] 39: 23.939 [thread-3] 39: 24.152 [ thread-4] 39: 24.977 [thread-3] 39: 26.861 [thread-1] 39: 28.617 [thread-4] 39: 28.942 [thread-2] 39: 31.039

Most sokkal jobban elterjedtünk. Nekünk van kiküszöböli mind az ütközéseket, mind a tétlen időt, és szinte állandó ügyfélhívásokkal jár, kizárva a kezdeti túlfeszültséget.

Megjegyzés: Túlértékeltük a szemléltetés intervallumát, és valós helyzetekben kisebb hézagokkal rendelkeznénk.

6. Következtetés

Ebben az oktatóanyagban megvizsgáltuk, hogyan javíthatjuk az ügyfélalkalmazások újrapróbálkozását a sikertelen hívásokon az exponenciális hátrányok kibővítésével a jitterrel.

Az oktatóanyagban használt minták forráskódja elérhető a GitHubon.


$config[zx-auto] not found$config[zx-overlay] not found