Muster: Leistungsschalter

Kontext

Sie haben die Microservice-Architektur angewendet.Dienste arbeiten manchmal bei der Bearbeitung von Anfragen zusammen.Wenn ein Dienst synchron einen anderen aufruft, besteht immer die Möglichkeit, dass der andere Dienst nicht verfügbar ist oder eine so hohe Latenz aufweist, dass er im Wesentlichen unbrauchbar ist.Wertvolle Ressourcen wie Threads können im Aufrufer verbraucht werden, während auf die Antwort des anderen Dienstes gewartet wird.Dies kann zu einer Erschöpfung der Ressourcen führen, wodurch der aufrufende Dienst andere Anforderungen nicht verarbeiten kann.Der Ausfall eines Dienstes kann möglicherweise zu anderen Diensten in der gesamten Anwendung führen.

Problem

Wie kann verhindert werden, dass ein Netzwerk- oder Dienstfehler zu anderen Diensten kaskadiert?

Lösung

Ein Dienstclient sollte einen Remote-Dienst über einen Proxy aufrufen, der ähnlich wie ein elektrischer Leistungsschalter funktioniert.Wenn die Anzahl der aufeinanderfolgenden Fehler einen Schwellenwert überschreitet, wird der Leistungsschalter ausgelöst, und für die Dauer eines Zeitlimits schlagen alle Versuche, den Remotedienst aufzurufen, sofort fehl.Nach Ablauf des Zeitlimits lässt der Leistungsschalter eine begrenzte Anzahl von Testanforderungen durchlaufen.Wenn diese Anforderungen erfolgreich sind, nimmt der Leistungsschalter den normalen Betrieb wieder auf.Andernfalls beginnt die Timeout-Periode erneut, wenn ein Fehler auftritt.

Beispiel

RegistrationServiceProxy Aus der Microservices-Beispielanwendung ist ein Beispiel für eine in Scala geschriebene Komponente, die einen Leistungsschalter verwendet, um Fehler beim Aufrufen eines Remotedienstes zu behandeln.

@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) } }}

Der @HystrixCommand sorgt dafür, dass Aufrufe an registerUser() unter Verwendung eines Leistungsschalters ausgeführt werden.

Die Schutzschalterfunktionalität wird mit der Annotation @EnableCircuitBreaker in der Klasse UserRegistrationConfiguration aktiviert.

@EnableCircuitBreakerclass UserRegistrationConfiguration {

Resultierender Kontext

Dieses Muster hat die folgenden Vorteile:

  • Dienste behandeln den Ausfall der von ihnen aufgerufenen Dienste

Dieses Muster weist die folgenden Probleme auf:

  • Es ist schwierig, Timeout-Werte zu wählen, ohne Fehlalarme zu erzeugen oder übermäßige Latenzzeiten einzuführen.
  • Das Microservice-Chassis implementiert möglicherweise dieses Muster
  • Ein API-Gateway verwendet dieses Muster zum Aufrufen von Diensten
  • Ein serverseitiger Discovery-Router verwendet dieses Muster möglicherweise zum Aufrufen von Diensten

Siehe auch

  • Netflix Hystrix ist ein Beispiel für eine Bibliothek, die dieses Muster implementiert

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.