„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Erstellen eines einfachen Load Balancers in Go

Erstellen eines einfachen Load Balancers in Go

Veröffentlicht am 05.11.2024
Durchsuche:898

Load Balancer sind in der modernen Softwareentwicklung von entscheidender Bedeutung. Wenn Sie sich jemals gefragt haben, wie Anfragen auf mehrere Server verteilt werden oder warum sich bestimmte Websites selbst bei hohem Datenverkehr schneller anfühlen, liegt die Antwort oft in einem effizienten Lastausgleich.

Building a simple load balancer in Go

In diesem Beitrag erstellen wir einen einfachen Anwendungs-Load-Balancer mit dem Round-Robin-Algorithmus in Go. Ziel dieses Beitrags ist es, Schritt für Schritt zu verstehen, wie ein Load Balancer unter der Haube funktioniert.

Was ist ein Load Balancer?

Ein Load Balancer ist ein System, das eingehenden Netzwerkverkehr auf mehrere Server verteilt. Dadurch wird sichergestellt, dass kein einzelner Server zu stark ausgelastet ist, wodurch Engpässe verhindert und das Benutzererlebnis insgesamt verbessert werden. Der Lastausgleichsansatz stellt außerdem sicher, dass bei Ausfall eines Servers der Datenverkehr automatisch auf einen anderen verfügbaren Server umgeleitet werden kann, wodurch die Auswirkungen des Ausfalls verringert und die Verfügbarkeit erhöht werden.

Warum verwenden wir Load Balancer?

  • Hohe Verfügbarkeit: Durch die Verteilung des Datenverkehrs stellen Load Balancer sicher, dass der Datenverkehr auch bei einem Serverausfall an andere fehlerfreie Server weitergeleitet werden kann, wodurch die Anwendung ausfallsicherer wird.
  • Skalierbarkeit: Mit Load Balancern können Sie Ihr System horizontal skalieren, indem Sie bei steigendem Datenverkehr weitere Server hinzufügen.
  • Effizienz: Es maximiert die Ressourcennutzung, indem sichergestellt wird, dass alle Server die Arbeitslast gleichmäßig teilen.

Lastausgleichsalgorithmen

Es gibt verschiedene Algorithmen und Strategien zur Verteilung des Traffics:

  • Round Robin: Eine der einfachsten verfügbaren Methoden. Es verteilt Anfragen sequentiell auf die verfügbaren Server. Sobald es den letzten Server erreicht, beginnt es erneut von vorne.
  • Gewichteter Round-Robin-Algorithmus: Ähnlich dem Round-Robin-Algorithmus, außer dass jedem Server eine feste numerische Gewichtung zugewiesen wird. Dieses gegebene Gewicht wird verwendet, um den Server für die Weiterleitung des Datenverkehrs zu bestimmen.
  • Kleinste Verbindungen: Leitet den Datenverkehr an den Server mit den wenigsten aktiven Verbindungen weiter.
  • IP-Hashing: Wählen Sie den Server basierend auf der IP-Adresse des Clients aus.

In diesem Beitrag konzentrieren wir uns auf die Implementierung eines Round Robin Load Balancers.

Was ist ein Round-Robin-Algorithmus?

Ein Round-Robin-Algorithmus sendet jede eingehende Anfrage kreisförmig an den nächsten verfügbaren Server. Wenn Server A die erste Anfrage bearbeitet, bearbeitet Server B die zweite und Server C die dritte. Sobald alle Server eine Anfrage erhalten haben, beginnt es erneut bei Server A.

Jetzt lasst uns in den Code springen und unseren Load Balancer erstellen!

Schritt 1: Definieren Sie den Load Balancer und den Server

type LoadBalancer struct {
    Current int
    Mutex   sync.Mutex
}

Wir definieren zunächst eine einfache LoadBalancer-Struktur mit einem Current-Feld, um zu verfolgen, welcher Server die nächste Anfrage bearbeiten soll. Der Mutex stellt sicher, dass unser Code sicher gleichzeitig verwendet werden kann.

Jeder Server, den wir auslasten, wird durch die Serverstruktur definiert:

type Server struct {
    URL       *url.URL
    IsHealthy bool
    Mutex     sync.Mutex
}

Hier hat jeder Server eine URL und ein IsHealthy-Flag, das angibt, ob der Server für die Bearbeitung von Anfragen verfügbar ist.

Schritt 2: Round-Robin-Algorithmus

Das Herzstück unseres Load Balancers ist der Round-Robin-Algorithmus. So funktioniert es:

func (lb *LoadBalancer) getNextServer(servers []*Server) *Server {
    lb.Mutex.Lock()
    defer lb.Mutex.Unlock()

    for i := 0; i 


  • Diese Methode durchläuft die Liste der Server im Round-Robin-Verfahren. Wenn der ausgewählte Server fehlerfrei ist, wird er zur Verarbeitung der eingehenden Anfrage an diesen Server zurückgegeben.
  • Wir verwenden Mutex, um sicherzustellen, dass jeweils nur eine Goroutine auf das aktuelle Feld des Load Balancers zugreifen und es ändern kann. Dadurch wird sichergestellt, dass der Round-Robin-Algorithmus ordnungsgemäß funktioniert, wenn mehrere Anforderungen gleichzeitig verarbeitet werden.
  • Jeder Server verfügt außerdem über einen eigenen Mutex. Wenn wir das Feld IsHealthy überprüfen, sperren wir den Mutex des Servers, um den gleichzeitigen Zugriff mehrerer Goroutinen zu verhindern.
  • Ohne Mutex-Sperre ist es möglich, dass eine andere Goroutine den Wert ändert, was zum Lesen falscher oder inkonsistenter Daten führen könnte.
  • Wir entsperren den Mutex, sobald wir das Current-Feld aktualisiert oder den IsHealthy-Feldwert gelesen haben, um den kritischen Abschnitt so klein wie möglich zu halten. Auf diese Weise verwenden wir Mutex, um jegliche Race-Bedingung zu vermeiden.

Schritt 3: Konfigurieren des Load Balancers

Unsere Konfiguration wird in einer config.json-Datei gespeichert, die die Server-URLs und Integritätsprüfungsintervalle enthält (mehr dazu im folgenden Abschnitt).

type Config struct {
    Port                string   `json:"port"`
    HealthCheckInterval string   `json:"healthCheckInterval"`
    Servers             []string `json:"servers"`
}

Die Konfigurationsdatei könnte so aussehen:

{
  "port": ":8080",
  "healthCheckInterval": "2s",
  "servers": [
    "http://localhost:5001",
    "http://localhost:5002",
    "http://localhost:5003",
    "http://localhost:5004",
    "http://localhost:5005"
  ]
}

Schritt 4: Gesundheitschecks

Wir möchten sicherstellen, dass die Server fehlerfrei sind, bevor wir eingehenden Datenverkehr an sie weiterleiten. Dies erfolgt durch das Senden regelmäßiger Gesundheitsprüfungen an jeden Server:

func healthCheck(s *Server, healthCheckInterval time.Duration) {
    for range time.Tick(healthCheckInterval) {
        res, err := http.Head(s.URL.String())
        s.Mutex.Lock()
        if err != nil || res.StatusCode != http.StatusOK {
            fmt.Printf("%s is down\n", s.URL)
            s.IsHealthy = false
        } else {
            s.IsHealthy = true
        }
        s.Mutex.Unlock()
    }
}

Alle paar Sekunden (wie in der Konfiguration angegeben) sendet der Load Balancer eine HEAD-Anfrage an jeden Server, um zu überprüfen, ob er fehlerfrei ist. Wenn ein Server ausfällt, wird das IsHealthy-Flag auf „false“ gesetzt, wodurch verhindert wird, dass künftiger Datenverkehr dorthin weitergeleitet wird.

Schritt 5: Reverse-Proxy

Wenn der Load Balancer eine Anfrage erhält, leitet er die Anfrage über einen Reverse-Proxy an den nächsten verfügbaren Server weiter. In Golang bietet das httputil-Paket eine integrierte Möglichkeit, Reverse-Proxying zu handhaben, und wir werden es in unserem Code über die ReverseProxy-Funktion verwenden:

func (s *Server) ReverseProxy() *httputil.ReverseProxy {
    return httputil.NewSingleHostReverseProxy(s.URL)
}
Was ist ein Reverse-Proxy?

Ein Reverse-Proxy ist ein Server, der zwischen einem Client und einem oder mehreren Backend-Servern sitzt. Es empfängt die Anfrage des Clients, leitet sie an einen der Backend-Server weiter und gibt dann die Antwort des Servers an den Client zurück. Der Client interagiert mit dem Proxy, ohne zu wissen, welcher Backend-Server die Anfrage bearbeitet.

In unserem Fall fungiert der Load Balancer als Reverse-Proxy, der vor mehreren Servern sitzt und eingehende HTTP-Anfragen auf diese verteilt.

Schritt 6: Bearbeitung von Anfragen

Wenn ein Client eine Anfrage an den Load Balancer stellt, wählt er mithilfe der Round-Robin-Algorithmus-Implementierung in der getNextServer-Funktion den nächsten verfügbaren fehlerfreien Server aus und leitet die Client-Anfrage an diesen Server weiter. Wenn kein fehlerfreier Server verfügbar ist, senden wir den Fehler „Dienst nicht verfügbar“ an den Client.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        server := lb.getNextServer(servers)
        if server == nil {
            http.Error(w, "No healthy server available", http.StatusServiceUnavailable)
            return
        }
        w.Header().Add("X-Forwarded-Server", server.URL.String())
        server.ReverseProxy().ServeHTTP(w, r)
    })

Die ReverseProxy-Methode leitet die Anfrage an den eigentlichen Server weiter, und wir fügen zu Debugging-Zwecken auch einen benutzerdefinierten Header „X-Forwarded-Server“ hinzu (in der Produktion sollten wir es jedoch vermeiden, interne Serverdetails wie diese offenzulegen).

Schritt 7: Starten des Load Balancers

Zuletzt starten wir den Load Balancer auf dem angegebenen Port:

log.Println("Starting load balancer on port", config.Port)
err = http.ListenAndServe(config.Port, nil)
if err != nil {
        log.Fatalf("Error starting load balancer: %s\n", err.Error())
}

Funktionierende Demo

TL;DR

In diesem Beitrag haben wir in Golang mithilfe eines Round-Robin-Algorithmus einen grundlegenden Load Balancer von Grund auf erstellt. Dies ist eine einfache, aber effektive Möglichkeit, den Datenverkehr auf mehrere Server zu verteilen und sicherzustellen, dass Ihr System höhere Lasten effizient bewältigen kann.

Es gibt noch viel mehr zu erkunden, z. B. das Hinzufügen ausgefeilter Integritätsprüfungen, die Implementierung verschiedener Lastausgleichsalgorithmen oder die Verbesserung der Fehlertoleranz. Aber dieses grundlegende Beispiel kann eine solide Grundlage sein, auf der man aufbauen kann.

Den Quellcode finden Sie in diesem GitHub-Repo.

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/vivekalhat/building-a-simple-load-balancer-in-go-70d?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3