Vodič za otpornost4j

1. Pregled

U ovom uputstvu razgovarat ćemo o biblioteci Resilience4j.

Biblioteka pomaže u implementaciji elastičnih sustava upravljajući tolerancijom kvara za daljinske komunikacije.

Biblioteka je nadahnuta Hystrixom, ali nudi puno prikladniji API i brojne druge značajke poput Ograničenja brzine (blokiranje prečestih zahtjeva), Pregrada (izbjegavanje previše istodobnih zahtjeva) itd.

2. Postavljanje Mavena

Za početak trebamo dodati ciljne module u naš pom.xml (npr. ovdje dodamo prekidač):

 io.github.resilience4j elastičnost4j-osigurač 0.12.1 

Ovdje koristimo osigurač modul. Svi moduli i njihove najnovije verzije mogu se naći na Maven Central.

U sljedećim odjeljcima proći ćemo kroz najčešće korištene module knjižnice.

3. Automatski osigurač

Imajte na umu da nam je za ovaj modul potreban elastičnost4j-prekidač ovisnost prikazana gore.

Uzorak prekidača pomaže nam u sprječavanju kaskade kvarova kada je udaljena usluga isključena.

Nakon niza neuspjelih pokušaja, možemo smatrati da usluga nije dostupna / preopterećena i nestrpljivo odbiti sve sljedeće zahtjeve tome. Na taj način možemo uštedjeti resurse sustava za pozive koji će vjerojatno propasti.

Pogledajmo kako to možemo postići s Resilience4j.

Prvo, moramo definirati postavke koje ćemo koristiti. Najjednostavniji način je korištenje zadanih postavki:

CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults ();

Također je moguće koristiti prilagođene parametre:

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

Ovdje smo postavili prag brzine na 20% i minimalni broj 5 pokušaja poziva.

Zatim kreiramo Osigurač objekt i putem njega nazovite udaljenu uslugu:

sučelje RemoteService {proces int (int i); } CircuitBreakerRegistry registry = CircuitBreakerRegistry.of (config); CircuitBreaker circuitBreaker = registry.circuitBreaker ("moj"); Uređena funkcija = CircuitBreaker .decorateFunction (CircuitBreaker, service :: process);

Napokon, pogledajmo kako ovo funkcionira putem JUnit testa.

Pokušat ćemo nazvati službu 10 puta. Morali bismo biti u mogućnosti provjeriti je li poziv pokušan najmanje 5 puta, a zatim zaustavljen čim 20% poziva nije uspjelo:

kada (service.process (bilo koji (Integer.class))). thenThrow (new RuntimeException ()); for (int i = 0; i <10; i ++) {try {ukrašen.apply (i); } catch (Exception ignore) {}} verify (service, times (5)). process (bilo koji (Integer.class));

3.1. Prekidači Države i postavke

A Osigurač može biti u jednom od tri stanja:

  • ZATVORENO - sve je u redu, nema kratkog spoja
  • OTVORENA - udaljeni poslužitelj nije u funkciji, svi zahtjevi za njega su kratko spojeni
  • POLA_OTVORENO - proteklo je konfigurirano vrijeme od ulaska u stanje OTVORENO i Osigurač omogućuje zahtjeve da provjere je li udaljena usluga ponovno na mreži

Možemo konfigurirati sljedeće postavke:

  • prag stope otkaza iznad kojeg je Osigurač otvara i započinje kratki spoj
  • trajanje čekanja koje definira koliko dugo Osigurač treba ostati otvoren prije nego što se prebaci na poluotvoreno
  • veličina prstena u međuspremniku kada Osigurač je napola otvoren ili zatvoren
  • običaj CircuitBreakerEventListener koji rukuje Osigurač događaja
  • običaj Predikat koja procjenjuje treba li iznimka računati kao kvar i tako povećati stopu kvara

4. Ograničite ocjenu

Slično prethodnom odjeljku, i za ove značajke potreban je elastičnost4j-ratelimiter ovisnost.

Kao što naziv govori, ova funkcionalnost omogućuje ograničavanje pristupa nekim uslugama. Njegov API je vrlo sličan Prekidači - tamo su Registar, Config i Ograničitelj razreda.

Evo primjera kako to izgleda:

RateLimiterConfig config = RateLimiterConfig.custom (). LimitForPeriod (2) .build (); RateLimiterRegistry registry = RateLimiterRegistry.of (config); RateLimiter rateLimiter = registry.rateLimiter ("moj"); Uređena funkcija = RateLimiter.decorateFunction (rateLimiter, service :: process);

Sada se svi pozivi na ukrašenom servisnom bloku po potrebi prilagođavaju konfiguraciji ograničenja brzine.

Možemo konfigurirati parametre poput:

  • razdoblje ograničenja osvježavanja
  • ograničenje dopuštenja za razdoblje osvježavanja
  • zadano čekanje na trajanje dopuštenja

5. Pregrada

Evo, prvo će nam trebati elastičnost4j-pregrada ovisnost.

To je moguće kako biste ograničili broj istovremenih poziva na određenu uslugu.

Pogledajmo primjer korištenja Bulkhead API-ja za konfiguriranje maksimalnog broja istodobnih poziva:

BulkheadConfig config = BulkheadConfig.custom (). MaxConcurrentCalls (1) .build (); Registar BulkheadRegistry = BulkheadRegistry.of (config); Pregrada pregrada = registry.bulkhead ("moja"); Uređena funkcija = Bulkhead.decorateFunction (pregrada, usluga :: proces);

Da bismo testirali ovu konfiguraciju, pozvat ćemo metodu lažne usluge.

Tada to osiguravamo Pregrada ne dopušta nikakve druge pozive:

Zasun CountDownLatch = novi CountDownLatch (1); when (service.process (anyInt ())). thenAnswer (invocation -> {latch.countDown (); Thread.currentThread (). join (); return null;}); ForkJoinTask zadatak = ForkJoinPool.commonPool (). Submit (() -> {try {ukrašen.primijeniti (1);} konačno {bulkhead.onComplete ();}}); zasun.čekaj (); assertThat (bulkhead.isCallPermitted ()). isFalse ();

Možemo konfigurirati sljedeće postavke:

  • maksimalna količina paralelnih izvršavanja dopuštenih pregradom
  • maksimalno vrijeme koje će nit čekati kada pokušava ući u zasićenu pregradu

6. Pokušajte ponovo

Za ovu značajku morat ćemo dodati elastičnost4j-ponovni pokušaj knjižnica na projekt.

Možemo automatski pokušaj neuspjelog poziva pomoću API-ja za ponovni pokušaj:

RetryConfig config = RetryConfig.custom (). MaxAttempts (2) .build (); RetryRegistry registry = RetryRegistry.of (config); Pokušaj ponovno pokušaj = registry.retry ("moj"); Uređena funkcija = Retry.decorateFunction (pokušaj, (Integer s) -> {service.process (s); return null;});

Ajmo sada oponašati situaciju kada se tijekom poziva udaljene usluge baci izuzetak i osigurajmo da knjižnica automatski pokuša neuspjeli poziv:

kada (service.process (anyInt ())). thenThrow (new RuntimeException ()); pokušajte {ukrašen.apply (1); fail ("Očekivano izbacivanje iznimke ako svi pokušaji ne uspiju"); } catch (Iznimka e) {verify (service, times (2)). process (bilo koji (Integer.class)); }

Također možemo konfigurirati sljedeće:

  • maksimalan broj pokušaja
  • trajanje čekanja prije ponovnih pokušaja
  • prilagođena funkcija za izmjenu intervala čekanja nakon kvara
  • običaj Predikat koja procjenjuje treba li iznimka rezultirati ponovnim pozivom

7. Predmemorija

Modul Cache zahtijeva elastičnost4j-predmemorija ovisnost.

Inicijalizacija izgleda malo drugačije od ostalih modula:

javax.cache.Cache cache = ...; // Ovdje upotrijebite odgovarajuću predmemoriju Cache cacheContext = Cache.of (cache); Uređena funkcija = Cache.decorateSupplier (cacheContext, () -> service.process (1));

Ovdje se predmemoriranje vrši korištenom implementacijom predmemorije JSR-107, a Resilience4j pruža način da se primijeni.

Imajte na umu da ne postoji API za ukrašavanje funkcija (poput Cache.decorateFunction (funkcija)), API podržava samo Dobavljač i Pozivno vrste.

8. TimeLimiter

Za ovaj modul moramo dodati elastičnost4j-timelimiter ovisnost.

Moguće je ograničite količinu vremena provedenog na pozivanju udaljene usluge koristeći TimeLimiter.

Da bismo demonstrirali, postavimo a TimeLimiter s konfiguriranim vremenskim ograničenjem od 1 milisekunde:

dugo ttl = 1; TimeLimiterConfig config = TimeLimiterConfig.custom (). TimeoutDuration (Duration.ofMillis (ttl)). Build (); TimeLimiter timeLimiter = TimeLimiter.of (config);

Dalje, provjerimo da Resilience4j poziva Future.get () s očekivanim vremenskim ograničenjem:

Budućnost futureMock = lažno (Future.class); Pozivni ograničeni poziv = TimeLimiter.decorateFutureSupplier (timeLimiter, () -> futureMock); restrictedCall.call (); verify (futureMock) .get (ttl, TimeUnit.MILLISECONDS);

Također ga možemo kombinirati s Osigurač:

Poziv chainedCallable = CircuitBreaker.decorateCallable (circuitBreaker, restrictedCall);

9. Dodatni moduli

Resilience4j također nudi brojne dodatne module koji olakšavaju njegovu integraciju s popularnim okvirima i knjižnicama.

Neke od poznatijih integracija su:

  • Proljetna čizma - elastičnost4j-spring-boot modul
  • Ratpack - elastičnost4j-ratpack modul
  • Retrofit - elastičnost4j-naknadna ugradnja modul
  • Vertx - elastičnost4j-vertx modul
  • Čarobnjak - elastičnost4j-metrika modul
  • Prometej - elastičnost4j-prometheus modul

10. Zaključak

U ovom smo članku prošli kroz različite aspekte biblioteke Resilience4j i naučili kako je koristiti za rješavanje različitih problema s tolerancijom grešaka u komunikaciji između poslužitelja.

Kao i uvijek, izvorni kod za gornje uzorke možete pronaći na GitHubu.


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