Heim  >  Artikel  >  Backend-Entwicklung  >  Leistungsschalter in Go-Apps

Leistungsschalter in Go-Apps

王林
王林Original
2024-09-03 14:15:11977Durchsuche

Heutzutage ist es üblich, dass unsere Anwendungen einige Abhängigkeiten aufweisen, insbesondere wenn sie in einer Microservice-Umgebung arbeiten. Wenn unsere App Fehler meldet, kommt es nicht selten vor, dass wir feststellen, dass eine Abhängigkeit ausgefallen ist.

Eine gute Vorgehensweise zur Verbesserung unserer Widerstandsfähigkeit besteht darin, die Kommunikation mit Apps zu unterbrechen, die sich nicht gut verhalten. Als wir uns in anderen Bereichen umschauten, lernten wir das Konzept von Leistungsschaltern aus der Elektrotechnik kennen, bei denen ein Schalter ausschaltet, wenn ein Fehler auftritt. In Brasilien verfügen alle Häuser über diese Schalter, die sich automatisch abschalten, wenn unser Stromnetz instabil wird.

In der Informatik ist unser Leistungsschalter etwas komplexer, da er auch einen Zwischenzustand hat. Die folgende Zeichnung erklärt mehr über die Funktionsweise:

Circuit Breaker in Go apps

Kurz gesagt sind die möglichen Zustände:

  • offen: Es findet keine Kommunikation zwischen Apps statt. Wenn dieser Zustand erreicht wird, startet ein Timer, der es der Abhängigkeit ermöglicht, sich selbst wiederherzustellen. Wenn der Timer abgelaufen ist, gehen wir zur Halböffnung über.
  • geschlossen: Es findet eine Kommunikation zwischen Apps statt. Bei jeder fehlgeschlagenen Anfrage wird ein Zähler aktualisiert. Wenn wir die Fehlerschwelle erreichen, bewegen wir den Stromkreis auf Öffnen.
  • halboffen: Es ist ein Heilungszustand, bis wir wie gewohnt arbeiten können. Wenn wir dabei die Erfolgsschwelle erreichen, wechseln wir zu „Geschlossen“. Wenn die Anfragen weiterhin fehlschlagen, kehren wir zum Öffnen zurück.

Ziemlich cool, oder? Um das Konzept besser zu erklären, warum erstellen Sie nicht eines?

Erstens bauen wir unseren Dienst A auf. Er wird für den Empfang aller Anfragen verantwortlich sein, mit anderen Worten, es wird der Dienst sein, von dem unsere Haupt-App abhängt. Zur Vereinfachung stellen wir zwei Endpunkte bereit: einen /success, der immer mit 200 antwortet, und einen /failure, der immer mit 500 antwortet.

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/success", func(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusOK) })
    http.HandleFunc("/failure", func(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusInternalServerError) })

    fmt.Println("Server is running at http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Unser Service B wird für den Anruf von Service A verantwortlich sein und unseren Leistungsschalter bauen. Die Go-Community verfügt bereits über den lib gobreaker, der das Muster bereits implementiert. Zunächst definieren wir unsere Breaker-Eigenschaften:

var st gobreaker.Settings
st.Name = "Circuit Breaker PoC"
st.Timeout = time.Second * 5
st.MaxRequests = 2
st.ReadyToTrip = func(counts gobreaker.Counts) bool {
    return counts.ConsecutiveFailures >= 1
}

Obwohl uns die Bibliothek die Anpassung weiterer Eigenschaften ermöglicht, konzentrieren wir uns auf nur drei:

  • Timeout: wie lange es im geöffneten Zustand bleiben wird. In diesem Beispiel wählen wir fünf Sekunden.
  • MaxRequests: Wie viele erfolgreiche Anfragen, bevor es geschlossen wird. In diesem Beispiel haben wir uns für zwei Anfragen entschieden.
  • ReadyToTrip: Definiert die Bedingung für den Übergang von geschlossen nach offen. Vereinfacht gesagt reicht ein Fehler aus.

Jetzt initialisieren wir einfach den Breaker und senden die Anfragen:

cb := gobreaker.NewCircuitBreaker[int](st)

url := "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // closed!

url = "http://localhost:8080/failure"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // open!

time.Sleep(time.Second * 6)
url = "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // half-open!

url = "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // closed!

Wir können feststellen, dass Gobreaker wie ein Wrapper um eine Funktion funktioniert. Wenn die Funktion einen Fehler zurückgibt, erhöht sie den Fehlerzähler, andernfalls erhöht sie den Erfolgszähler. Definieren wir diese Funktion:

func Get(url string) (int, error) {
    r, _ := http.Get(url)

    if r.StatusCode != http.StatusOK {
        return r.StatusCode, fmt.Errorf("failed to get %s", url)
    }

    return r.StatusCode, nil
}

Und so können wir eine Go-App mit Schutzschalter haben! Wenn Sie dieses Muster verwenden, können Sie die Ausfallsicherheit Ihrer App erhöhen, indem Sie sie toleranter gegenüber Fehlern aus Ihren Abhängigkeiten machen. Außerdem wurde durch die Verwendung dieser Bibliothek ein Großteil der Komplexität beseitigt, wodurch es einfacher wurde, das Muster in unsere alltäglichen Apps zu übernehmen. Wenn Sie den Code dieses Proof of Concept sehen möchten, sehen Sie ihn sich hier an.

Wenn Sie immer noch neugierig auf andere Resilienzmuster sind: Elton Minetto hat auch einen tollen Blogbeitrag darüber veröffentlicht!

Sie können diesen und andere Beiträge auch auf meinem persönlichen Blog lesen. Sagen Sie mir in den Kommentaren, was Sie von diesem Blogbeitrag halten, und stellen Sie mir eine Frage: Haben Sie schon einmal Leistungsschalter verwendet?

Das obige ist der detaillierte Inhalt vonLeistungsschalter in Go-Apps. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn