Pengimbang beban adalah penting dalam pembangunan perisian moden. Jika anda pernah tertanya-tanya bagaimana permintaan diedarkan merentasi berbilang pelayan atau sebab tapak web tertentu berasa lebih pantas walaupun semasa trafik padat, jawapannya selalunya terletak pada pengimbangan beban yang cekap.
Dalam siaran ini, kami akan membina pengimbang beban aplikasi mudah menggunakan algoritma Round Robin dalam Go. Matlamat siaran ini adalah untuk memahami cara pengimbang beban berfungsi di bawah hud, langkah demi langkah.
Pengimbang beban ialah sistem yang mengagihkan trafik rangkaian masuk merentas berbilang pelayan. Ia memastikan bahawa tiada pelayan tunggal menanggung beban yang terlalu banyak, menghalang kesesakan dan meningkatkan keseluruhan pengalaman pengguna. Pendekatan pengimbangan beban juga memastikan bahawa jika satu pelayan gagal, maka trafik boleh dialihkan semula secara automatik ke pelayan lain yang tersedia, sekali gus mengurangkan kesan kegagalan dan meningkatkan ketersediaan.
Terdapat algoritma dan strategi yang berbeza untuk mengagihkan trafik:
Dalam siaran ini, kami akan menumpukan pada pelaksanaan Round Robin pengimbang beban.
Algoritma round robin menghantar setiap permintaan masuk ke pelayan tersedia seterusnya secara bulat. Jika pelayan A mengendalikan permintaan pertama, pelayan B akan mengendalikan permintaan kedua, dan pelayan C akan mengendalikan permintaan ketiga. Setelah semua pelayan menerima permintaan, ia bermula semula dari pelayan A.
Sekarang, mari beralih ke kod dan bina pengimbang beban kami!
type LoadBalancer struct { Current int Mutex sync.Mutex }
Kami mula-mula akan mentakrifkan struct LoadBalancer yang mudah dengan medan Semasa untuk menjejaki pelayan mana yang harus mengendalikan permintaan seterusnya. Mutex memastikan kod kami selamat digunakan serentak.
Setiap pelayan yang kami muatkan baki ditentukan oleh struct Pelayan:
type Server struct { URL *url.URL IsHealthy bool Mutex sync.Mutex }
Di sini, setiap pelayan mempunyai URL dan bendera IsHealthy, yang menunjukkan sama ada pelayan tersedia untuk mengendalikan permintaan.
Inti pengimbang beban kami ialah algoritma round robin. Begini caranya:
func (lb *LoadBalancer) getNextServer(servers []*Server) *Server { lb.Mutex.Lock() defer lb.Mutex.Unlock() for i := 0; i < len(servers); i++ { idx := lb.Current % len(servers) nextServer := servers[idx] lb.Current++ nextServer.Mutex.Lock() isHealthy := nextServer.IsHealthy nextServer.Mutex.Unlock() if isHealthy { return nextServer } } return nil }
Konfigurasi kami disimpan dalam fail config.json, yang mengandungi URL pelayan dan selang semakan kesihatan (lebih lanjut mengenainya di bahagian bawah).
type Config struct { Port string `json:"port"` HealthCheckInterval string `json:"healthCheckInterval"` Servers []string `json:"servers"` }
Fail konfigurasi mungkin kelihatan seperti ini:
{ "port": ":8080", "healthCheckInterval": "2s", "servers": [ "http://localhost:5001", "http://localhost:5002", "http://localhost:5003", "http://localhost:5004", "http://localhost:5005" ] }
We want to make sure that the servers are healthy before routing any incoming traffic to them. This is done by sending periodic health checks to each 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() } }
Every few seconds (as specified in the config), the load balancer sends a HEAD request to each server to check if it is healthy. If a server is down, the IsHealthy flag is set to false, preventing future traffic from being routed to it.
When the load balancer receives a request, it forwards the request to the next available server using a reverse proxy. In Golang, the httputil package provides a built-in way to handle reverse proxying, and we will use it in our code through the ReverseProxy function:
func (s *Server) ReverseProxy() *httputil.ReverseProxy { return httputil.NewSingleHostReverseProxy(s.URL) }
A reverse proxy is a server that sits between a client and one or more backend severs. It receives the client's request, forwards it to one of the backend servers, and then returns the server's response to the client. The client interacts with the proxy, unaware of which specific backend server is handling the request.
In our case, the load balancer acts as a reverse proxy, sitting in front of multiple servers and distributing incoming HTTP requests across them.
When a client makes a request to the load balancer, it selects the next available healthy server using the round robin algorithm implementation in getNextServer function and proxies the client request to that server. If no healthy server is available then we send service unavailable error to the 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) })
The ReverseProxy method proxies the request to the actual server, and we also add a custom header X-Forwarded-Server for debugging purposes (though in production, we should avoid exposing internal server details like this).
Finally, we start the load balancer on the specified 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 this post, we built a basic load balancer from scratch in Golang using a round robin algorithm. This is a simple yet effective way to distribute traffic across multiple servers and ensure that your system can handle higher loads efficiently.
There's a lot more to explore, such as adding sophisticated health checks, implementing different load balancing algorithms, or improving fault tolerance. But this basic example can be a solid foundation to build upon.
You can find the source code in this GitHub repo.
Atas ialah kandungan terperinci Membina pengimbang beban mudah dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!