Крошечный балансировщик нагрузки ⚖️
В этом балансировщике нагрузки мы определяем часть внутренних серверов и используем генератор случайных чисел для выбора сервера для каждого входящего запроса. Затем мы используем пакет Go httputil.ReverseProxy для проксирования запроса на выбранный внутренний сервер.
Обратите внимание, что мы используем sync.Mutex для защиты доступа к общему фрагменту внутренних серверов. Это необходимо для предотвращения состояния гонки при одновременной обработке нескольких запросов.
Также обратите внимание, что мы используем вызов time.Sleep() для имитации некоторой работы, выполняемой внутренними серверами.
package main import ( "fmt" "math/rand" "net/http" "time" ) // Define a slice of backend servers var servers = []string{ "http://localhost:8001", "http://localhost:8002", "http://localhost:8003", } func main() { // Create a new HTTP server server := http.Server{ Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Choose a random backend server rand.Seed(time.Now().UnixNano()) backend := servers[rand.Intn(len(servers))] // Proxy the request to the backend server fmt.Printf("Proxying request to %s\n", backend) proxy := NewSingleHostReverseProxy(backend) proxy.ServeHTTP(w, r) }), } // Start the server fmt.Println("Starting load balancer on port 8080") server.ListenAndServe() } // A simple reverse proxy that only proxies requests to a single host func NewSingleHostReverseProxy(target string) *httputil.ReverseProxy { targetURL, _ := url.Parse(target) return &httputil.ReverseProxy{Director: func(req *http.Request) { req.URL.Scheme = targetURL.Scheme req.URL.Host = targetURL.Host req.URL.Path = singleJoiningSlash(targetURL.Path, req.URL.Path) req.Host = targetURL.Host }} } func singleJoiningSlash(a, b string) string { aslash := strings.HasSuffix(a, "/") bslash := strings.HasPrefix(b, "/") switch { case aslash && bslash: return a + b[1:] case !aslash && !bslash: return a + "/" + b } return a + b }
мы можем использовать горутины в коде балансировщика нагрузки для одновременной обработки входящих запросов и улучшения масштабируемости балансировщика нагрузки и повышения производительности балансировщика нагрузки.
Вот обновленная версия кода балансировщика нагрузки, который использует горутины для обработки входящих запросов:
package main import ( "fmt" "math/rand" "net/http" "net/http/httputil" "net/url" "strings" "sync" "time" ) // Define a slice of backend servers var servers = []string{ "http://localhost:8001", "http://localhost:8002", "http://localhost:8003", } // Define a mutex to protect access to the shared slice of servers var mutex = &sync.Mutex{} func main() { // Create a new HTTP server server := http.Server{ Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Use a goroutine to handle each incoming request concurrently go func() { // Choose a random backend server backend := chooseBackendServer() // Proxy the request to the backend server fmt.Printf("Proxying request to %s\n", backend) proxy := NewSingleHostReverseProxy(backend) proxy.ServeHTTP(w, r) }() }), } // Start the server fmt.Println("Starting load balancer on port 8080") server.ListenAndServe() } // A simple function that chooses a random backend server from the slice func chooseBackendServer() string { mutex.Lock() defer mutex.Unlock() rand.Seed(time.Now().UnixNano()) return servers[rand.Intn(len(servers))] } // A simple reverse proxy that only proxies requests to a single host func NewSingleHostReverseProxy(target string) *httputil.ReverseProxy { targetURL, _ := url.Parse(target) return &httputil.ReverseProxy{Director: func(req *http.Request) { req.URL.Scheme = targetURL.Scheme req.URL.Host = targetURL.Host req.URL.Path = singleJoiningSlash(targetURL.Path, req.URL.Path) req.Host = targetURL.Host }} } func singleJoiningSlash(a, b string) string { aslash := strings.HasSuffix(a, "/") bslash := strings.HasPrefix(b, "/") switch { case aslash && bslash: return a + b[1:] case !aslash && !bslash: return a + "/" + b } return a + b }
В реальном балансировщике нагрузки вы бы заменили это фактической работой, выполняемой серверами.
Надеюсь, вам понравилось читать эту статью.