Útmutató a rugalmassághoz4j

1. Áttekintés

Ebben az oktatóanyagban a Resilience4j könyvtárról fogunk beszélni.

A könyvtár segít a rugalmas rendszerek megvalósításában a távoli kommunikáció hibatűrésének kezelésével.

A könyvtárat a Hystrix ihlette, de sokkal kényelmesebb API-t és számos egyéb funkciót kínál, mint a Rate Limiter (túl gyakori kérések blokkolása), Bulkhead (a túl sok egyidejű kérés elkerülése) stb.

2. Maven Setup

A kezdéshez hozzá kell adnunk a célmodulokat a sajátunkhoz pom.xml (pl. itt hozzáadjuk a megszakítót):

 io.github.resilience4j resilience4j-megszakító 0.12.1 

Itt használjuk a biztosíték modul. Minden modul és azok legújabb verziói megtalálhatók a Maven Central oldalon.

A következő szakaszokban áttekintjük a könyvtár leggyakrabban használt moduljait.

3. Megszakító

Vegye figyelembe, hogy ehhez a modulhoz szükségünk van a ellenálló képesség4j-megszakító fent látható függőség.

A megszakító minta segít megelőzni a meghibásodások lépcsőfokát, ha egy távoli szolgáltatás nem működik.

Számos sikertelen próbálkozás után úgy gondolhatjuk, hogy a szolgáltatás nem érhető el / túlterhelt, és lelkesen elutasíthatunk minden későbbi kérést hozzá. Ily módon megtakaríthatjuk a rendszer erőforrásait a valószínűleg sikertelen hívásokra.

Lássuk, hogyan érhetjük el ezt a Resilience4j segítségével.

Először meg kell határoznunk a használni kívánt beállításokat. A legegyszerűbb mód az alapértelmezett beállítások használata:

CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults ();

Lehetőség van egyéni paraméterek használatára is:

CircuitBreakerConfig config = CircuitBreakerConfig.custom () .failureRateThreshold (20) .ringBufferSizeInClosedState (5) .build ();

Itt az arány küszöbértéket 20% -ra és minimum 5 hívási kísérletre állítottuk be.

Ezután létrehozunk egy Biztosíték objektumot, és hívja rajta keresztül a távoli szolgáltatást:

interfész RemoteService {int folyamat (int i); } CircuitBreakerRegistry register = CircuitBreakerRegistry.of (config); CircuitBreaker circuitBreaker = register.circuitBreaker ("én"); Funkció díszítve = CircuitBreaker .decorateFunction (áramkörmegszakító, szolgáltatás :: folyamat);

Végül nézzük meg, hogyan működik ez a JUnit teszt segítségével.

Tízszer próbáljuk felhívni a szolgáltatást. Ellenőriznünk kell, hogy a hívást legalább ötször megkísérelték-e, majd leállították, amint a hívások 20% -a kudarcot vallott:

mikor (service.process (bármely (Integer.class))). thenThrow (új RuntimeException ()); mert (int i = 0; i <10; i ++) {próbálkozzon {díszített.alkalmazzon (i); } catch (Exception ignore) {}} verify (service, times (5)). process (any (Integer.class));

3.1. Megszakítók Állapotok és beállítások

A Biztosíték a három állapot egyikében lehet:

  • ZÁRVA - minden rendben van, nincs rövidzárlat
  • NYISD KI - a távoli szerver nem működik, az összes kérés rövidzárlatos
  • HALF_OPEN - konfigurált idő eltelt az OPEN állapotba lépés óta és Biztosíték lehetővé teszi a kérelmek számára annak ellenőrzését, hogy a távoli szolgáltatás online állapotban van-e

A következő beállításokat konfigurálhatjuk:

  • a meghibásodási küszöbérték, amely felett a Biztosíték megnyitja és megkezdi a rövidzárlatot
  • a várakozási idő, amely meghatározza a Biztosíték nyitva kell maradnia, mielőtt félig nyitva állna
  • a gyűrűpuffer mérete, amikor a Biztosíték félig nyitott vagy zárt
  • szokás CircuitBreakerEventListener amelyik kezeli Biztosíték események
  • szokás Állítmány amely értékeli, hogy egy kivételnek meghibásodásnak kell-e számítania, és ezáltal növelnie kell a meghibásodási arányt

4. Rate Limiter

Az előző szakaszhoz hasonlóan ehhez a funkcióhoz a rugalmasság4j-ratelimiter függőség.

Ahogy a neve is mutatja, ez a funkció lehetővé teszi bizonyos szolgáltatásokhoz való hozzáférés korlátozását. API-ja nagyon hasonlít a Megszakítók - vannak Iktató hivatal, Konfig és Limiter osztályok.

Íme egy példa a megjelenésére:

RateLimiterConfig config = RateLimiterConfig.custom (). LimitForPeriod (2) .build (); RateLimiterRegistry register = RateLimiterRegistry.of (config); RateLimiter rateLimiter = register.rateLimiter ("én"); Dekorált függvény = RateLimiter.decorateFunction (rateLimiter, service :: process);

Most minden hívás a díszített szervizblokkra, ha szükséges, hogy megfeleljen a sebességkorlátozó konfigurációjának.

Konfigurálhatunk olyan paramétereket, mint:

  • a limit frissítésének időszaka
  • a frissítési periódus engedélyeinek korlátja
  • az alapértelmezett várakozás az engedély időtartamára

5. Válaszfal

Itt először szükségünk lesz a rugalmasság4j-válaszfal függőség.

Lehetséges egy adott szolgáltatásra korlátozni az egyidejű hívások számát.

Lássunk egy példát a Bulkhead API használatára egyidejű hívások maximális számának konfigurálásához:

BulkheadConfig config = BulkheadConfig.custom (). MaxConcurrentCalls (1) .build (); BulkheadRegistry register = BulkheadRegistry.of (config); Válaszfal válaszfal = register.bulkhead ("én"); Funkció díszítve = Bulkhead.decorateFunction (válaszfal, szolgáltatás :: folyamat);

A konfiguráció teszteléséhez meghívjuk az álszolgáltatás módszerét.

Ezután biztosítjuk ezt Válaszfal nem engedélyez más hívásokat:

CountDownLatch retesz = new CountDownLatch (1); mikor (service.process (anyInt ())). thenAnswer (meghívás -> {latch.countDown (); Thread.currentThread (). join (); return null;}); ForkJoinTask task = ForkJoinPool.commonPool (). Submit (() -> {próbáld ki {díszített.apply (1);} végül {bulkhead.onComplete ();}}); retesz.várakozik (); assertThat (válaszfal.isCallPermitted ()). isFalse ();

A következő beállításokat konfigurálhatjuk:

  • a válaszfal által megengedett párhuzamos végrehajtások maximális mennyisége
  • a szál maximális időtartama, amíg egy telített válaszfalba próbál belépni

6. Próbálja újra

Ehhez a funkcióhoz hozzá kell adnunk a resilience4j-próbálkozzon újra könyvtár a projekthez.

Tudunk próbálkozzon újra egy sikertelen hívással a Retry API használatával:

RetryConfig config = RetryConfig.custom (). MaxAtt kísérletek (2) .build (); RetryRegistry register = RetryRegistry.of (config); Újrapróbálkozás = regisztráció.retry ("én"); Funkció díszítve = Retry.decorateFunction (próbálkozzon újra, (Egész szám s) -> {szolgáltatás.folyamat (ok); return null;});

Most utánozzunk egy olyan helyzetet, amikor a távoli szolgáltatási hívás során kivételt képezünk, és győződjünk meg arról, hogy a könyvtár automatikusan újrapróbálja a sikertelen hívást:

mikor (service.process (anyInt ())). thenThrow (new RuntimeException ()); próbáld ki a {díszített.alkalmazás (1); sikertelen ("Várható kivétel vetése, ha minden újrapróbálkozás sikertelen"); } catch (e kivétel) {verify (service, times (2)). process (any (Integer.class)); }

A következőket is konfigurálhatjuk:

  • a max. kísérletek száma
  • az újrapróbálkozás előtti várakozási idő
  • egyedi funkció a hiba utáni várakozási intervallum módosítására
  • szokás Állítmány amely kiértékeli, hogy egy kivétel eredményezheti-e a hívás újrapróbálkozását

7. Gyorsítótár

A Cache modulhoz a resilience4j-cache függőség.

Az inicializálás kissé eltérően néz ki, mint a többi modul:

javax.cache.Cache cache = ...; // Itt használja a megfelelő gyorsítótárat. Gyorsítótár cacheContext = Cache.of (cache); Funkció díszítve = Cache.decorateSupplier (cacheContext, () -> service.process (1));

Itt a gyorsítótárat a használt JSR-107 gyorsítótár-megvalósítás végzi, és a Resilience4j lehetőséget nyújt annak alkalmazására.

Vegye figyelembe, hogy a függvények (például Cache.decorateFunction (Funkció)), az API csak támogatja Támogató és Hívható típusok.

8. TimeLimiter

Ehhez a modulhoz hozzá kell adnunk a resilience4j-timelimiter függőség.

Lehetséges korlátozza a távoli szolgáltatás hívására fordított idő mennyiségét a TimeLimiter használatával.

A demonstráláshoz állítsunk fel egy TimeLimiter 1 milliszekundum konfigurált időtúllépés esetén:

hosszú ttl = 1; TimeLimiterConfig config = TimeLimiterConfig.custom (). TimeoutDuration (Durill.ofMillis (ttl)). Build (); TimeLimiter timeLimiter = TimeLimiter.of (config);

Ezután ellenőrizzük, hogy a Resilience4j hív-e Future.get () a várható időtúllépéssel:

Future futureMock = gúny (Future.class); Hívható limitedCall = TimeLimiter.decorateFutureSupplier (timeLimiter, () -> futureMock); limitedCall.call (); ellenőrizze (futureMock) .get (ttl, TimeUnit.MILLISECONDS);

Kombinálhatjuk azzal is Biztosíték:

Callable chainedCallable = CircuitBreaker.decorateCallable (circuitBreaker, limitedCall);

9. Kiegészítő modulok

A Resilience4j számos kiegészítő modult is kínál, amelyek megkönnyítik integrálását a népszerű keretrendszerekkel és könyvtárakkal.

Néhány legismertebb integráció:

  • Tavaszi csizma - resilience4j-spring-boot modul
  • Ratpack - resilience4j-ratpack modul
  • Utólagos felszerelés - rugalmasság4j-utólagos felszerelés modul
  • Vertx - rugalmasság4j-vertx modul
  • Dropwizard - rugalmasság4j-metrikák modul
  • Prométheusz - ellenálló képesség4j-prometheus modul

10. Következtetés

Ebben a cikkben átnéztük a Resilience4j könyvtár különböző aspektusait, és megtanultuk, hogyan kell használni a különböző hibatűrési problémák kezelésére a szerverek közötti kommunikáció során.

Mint mindig, a fenti minták forráskódja a GitHub oldalon található.