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.
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.
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.
Es gibt verschiedene Algorithmen und Strategien zur Verteilung des Traffics:
In diesem Beitrag konzentrieren wir uns auf die Implementierung eines Round Robin Load Balancers.
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!
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.
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
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" ] }
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.
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) }
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.
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).
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()) }
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.
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