Les équilibreurs de charge sont cruciaux dans le développement de logiciels modernes. Si vous vous êtes déjà demandé comment les requêtes sont réparties sur plusieurs serveurs, ou pourquoi certains sites Web semblent plus rapides même en cas de trafic intense, la réponse réside souvent dans un équilibrage de charge efficace.
Dans cet article, nous allons créer un équilibreur de charge d'application simple à l'aide de l'algorithme Round Robin dans Go. Le but de cet article est de comprendre comment fonctionne un équilibreur de charge sous le capot, étape par étape.
Un équilibreur de charge est un système qui répartit le trafic réseau entrant sur plusieurs serveurs. Il garantit qu'aucun serveur ne supporte trop de charge, évitant ainsi les goulots d'étranglement et améliorant l'expérience utilisateur globale. L'approche d'équilibrage de charge garantit également qu'en cas de panne d'un serveur, le trafic peut être automatiquement redirigé vers un autre serveur disponible, réduisant ainsi l'impact de la panne et augmentant la disponibilité.
Il existe différents algorithmes et stratégies pour répartir le trafic :
Dans cet article, nous nous concentrerons sur la mise en œuvre d'un équilibreur de charge Round Robin.
Un algorithme round robin envoie chaque requête entrante au prochain serveur disponible de manière circulaire. Si le serveur A gère la première requête, le serveur B gérera la seconde et le serveur C gérera la troisième. Une fois que tous les serveurs ont reçu une requête, celle-ci redémarre depuis le serveur A.
Maintenant, passons au code et construisons notre équilibreur de charge !
type LoadBalancer struct { Current int Mutex sync.Mutex }
Nous allons d'abord définir une structure LoadBalancer simple avec un champ Current pour savoir quel serveur doit gérer la prochaine requête. Le Mutex garantit que notre code peut être utilisé simultanément en toute sécurité.
Chaque serveur que nous équilibrons est défini par la structure Server :
type Server struct { URL *url.URL IsHealthy bool Mutex sync.Mutex }
Ici, chaque serveur a une URL et un indicateur IsHealthy, qui indique si le serveur est disponible pour traiter les requêtes.
Le cœur de notre équilibreur de charge est l'algorithme round robin. Voici comment cela fonctionne :
func (lb *LoadBalancer) getNextServer(servers []*Server) *Server { lb.Mutex.Lock() defer lb.Mutex.Unlock() for i := 0; i
Notre configuration est stockée dans un fichier config.json, qui contient les URL du serveur et les intervalles de vérification de l'état (plus d'informations dans la section ci-dessous).
type Config struct { Port string `json:"port"` HealthCheckInterval string `json:"healthCheckInterval"` Servers []string `json:"servers"` }
Le fichier de configuration pourrait ressembler à ceci :
{ "port": ":8080", "healthCheckInterval": "2s", "servers": [ "http://localhost:5001", "http://localhost:5002", "http://localhost:5003", "http://localhost:5004", "http://localhost:5005" ] }
Nous voulons nous assurer que les serveurs sont sains avant de leur acheminer tout trafic entrant. Cela se fait en envoyant des contrôles de santé périodiques à chaque serveur :
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() } }
Toutes les quelques secondes (comme spécifié dans la configuration), l'équilibreur de charge envoie une requête HEAD à chaque serveur pour vérifier s'il est sain. Si un serveur est en panne, l'indicateur IsHealthy est défini sur false, empêchant ainsi le trafic futur d'y être acheminé.
Lorsque l'équilibreur de charge reçoit une requête, il la transmet au prochain serveur disponible à l'aide d'un proxy inverse. Dans Golang, le package httputil fournit un moyen intégré de gérer le proxy inverse, et nous l'utiliserons dans notre code via la fonction ReverseProxy :
func (s *Server) ReverseProxy() *httputil.ReverseProxy { return httputil.NewSingleHostReverseProxy(s.URL) }
Un proxy inverse est un serveur situé entre un client et un ou plusieurs serveurs backend. Il reçoit la demande du client, la transmet à l'un des serveurs principaux, puis renvoie la réponse du serveur au client. Le client interagit avec le proxy, ignorant quel serveur principal spécifique gère la demande.
Dans notre cas, l'équilibreur de charge agit comme un proxy inverse, assis devant plusieurs serveurs et distribuant les requêtes HTTP entrantes entre eux.
Lorsqu'un client envoie une requête à l'équilibreur de charge, il sélectionne le prochain serveur sain disponible à l'aide de l'implémentation de l'algorithme round robin dans la fonction getNextServer et transmet la requête du client à ce serveur. Si aucun serveur sain n'est disponible, nous envoyons une erreur de service indisponible au 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) })
La méthode ReverseProxy transmet la requête au serveur réel, et nous ajoutons également un en-tête personnalisé X-Forwarded-Server à des fins de débogage (bien qu'en production, nous devrions éviter d'exposer les détails internes du serveur comme celui-ci).
Enfin, nous démarrons l'équilibreur de charge sur le port spécifié :
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()) }
Dans cet article, nous avons construit un équilibreur de charge de base à partir de zéro dans Golang en utilisant un algorithme round robin. Il s'agit d'un moyen simple mais efficace de répartir le trafic sur plusieurs serveurs et de garantir que votre système peut gérer efficacement des charges plus élevées.
Il y a beaucoup plus à explorer, comme l'ajout de contrôles de santé sophistiqués, la mise en œuvre de différents algorithmes d'équilibrage de charge ou l'amélioration de la tolérance aux pannes. Mais cet exemple de base peut constituer une base solide sur laquelle s’appuyer.
Vous pouvez trouver le code source dans ce dépôt GitHub.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3