1. Sarrera erabiltzen dira gaur egun erantzuten ez duten zerbitzuren bati edo besteari gehiegizko eskaerak ekiditeko. Esaterako, zerbitzu bat itzaltzen denean, edozein arrazoirengatik, etengailu batek, bere izenak dioen bezala, zirkuitua hautsi beharko luke. Hau da, zaldi lasterketa baten emaitzak lortzeko milioi bat eskaera aldi berean egiten diren egoeran, eskaera horiek hori kudeatu dezakeen beste zerbitzu batera bideratzea nahi dugu. Circuit-breakers Beste zerbitzu hau haren erreplika izan daiteke, edo jatorrizko zerbitzuaren hutsegiteari buruzko beste eragiketa batzuk egiteko soilik erabil daiteke. Azken helburua beti da beharrezkoa ez diren deiak apurtzea eta fluxua beste nonbait egitea. , Circuit Breaker diseinu eredua software garapenaren diseinuaren abangoardian jarri zuen. Hau bere argitalpenean egin zen Release It!: Design and Deploy Production-Ready Software (Pragmatic Programers) 1. Edizioa. 2017 Michael Nygard diseinuaren eredua benetako zirkuitu elektroniko eta elektrikoetan inspiratuta dago. Hala ere, kontzeptu orokor bati dagokionez, etengailuaren ideia benetan asmatu zuen . Garai hartan bezala, gainezka dagoen korronte bat kudeatu behar da. Termino oso-oso sinpleetan, hau da software-arkitekturari aplikatzen dioguna kasu honetan. Helburu nagusia sistema nahikoa erresistentea dela ziurtatzea da. Zein erresistentzia izan behar duen eta zeinen izan behar duen eredu hori ezartzea errazteaz arduratzen diren ingeniarien ustez. Horren atzean dagoen ideia da baldintza jakin batzuetan eskakizun jakin baten fluxua amaiera beraren atzean dagoen beste fluxu eskuragarriago batera erraz birbideratu nahi dugula. circuit breaker Thomas Edison 1879 fault-tolerant endpoint Demagun tik eskaera bat egin nahi dugula. Noizean behin, B-k huts egiten du eta beti dago eskuragarri. ausaz huts egiten badu, iritsi nahi dugu gure zerbitzua guztiz erabilgarri izan dadin. Hala ere, ra itzultzeko eskaerak egiteko, ziurtatu nahi dugu ez duela hainbeste huts egingo berriro. Ondoren, gure sistema konfiguratu dezakegu B-ri ausazko eskaerak egiteko eta ra guztiz itzultzeko hutsegite-tasa maila jakin bat jaitsi denean. A B C B C B B B Agian C eskaera egin nahi dugu errorean baina baita latentzian ere. oso motela bada, baliteke eskaera guztiak ra berriro bidali nahi izatea. Beste konfigurazio posible asko daude, hala nola iristen saiatzea saiakera kopuru zehaztu baten ondoren, eskaera motak, aldibereko hariak eta beste hainbat aukera. B C short-circuiting C Etengailu bat benetan zer den ezagutzen dugun gehiago ulertzeko, etenaldi batek gure aplikazioan entitate gisa funtzionatzen duela ulertu behar dugu. Hiru egoera nagusi daude etengailu baten kasuan. Itxita, irekia edo erdi irekia izan daiteke. Itxitako egoera batek gure aplikazio-fluxuak normal exekutatzen direla esan nahi du. Segurtasunez egin ditzakegu eskaerak A zerbitzura, jakinik eskaera guztiak B zerbitzura joango direla. Egoera ireki batek B zerbitzurako eskaera guztiek huts egingo dutela esan nahi du. Porrot bat irudikatzeko definitu ditugun arauak gertatu dira eta jada ez gara B zerbitzura iristen. Kasu honetan, salbuespen bat itzultzen da beti. egoera da gure etengailuak B zerbitzuan probak egiteko agintzen dionean berriro martxan dagoen ikusteko. half-open Eskaera arrakastatsu bakoitza normaltasunez kudeatzen da, baina C-ri eskaerak egiten jarraituko du. B-k ezarri ditugun egiaztapen-arauen arabera espero bezala jokatzen badu, gure etengailua itxita egoerara itzuliko da eta A zerbitzua egiten hasiko da. B zerbitzuari soilik eskatzen dio. Aplikazio gehienetan, etengailu batek dekoratzaileen diseinu-eredua jarraitzen du. Hala ere, eskuz inplementa daiteke, eta etengailuak ezartzeko eta, azkenik, AOPn oinarritutako inplementazio bat erabiltzeko hiru modu programatiko aztertuko ditugu. Kodea en dago eskuragarri. GitHub- 2. Autoen egiaztapenak Artikulu honen azken puntuan, auto-lasterketen joko bat ikusiko dugu. Hala ere, hara iritsi baino lehen, batekin exekutatzen den aplikazio bat eraikitzeko alderdi batzuk gidatu nahi zaitut. circuit breaker 2.1. Kystrix (parisetik-berlinera-kystrix-runnable-app) , txiki gisa , asmatu eta sortutako liburutegi harrigarria da . Liburutegiak aukera asko eskaintzen ditu, Spring eta Spring WebFlux-ekin integratzea barne. Interesgarria da begirada bat ematea eta pixka bat jolastea: Kystrixs DSL Johan Haleby <dependency> <groupId>se.haleby.kystrix</groupId> <artifactId>kystrix-core</artifactId> </dependency> <dependency> <groupId>se.haleby.kystrix</groupId> <artifactId>kystrix-spring</artifactId> </dependency> Adibide bat sortu dut, eta -eko moduluan dago. Lehenik eta behin, kodeari begirada bat emango diogu: GitHub from-paris-to-berlin-kystrix-runnable-app @GetMapping("/{id}") private fun getCars(@PathVariable id: Int): Mono<Car> { return if (id == 1) Mono.just(Car("Jaguar")) else { hystrixObservableCommand<Car> { groupKey("Test2") commandKey("Test-Command2") monoCommand { webClient.get().uri("/cars/carros/1").retrieve().bodyToMono<Car>() .delayElement(Duration.ofSeconds(1)) } commandProperties { withRequestLogEnabled(true) withExecutionTimeoutInMilliseconds(5000) withExecutionTimeoutEnabled(true) withFallbackEnabled(true) withCircuitBreakerEnabled(false) withCircuitBreakerForceClosed(true) } fallback { Observable.just(Car("Tank1")) } }.toMono() } } Kode honek adibideko 2. komandoa adierazten du. Egiaztatu komandoaren kodea 1. Hemen gertatzen ari dena da nahi dugun komandoa definitzen ari garela. Hemen, deitu behar dugun metodoa definitzen dugu. -en, irekitzeko egoera aldatzen duten arauak definitzen ditugu. Gure deia berariaz atzeratzen dugu segundo 1 irauteko. monoCommand commandProperties circuit-breaker Aldi berean, milisegundoko denbora-muga definitzen dugu. Horrek esan nahi du inoiz ez garela denbora-muga batera iritsiko. Adibide honetan, batekin deiak egin ditzakegu. Proba bat besterik ez denez, suposatuko dugu, auto baten bat dela, behar ez duen Jaguar bat. Horrek ere esan nahi du inoiz ez dugula Tank1 lortuko fallback metodoan definitutako moduan. Oraindik ohartu ez bazara, begiratu arretaz atzerako metodoari. Metodo honek bat erabiltzen du. diseinu ereduaren arabera inplementatzen den arren, ez da zehazki Behagarri bat. 5000 Id Id=1 Id circuit-breaker Observable WebFlux Observable Flux Hala ere, hystrix-ek biak onartzen ditu. Exekutatu aplikazioa eta ireki zure arakatzailea helbidean, hau baieztatzeko. Garrantzitsua da ulertzea Spring Boot abiaraztean deiak egiten oso goiz hasten bazara, azkenean Tank1 mezu bat jaso dezakezula. Hau da, abioko atzerapenak 5 segundo gainditu ditzakeelako oso erraz prozesu hau exekutatzen ari zarenaren arabera. Bigarren adibidean, gure adibidea Tank 2-ra zirkuitu laburtuko dugu: http://localhost:8080/cars/2 @GetMapping("/timeout/{id}") private fun getCarsTimeout(@PathVariable id: Int): Mono<Car> { return if (id == 1) Mono.just(Car("Jaguar")) else { hystrixObservableCommand<Car> { groupKey("Test3") commandKey("Test-Command3") monoCommand { webClient.get().uri("/cars/carros/1").retrieve().bodyToMono<Car>() .delayElement(Duration.ofSeconds(1)) } commandProperties { withRequestLogEnabled(true) withExecutionIsolationThreadInterruptOnTimeout(true) withExecutionTimeoutInMilliseconds(500) withExecutionTimeoutEnabled(true) withFallbackEnabled(true) withCircuitBreakerEnabled(false) withCircuitBreakerForceClosed(true) } fallback { Observable.just(Car("Tank2")) } }.toMono() } } Adibide honetan, gure egoera irekiko amaierako itzulera Tank 2 batera sartuko da erantzun gisa. Hau da, hemen ere 1s atzerapena eragiten ari garelako, baina gure zirkuitu etenaldiaren egoera 500 ms-ren ondoren abiarazten dela zehazten dugu. nola funtzionatzen duen ezagutzen baduzu, aurrerantzean ez duela ezer desberdina ikusiko duzu. Une honetan Hystrix-ek eman ez zidana, jokoa egiteko behar nuena eskaintzeko modurik gabeko eta esfortzurik gabekoa izan zen. bezeroaren arabera lan egiten duela dirudi. Horrek esan nahi du gure kodea deklaratu behar dugula gure zerbitzu nagusiaren atzean dauden zerbitzuei eskaerak egin aurretik. circuit-breaker hystrix kystrix Kystrix 2.2. Erresilientzia4J badirudi askok etengailu baten ezarpen oso gisa aipatzen dutela. Nire lehenengo saiakerak etengailuen alderdi garrantzitsu batzuk aztertzen joan ziren. Hots, etengailu bat ikusi nahi nuen denbora-muga eta eskaera arrakastatsuen maiztasunaren arabera funtziona zezakeen. mota desberdinak konfiguratzeko aukera ematen du. Hauek kategoria desberdinetan bereizten dira: , , , eta . Horiek guztiak diseinu ereduen izenak ere badira. moduluak eredu honen inplementazio osoa eskaintzen du. Resilience4J Resilience4J short-circuiting 6 CircuitBreaker Bulkhead Ratelimiter Retry Timelimiter CircuitBreaker Konfiguratu ditzakegun parametro asko ditugu, baina funtsean, moduluak hutsegite gisa antzematen duguna konfiguratzeko aukera ematen digu, zenbat eskaera onartzen ditugun erdi irekian eta leiho irristakorra, denboraren arabera konfigura daitekeena edo. zenbaketa, non egoera itxian gertatzen diren eskaeren zenbaketa mantentzen dugun. Hau garrantzitsua da errore-maiztasuna kalkulatzeko. Funtsean, modulu honek eskaeren tasarekin lagunduko digula esan genezake, baina hori ez da zertan egia. CircuitBreaker CircuitBreaker Nola interpretatzen duzunaren araberakoa da. Modu hobea dirudi akatsei aurre egiteko modu bat besterik ez dela pentsatzeko. Denbora-muga batetik edo salbuespen batetik datozen ala ez, hemen tratatzen dira eta eskaerak modu errazean birbideratu daitezke beste nonbait. modulua aldibereko eskaerei aurre egiteko diseinatuta dago. Ez da tasa mugatzailea. Bulkhead Horren ordez, diseinu eredua inplementatzen du, prozesatzeko gehiegizko puntu bakar batean gerta ez dadin erabiltzen dena. Kasu honetan, gure eskaerak prozesatzeko aukera ematen digu eskuragarri dauden amaiera-puntu guztietan banatzeko moduan. izena itsasontzi handi batek normalean hondoratzea saihestu behar duen konpartimentu itxietatik dator, istripu bat gertatuz gero, eta itsasontzien kasuan bezala, hari-igerilekuan zenbat hari egongo diren eta alokairu-denbora zehaztu behar dugu. . Bulkhead Bulkhead Bulkhead modulua eskaeren tasa kudeatzeko diseinatuta dago. Honen eta moduluaren arteko aldea ezinbestekoa da puntu jakin batera arte tasekin tolerantea izan nahi dugula. Horrek esan nahi du ez dugula porrotik eragin behar horretarako. Diseinuan esaten dugu ez dugula balio jakin batetik gorako tasarik onartzen. Horrez gain, eskaera bat birbideratu edo atxikita eduki dezakegu eskaera egiteko baimena eman arte. modulua da ulertzeko errazena, ez baitu beste moduluekin zerikusi handirik. RateLimiter Bulkhead Retry Funtsean, amaiera-puntu jakin baterako errepikapenen kopurua esplizituki adierazten dugu, gure definitutako atalasea iritsi arte. modulua moduluaren sinplifikazio gisa ikus daiteke, biek denbora-muga konfiguratzeko aukera partekatzen baitute. Hala ere, ez dago beste parametro batzuen menpekoa, adibidez, leiho irristagarriak, eta ez du eraikuntza barneko hutsegite atalasearen kalkulurik. Timelimiter CircuitBreaker Timelimiter Beraz, zerbitzu jakin bati deitzean denbora-muga batzuk kudeatzea interesatzen bazaigu eta beste akats posibleak kontuan hartzen ez baditugu, seguruenik hobeto egongo gara ekin. Timelimiter 2.2.1. Resilience4J Kotlin eta No Spring esparruarekin (from-paris-to-berlin-resilience4j-runnable-app) Modulu honetan, kotlin liburutegia soilik erabiltzea erabaki dut: resilience4j <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-kotlin</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-retry</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-circuitbreaker</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-ratelimiter</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-timelimiter</artifactId> </dependency> Inplementazio hau GitHub-en repo-n dago eskuragarri. Lehenik eta behin ereduari begiratuko diogu: TimeLimiter var timeLimiterConfig: TimeLimiterConfig = TimeLimiterConfig.custom() .timeoutDuration(Duration.ofMillis(100)) .build() var timeLimiter: TimeLimiter = TimeLimiter.of("backendName", timeLimiterConfig) private suspend fun getPublicCar(): Car { return timeLimiter.decorateSuspendFunction { getPrivateCar() }.let { suspendFunction -> try { suspendFunction() } catch (exception: Exception) { Car("Opel Corsa") } } } private suspend fun getPrivateCar(): Car { delay(10000) return Car("Lancya") } Kasu honetan, funtzioarekin apaintzen ari gara funtzioa erabiliz. Honek egingo duena denbora-muga eragitea da, deitzen dugun funtzioak denbora gehiegi hartzen badu Opel Corsa bat lortuko dugu Lancya baten ordez. Hau probatzeko, aplikazioa exekutatu eta ireki besterik ez dugu egin. getPrivateCar function TimeLimiter decorateSuspendFunction http://localhost:8080/cars/timelimiter/normal/1 Inplementazioari begira, ikusten dugu inoiz ezin dugula bat lortu. Eta hori nahita itxaroten dugulako itzuli aurretik. Gure denbora-muga askoz txikiagoa du, beraz, honek ez du inoiz funtzionatuko. nahiko erraza da ulertzeko. A , berriz, beste istorio bat izan daiteke. Hau nola egin daitekeen adibide bat da: Lancya 10s TimeLimiter TimeLimiter CircuitBreaker val circuitBreakerConfig = CircuitBreakerConfig.custom() .failureRateThreshold(20f) .slowCallRateThreshold(50f) .slowCallDurationThreshold(Duration.ofMillis(1000)) .waitDurationInOpenState(Duration.ofMillis(1000)) .maxWaitDurationInHalfOpenState(Duration.ofMillis(1000)) .permittedNumberOfCallsInHalfOpenState(500) .minimumNumberOfCalls(2) .slidingWindowSize(2) .slidingWindowType(COUNT_BASED) .build() val circuitBreaker = CircuitBreakerRegistry.of(circuitBreakerConfig).circuitBreaker("TEST") private suspend fun getPublicCar(id: Long): Car { return circuitBreaker.decorateSuspendFunction { getPrivateCar(id) }.let { suspendFunction -> try { suspendFunction() } catch (exception: Exception) { Car("Opel Corsa") } } } private fun getPrivateCar(id: Long): Car { if (id == 2L) { throw RuntimeException() } return Car("Lancya") } Kasu honetan, esaten ari gara gure etengailuak zirkuitua ixtea nahi dugula, jabetzarekin hutsegite-tasa baino txikiagoa denean. Dei geldoek ere atalasea izango dute, baina kasu honetan, %50etik beherakoa izango da. Dei geldo batek 1s baino gehiago iraun behar duela esaten dugu bat hartzeko. Gainera, egoera erdi ireki baten iraupena 1s izan behar dela zehazten ari gara. Horrek esan nahi du, praktikan, egoera irekia, erdi irekia edo itxia izango dugula. 20% Era berean, esaten dugu gehienez ere 500 estatu erdi irekiko eskaera onartzen ditugula. Erroreak kalkulatzeko, etengailuak jakin behar du zein markatan egingo duen hori. Hau garrantzitsua da zirkuitua noiz itxi behar den zehazteko. Kalkulu honetarako gutxieneko 2 eskaera beharrezkoak izango direla esaten dugu, propietatearekin. Gogoratzen al duzu erdi irekia dela zirkuitua ixten saiatzen ari garela eskaerak hutsegite seguruaren atalasea iristen badira? minimumNumberOfCalls Konfigurazio honetan, esan nahi du gutxienez eskaera egin behar ditugula, leiho lerragarriaren barruan, errore-maiztasuna kalkulatzeko eta egoera itxi batera itzuli edo ez zehazteko. Hau da konfiguratu ditugun aldagai guztien irakurketa zehatza. Oro har, horrek esan nahi duena da gure aplikazioak seguruenik hainbat dei egingo dituela zerbitzu alternatibora, halakorik egonez gero, ez da oso erraz pasako egoera irekitik itxiera, izan ere, erdibidean horretarako arrakasta-tasa % 80koa izan behar da. -open egoerak eta irekitako egoerarako denbora-muga gertatu behar da. 2 Modu asko daude denbora-muga horiek zehazteko. Gure adibidean, 1s dela esaten dugu. Horrek esan nahi du gure egoera irekita mantenduko duela, gure egiaztapenak itxitako egoera baldintza betetzen ez badu edo denbora-muga hori oraindik gertatu ez bada. honetan definitutako portaera zaila izan daiteke jarraitzea eta aurreikustea, eskaeren geldialdi-denbora, tasa eta bestelako ezaugarri zehatzak ezin direlako zehatz-mehatz errepikatu, baina amaierako puntu honetara hainbat eskaera egiten baditugu, ikusiko dugu. goian azaldutako jokabidea gure esperientziarekin bat dator. maxDurationInHalfOpenState CircuitBreaker CircuitBreaker Beraz, saia gaitezen amaierako puntuei hainbat eskaera egiten: eta . 1ean amaitzen den autoa arrakastaz berreskuratzearen amaiera da, eta 2z amaitzea zehaztutako autoa eskuratzean huts egin izanaren amaiera da. Kodea ikusita, 2 bat ez den edozerk esan nahi du bat jasotzen dugula erantzun gisa. A , esan nahi du berehala botatzen dugula exekuzio-denboraren salbuespena, hau da, erantzun gisa bat lortzen dugula esan nahi du. http://localhost:8080/cars/circuit/1 http://localhost:8080/cars/circuit/2 Lancya 2 Opel Corsa amaierako puntuari eskaerak egiten baditugu, erantzun gisa ikusten jarraituko dugu. Sistema huts egiten hasten bada, orduan 2-ri eskaerak egiten dizkiozu,\; ikusiko duzu itzultzea ez dela etengabea izango pixka bat igaro ondoren. Ireki egoeran dagoela jakinaraziko du eta ez dela eskaera gehiago onartzen. 1 Lancya Lancya System 2021-10-20 09:56:50.492 ERROR 34064 --- [ctor-http-nio-2] .fcbrrcCarControllerCircuitBreaker : io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'TEST' is OPEN and does not permit further calls Orduan, gure etengailua erdi irekiko egoerara joango da eskaera arrakastatsu baten ondoren, eta horrek esan nahi du eskaera batzuk 1era itzuli beharko ditugula normalizatu aurretik. aldatuko gara pare bat aldiz berriro eskuratu baino lehen. Zenbaki hau 2 dela definitu dugu. Hau da erroreen kalkulurako minimoa. Huts bakarra eragiten badugu eta huts egiten ez duen amaierako puntuari deitzen jarraitzen badugu, gertatzen ari denaren irudi argiago bat lor dezakegu: Lancya Opel Corsa Lancya 2021-10-20 11:53:29.058 ERROR 34090 --- [ctor-http-nio-4] .fcbrrcCarControllerCircuitBreaker : java.lang.RuntimeException 2021-10-20 11:53:41.102 ERROR 34090 --- [ctor-http-nio-4] .fcbrrcCarControllerCircuitBreaker : io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'TEST' is OPEN and does not permit further calls Egoera irekiko mezu hau, egia izan arren, huts egin ez duen amaierako 2 eskaera egin ondoren gertatu da. Horregatik estatua erdi irekia omen da. 2.2.2. Resilience4J Spring Boot-ekin eta AOPrik gabe (from-paris-to-berlin-resilience4j-spring-app) Aurreko segmentuan, oso modu programatikoan nola inplementatu ikusi genuen, Spring teknologiarik erabili gabe. Spring erabili genuen baina zerbitzu mota bat eskaintzeko soilik. Gainera, ez dugu ezer aldatu zerbitzuei buruz. Hurrengo aplikazioan, honako liburutegi hauek aztertuko ditugu: WebFlux MVC <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-all</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-reactor</artifactId> </dependency> Kodea nola egiten den aztertzean, alde handia ikus dezakegu: @RestController @RequestMapping("/cars") class CarController( private val carService: CarService, timeLimiterRegistry: TimeLimiterRegistry, circuitBreakerRegistry: CircuitBreakerRegistry, bulkheadRegistry: BulkheadRegistry ) { private var timeLimiter: TimeLimiter = timeLimiterRegistry.timeLimiter(CARS) private var circuitBreaker = circuitBreakerRegistry.circuitBreaker(CARS) private var bulkhead = bulkheadRegistry.bulkhead(CARS) @GetMapping("/{id}") private fun getCars(@PathVariable id: Int): Mono<Car> { return carService.getCar() .transform(TimeLimiterOperator.of(timeLimiter)) .transform(CircuitBreakerOperator.of(circuitBreaker)) .transform(BulkheadOperator.of(bulkhead)) .onErrorResume(TimeoutException::class.java, ::fallback) } @GetMapping("/test/{id}") private fun getCarsTest(@PathVariable id: Int): Mono<Car> { return carService.getCar() .transform(TimeLimiterOperator.of(timeLimiter)) .transform(CircuitBreakerOperator.of(circuitBreaker)) .transform(BulkheadOperator.of(bulkhead)) .onErrorResume(TimeoutException::class.java, ::fallback) } @GetMapping("/carros/{id}") private fun getCarros(@PathVariable id: Long): Mono<Car> { return Mono.just(Car("Laborghini")) } private fun fallback(ex: Throwable): Mono<Car> { return Mono.just(Car("Rolls Royce")) } } Adibide honetan eta hurrengoan, denbora-muga propietateei begiratuko diegu gehienbat. -en konplexutasunak ez dira hain garrantzitsuak hau sarrerako artikulua delako. Garrantzitsua dena konturatzea da -k Udaberrirako eskaintzen dituen dekoratzaileekin hori zein erraz ezar dezakegun. Modu oraindik ere, gure hasierako argitaletxea erraz apain dezakegu, -tik lortzen duguna, nahi ditugun motekin. CircuitBreaker Resilience4J programmatical carService.getCar() short-circuit Adibide honetan, , eta bat erregistratzen ditugu. Azkenik, TimeoutException bat gertatutakoan abiarazteko funtzioa definitzen dugu. Ikusi behar duguna da hau guztia nola konfiguratuta dagoen. Udaberrian Resilience4J konfiguratzen dugu beste edozein modulu konfiguragarri bezala. erabiltzen dugu: TimeLiter BulkHead CircuitBreaker application.yml resilience4j.circuitbreaker: configs: default: registerHealthIndicator: true slidingWindowSize: 10 minimumNumberOfCalls: 5 permittedNumberOfCallsInHalfOpenState: 3 automaticTransitionFromOpenToHalfOpenEnabled: true waitDurationInOpenState: 5s failureRateThreshold: 50 eventConsumerBufferSize: 10 recordExceptions: - org.springframework.web.client.HttpServerErrorException - java.util.concurrent.TimeoutException - java.io.IOException ignoreExceptions: # - io.github.robwin.exception.BusinessException shared: slidingWindowSize: 100 permittedNumberOfCallsInHalfOpenState: 30 waitDurationInOpenState: 1s failureRateThreshold: 50 eventConsumerBufferSize: 10 ignoreExceptions: # - io.github.robwin.exception.BusinessException instances: cars: baseConfig: default roads: registerHealthIndicator: true slidingWindowSize: 10 minimumNumberOfCalls: 10 permittedNumberOfCallsInHalfOpenState: 3 waitDurationInOpenState: 5s failureRateThreshold: 50 eventConsumerBufferSize: 10 # recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate resilience4j.retry: configs: default: maxAttempts: 3 waitDuration: 100 retryExceptions: - org.springframework.web.client.HttpServerErrorException - java.util.concurrent.TimeoutException - java.io.IOException ignoreExceptions: # - io.github.robwin.exception.BusinessException instances: cars: baseConfig: default roads: baseConfig: default resilience4j.bulkhead: configs: default: maxConcurrentCalls: 100 instances: cars: maxConcurrentCalls: 10 roads: maxWaitDuration: 10ms maxConcurrentCalls: 20 resilience4j.thread-pool-bulkhead: configs: default: maxThreadPoolSize: 4 coreThreadPoolSize: 2 queueCapacity: 2 instances: cars: baseConfig: default roads: maxThreadPoolSize: 1 coreThreadPoolSize: 1 queueCapacity: 1 resilience4j.ratelimiter: configs: default: registerHealthIndicator: false limitForPeriod: 10 limitRefreshPeriod: 1s timeoutDuration: 0 eventConsumerBufferSize: 100 instances: cars: baseConfig: default roads: limitForPeriod: 6 limitRefreshPeriod: 500ms timeoutDuration: 3s resilience4j.timelimiter: configs: default: cancelRunningFuture: false timeoutDuration: 2s instances: cars: baseConfig: default roads: baseConfig: default Fitxategi hau beren errepositoriotik hartutako adibide-fitxategi bat da eta horren arabera nire adibidera aldatu da. Lehen ikusi dugunez, mota ezberdinen instantziek izen bat dute. Izena oso garrantzitsua da hainbat erregistro eta mugatzaile desberdinak badituzu. Gure adibiderako, eta lehen aipatu bezala, denbora-mugatzailea interesatzen zaigu. 2setara mugatuta dagoela ikus dezakegu. Zerbitzua inplementatu dugun moduari erreparatzen badiogu, ikusten dugu denbora-muga bat gertatzera behartzen ari garela: limiters/short-circuit @Component open class CarService { open fun getCar(): Mono<Car> { return Mono.just(Car("Fiat")).delayElement(Duration.ofSeconds(10)); } } Hasi gaitezen aplikazioa, eta arakatzailean, joan hona: . bat eskuratu beharrean, bat lortuko dugu. Horrela definitu dugu denbora-muga. Modu berean, bat erraz sor dezakegu. http://localhost:8080/cars/test/2 Fiat Rolls Royce CircuitBreaker 3. Kasua Orain arte, eta erlazionatutako mugatzaileak ezartzeko hiru modu ezinbesteko ikusi ditugu. Gainera, etengailuak ezartzeko dudan modurik gogokoena aztertuko dugu, nik egindako aplikazio batetik pasatuz, hau da, oso joko sinple bat, non karratuetan klik egiten dugun Paristik Berlinera joateko. Jokoa nola inplementatu ulertzeko egiten da. Ez du asko esaten hau non gauzatu. Zuekin ezagutzak partekatzeko diseinatu dudan kasu bat besterik ez da. CircuitBreakers Jakina noiz uzten dizut gero erabakitzeko. Funtsean, hainbat kotxe sortu eta Berlinera bide bat ezarri nahi dugu. Ibilbide honetako toki ezberdinetan, ausaz arazoak sortuko ditugun hirietara iritsiko gara. Gure erabakiko dute zenbat denbora itxaron beharko dugun aurrera jarraitu ahal izateko. Beste autoek ez dute arazorik, eta bide egokia aukeratu besterik ez dugu egin behar. circuit breakers Ordutegi bat egiaztatzeko baimena dugu non erregistratuta dagoen hiri batean arazo jakin bat minutu jakin batean gertatuko den. Minutu marka baliozkoa da bere 0 posizio indexatuetan. Horrek esan nahi du 2k esan nahi du erlojuaren 2, 12, 22, 32, 42, 52 minutuko marka balio izango duela arazo hau sortzeko. Arazoak 2 motakoak izango dira: eta . Errore-huts batek 20 segundoko atzerapena emango dizu. every ERROR TIMEOUT Denbora-muga batek 50 segundoko atzerapena emango dizu. Hiri aldaketa bakoitzeko, denek 10 segundo itxaron behar dute. Itxaron baino lehen, ordea, autoa hurrengo hiriko sarreran dago jada hori atzerako metodoetan egiten denean. Kasu honetan, hurrengo hiria ausaz aukeratzen da. 4. Ezarpena Lehenago ikusi dugu nola konfiguratu gure erregistroa erabiliz. Hau eginda, ikus ditzagun gure funtzioak apaintzeko adibide batzuk: resilience4j application.yml @TimeLimiter(name = CarService.CARS, fallbackMethod = "reportTimeout") @CircuitBreaker(name = CarService.CARS, fallbackMethod = "reportError") @Bulkhead(name = CarService.CARS) open fun moveToCity(id: Long): Mono<RoadRace> { val myCar = roadRace.getMyCar() if (!myCar.isWaiting()) { val destination = myCar.location.forward.find { it.id == id } val blockage = destination?.blockageTimeTable?.find { it.minute.toString().last() == LocalDateTime.now().minute.toString().last() } blockage?.let { roadBlockTime -> when (roadBlockTime.blockageType) { BlockageType.TIMEOUT -> return Mono.just(roadRace).delayElement(Duration.ofSeconds(10)) BlockageType.ERROR -> return Mono.create { it.error(BlockageException()) } BlockageType.UNKNOWN -> return listOf(Mono.create { it.error(BlockageException()) }, Mono.just(roadRace).delayElement(Duration.ofSeconds(10))).random() else -> print("Nothing to do here!") } } destination?.let { myCar.delay(10) myCar.location = it myCar.formerLocations.add(myCar.location) } } return Mono.just(roadRace) } private fun reportError(exception: Exception): Mono<RoadRace> { logger.info("---- **** error reported") roadRace.getMyCar().delay(20L) roadRace.getMyCar().randomFw() roadRace.errorReports.add("Error reported! at ${LocalDateTime.now()}") return Mono.create { it.error(BlockageException()) } } private fun reportTimeout(exception: TimeoutException): Mono<RoadRace> { logger.info("---- **** timeout reported!") roadRace.getMyCar().delay(50L) roadRace.getMyCar().randomFw() roadRace.errorReports.add("Timeout reported! at ${LocalDateTime.now()}") return Mono.just(roadRace) } Ikus dezakegunez, jatorrizko zerbitzu-deiak zuzenean apaintzen dira oharrak erabiliz! Hau paketean modulua egoteagatik bakarrik egin daiteke: AOP <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> edo oinarritutako beste programazio paradigma bat da. ren osagarritzat hartzen da, eta hain zuzen ere zenbat oharrak funtzionatzen duten. Honek jatorrizko metodoaren inguruan, aurretik edo ondoren beste funtzio batzuk abiarazteko aukera ematen du ebaketa-puntu zehatzetan. Adibidean ikus dezakezun bezala, denbora-muga edo erroreak sortzen ari gara. , era berean, ordezko metodoaren barruan sortzen da. Horrek ez du arazo bat adierazten. Erantzuna izan ezik. AOP Aspect Oriented Programming OOP OOP BlockageException Hala ere, aplikazioa eta, beraz, errore hau ez da aplikazioan ikusiko. Orain arte, hau zen jokoa. Hau inplementatu nuen, oharrak erabiltzeak gure bizitza askoz errazagoa izan dezakeen erakusteko helburuarekin, aplikazio erresiliente bat inplementatzen denean. CircuitBreakers ez ezik, beste teknologia batzuk ere baditugu, hala nola , , , , eta beste hainbat. Hau guztia CircuitBreakers aplikazio batean nola jokatuko lukeen ikusteko egin da. Aplikazio honekin jolastu nahi baduzu, joan proiektuaren errora eta exekutatu: WebSockets, WebSockets Spring WebFlux Docker NGINX typescript make docker-clean-build-start Ondoren, exekutatu komando hau: curl -X POST http://localhost:8080/api/fptb/blockage -H "Content-Type: application/json" --data '{"id":1,"name":"Paris","forward":[{"id":2,"name":"Soissons","forward":[{"id":5,"name":"Aken","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":6,"name":"Heerlen","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":7,"name":"Düren","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":3,"name":"Compiègne","forward":[{"id":5,"name":"Aken","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":6,"name":"Heerlen","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":7,"name":"Düren","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":4,"name":"Reims","forward":[{"id":5,"name":"Aken","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":6,"name":"Heerlen","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]},{"id":7,"name":"Düren","forward":[{"id":8,"name":"Berlin","forward":[],"blockageTimeTable":[]}],"blockageTimeTable":[]}],"blockageTimeTable":[]}],"blockageTimeTable":[]}' Eskaera honen karga modulua erabiliz sortzen da. Modulu hau aztertzen baduzu, ulertu nahiko erraza dela ikusiko duzu eta jokorako zure mapa sortu dezakezula! Azkenik, joan helbidera eta zure aplikazioa martxan egon beharko litzateke! Orain, eskuineko laukietan klik egin beharko zenuke jokoan aritzeko. Ez egin klik gorrietan irabazi nahi baduzu. Zirkuitu-disektorea martxan ikusi nahi baduzu, mesedez, exekutatu aplikazioen erregistroak: from-paris-to-berlin-city-generator http://localhost:9000 docker logs from_paris_to_berlin_web -f Eta esplizituki egin klik lauki gorrietan hutsegite bat eragiteko. 5. Nola desberdintzen diren Kystrix eta Resilience4J aproposa da zure aplikazioa txikia den kasuetan, eta DSLaren erabilera oso baxua mantentzen dela ziurtatu nahi duzu. Badirudi alde txar bakarra ez duela etengailu batek eraginda eragiteko metodoak apaintzeko modu errazik eskaintzen. aukera paregabea dirudi etengailuekin enpresa-lanerako. Oharpenetan oinarritutako programazioa eskaintzen du, AOPren abantaila guztiak erabiltzen ditu eta bere moduluak bereizita daude. Nolabait esateko, aplikazioko puntu kritikoetarako ere estrategikoki erabil daiteke. Aplikazio baten alderdi asko estaltzeko esparru oso gisa ere erabil daiteke. Kystrix Resilience4J 6. Ondorioa Aukeratzen dugun marka edozein dela ere, helburua beti da aplikazio erresiliente bat izatea. Artikulu honetan, etengailuak ikertzen eta nire aurkikuntzak maila oso altuan bizi izan ditudan adibide batzuk erakutsi ditut. Horrek esan nahi du artikulu hau etengailuak zer diren eta mugatzaileek zer egin dezaketen jakin nahi duten pertsonentzat idatzita dagoela. Aukerak amaigabeak dira gure aplikazioak bezalako erresilientzia mekanismoekin hobetzea pentsatzen denean. Eredu honek aplikazio bat doitzeko aukera ematen du, ditugun baliabideak hobeto erabiltzeko. Gehienbat hodeian, oraindik oso garrantzitsua da gure kostuak optimizatzea eta zenbat baliabide esleitu behar ditugun benetan. circuit breakers konfiguratzea ez da zeregin hutsala Mugatzaileentzat bezala, eta benetan konfigurazio aukera guztiak ulertu behar ditugu errendimendu eta erresilientzia maila ezin hobeak lortzeko. Hau da etengailuei buruzko sarrerako artikulu honetan xehetasunetan sartu nahi izan ez dudan arrazoia. CircuitBreakers aplikazio mota askotara aplika daitezke. Mezularitza eta streaming aplikazio mota gehienek hau beharko dute. Oso eskuragarri egon behar duten datu-bolumen handiak kudeatzen dituzten aplikazioetarako, etengailuaren formaren bat inplementatu dezakegu eta behar dugu. Lineako txikizkako denda handiek datu kopuru handiak kudeatu behar dituzte egunero eta iraganean, oso erabilia zen. Gaur egun, badirudi hau baino askoz gehiago biltzen duen norabidean goazela. Circuit-breakers Hystrix Resilience4J 6. Erreferentziak https://youtu.be/kR2sm1zelI4 https://youtu.be/AiP2_icXpAk Hobetu zure Kotlin kodea Detekt-ekin Erresilientzia 4J Spring-Boot-Demo Netflix / Hystrix Kystrix - Hystrix-entzako Kotlin DSL bat johanhaleby / kystrix erresilientzia4j / erresilientzia4j Circuit Breaker - Resilience4j-circuitbreaker-ekin hastea Eskerrik asko! Espero dut artikulu hau egitea nik bezainbeste gustatu izana! Mesedez, utzi iritzia, iruzkinak edo edozein sare sozialetan eman nahi duzun iritzia beheko esteketan. Oso eskertuta nago artikulu hau hobetzen lagundu nahi badidazu. Aplikazio honen iturburu-kode guztia Eskerrik asko irakurtzeagatik! GitHub-en jarri dut.