mønster: Circuit Breaker
kontekst
du har anvendt Microservice-arkitekturen.Tjenester samarbejder undertiden, når de håndterer anmodninger.Når en tjeneste synkront påberåber sig en anden, er der altid muligheden for, at den anden tjeneste ikke er tilgængelig eller udviser en så høj latenstid, at den i det væsentlige er ubrugelig.Dyrebare ressourcer såsom tråde kan forbruges i den, der ringer op, mens de venter på, at den anden tjeneste reagerer.Dette kan føre til ressourceudmattelse, hvilket ville gøre den kaldende tjeneste ude af stand til at håndtere andre anmodninger.Fejlen i en tjeneste kan potentielt kaskade til andre tjenester i hele applikationen.
Problem
Sådan forhindres et netværks-eller servicefejl i at kaskade til andre tjenester?
løsning
en serviceklient skal påberåbe sig en fjerntjeneste via en fuldmagt, der fungerer på samme måde som en elektrisk afbryder.Når antallet af på hinanden følgende fejl krydser en tærskel, Afbryder afbryderen, og i løbet af en timeout-periode mislykkes alle forsøg på at påberåbe sig fjerntjenesten med det samme.Når timeout udløber, tillader afbryderen et begrænset antal testanmodninger at passere igennem.Hvis disse anmodninger lykkes Afbryder genoptager normal drift.Ellers, hvis der er en fejl, begynder timeoutperioden igen.
eksempel
RegistrationServiceProxy
Fra applikationen Microservices eksempel er et eksempel på en komponent, der er skrevet i Scala, der bruger en afbryder til at håndtere fejl, når der påberåbes en fjerntjeneste.
@Componentclass RegistrationServiceProxy @Autowired()(restTemplate: RestTemplate) extends RegistrationService { @Value("${user_registration_url}") var userRegistrationUrl: String = _ @HystrixCommand(commandProperties=Array(new HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="800"))) override def registerUser(emailAddress: String, password: String): Either = { try { val response = restTemplate.postForEntity(userRegistrationUrl, RegistrationBackendRequest(emailAddress, password), classOf) response.getStatusCode match { case HttpStatus.OK => Right(response.getBody.id) } } catch { case e: HttpClientErrorException if e.getStatusCode == HttpStatus.CONFLICT => Left(DuplicateRegistrationError) } }}
@HystrixCommand
sørger for, at opkald til registerUser()
udføres ved hjælp af en afbryder.
afbryderfunktionaliteten er aktiveret ved hjælp af @EnableCircuitBreaker
annotationen på UserRegistrationConfiguration
klassen.
@EnableCircuitBreakerclass UserRegistrationConfiguration {
resulterende kontekst
dette mønster har følgende fordele:
- tjenester håndterer fejlen i de tjenester, de påberåber sig
dette mønster har følgende problemer:
- det er udfordrende at vælge timeout-værdier uden at skabe falske positive eller indføre overdreven latenstid.
- Microservice-chassiset implementerer muligvis dette mønster
- en API-Port bruger dette mønster til at påberåbe sig tjenester
- en opdagelsesrouter på serversiden bruger muligvis dette mønster til at påberåbe sig tjenester