Os balanceadores de carga são cruciais no desenvolvimento de software moderno. Se você já se perguntou como as solicitações são distribuídas entre vários servidores ou por que certos sites parecem mais rápidos mesmo durante tráfego intenso, a resposta geralmente está no balanceamento de carga eficiente.
Nesta postagem, construiremos um balanceador de carga de aplicativo simples usando o algoritmo Round Robin em Go. O objetivo desta postagem é entender como um balanceador de carga funciona nos bastidores, passo a passo.
Um balanceador de carga é um sistema que distribui o tráfego de rede de entrada em vários servidores. Ele garante que nenhum servidor suporte muita carga, evitando gargalos e melhorando a experiência geral do usuário. A abordagem de balanceamento de carga também garante que, se um servidor falhar, o tráfego poderá ser automaticamente redirecionado para outro servidor disponível, reduzindo assim o impacto da falha e aumentando a disponibilidade.
Existem diferentes algoritmos e estratégias para distribuir o tráfego:
Nesta postagem, vamos nos concentrar na implementação de um balanceador de carga Round Robin.
Um algoritmo round robin envia cada solicitação recebida para o próximo servidor disponível de maneira circular. Se o servidor A tratar a primeira solicitação, o servidor B tratará a segunda e o servidor C tratará a terceira. Depois que todos os servidores receberem uma solicitação, ela será reiniciada no servidor A.
Agora, vamos pular para o código e construir nosso balanceador de carga!
type LoadBalancer struct { Current int Mutex sync.Mutex }
Primeiro definiremos uma estrutura LoadBalancer simples com um campo Current para controlar qual servidor deve lidar com a próxima solicitação. O Mutex garante que nosso código seja seguro para uso simultâneo.
Cada servidor que balanceamos a carga é definido pela estrutura do servidor:
type Server struct { URL *url.URL IsHealthy bool Mutex sync.Mutex }
Aqui, cada servidor tem uma URL e um sinalizador IsHealthy, que indica se o servidor está disponível para lidar com solicitações.
O coração do nosso balanceador de carga é o algoritmo round robin. Veja como funciona:
func (lb *LoadBalancer) getNextServer(servers []*Server) *Server { lb.Mutex.Lock() defer lb.Mutex.Unlock() for i := 0; i
Nossa configuração é armazenada em um arquivo config.json, que contém os URLs do servidor e os intervalos de verificação de integridade (mais sobre isso na seção abaixo).
type Config struct { Port string `json:"port"` HealthCheckInterval string `json:"healthCheckInterval"` Servers []string `json:"servers"` }
O arquivo de configuração pode ter esta aparência:
{ "port": ":8080", "healthCheckInterval": "2s", "servers": [ "http://localhost:5001", "http://localhost:5002", "http://localhost:5003", "http://localhost:5004", "http://localhost:5005" ] }
Queremos ter certeza de que os servidores estão íntegros antes de rotear qualquer tráfego de entrada para eles. Isso é feito enviando verificações de integridade periódicas para cada servidor:
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() } }
A cada poucos segundos (conforme especificado na configuração), o balanceador de carga envia uma solicitação HEAD para cada servidor para verificar se ele está íntegro. Se um servidor estiver inativo, o sinalizador IsHealthy será definido como falso, evitando que tráfego futuro seja roteado para ele.
Quando o balanceador de carga recebe uma solicitação, ele encaminha a solicitação para o próximo servidor disponível usando um proxy reverso. Em Golang, o pacote httputil fornece uma maneira integrada de lidar com proxy reverso, e vamos usá-lo em nosso código por meio da função ReverseProxy:
func (s *Server) ReverseProxy() *httputil.ReverseProxy { return httputil.NewSingleHostReverseProxy(s.URL) }
Um proxy reverso é um servidor que fica entre um cliente e um ou mais servidores back-end. Ele recebe a solicitação do cliente, encaminha-a para um dos servidores back-end e, em seguida, retorna a resposta do servidor ao cliente. O cliente interage com o proxy, sem saber qual servidor back-end específico está lidando com a solicitação.
No nosso caso, o balanceador de carga atua como um proxy reverso, ficando na frente de vários servidores e distribuindo solicitações HTTP recebidas entre eles.
Quando um cliente faz uma solicitação ao balanceador de carga, ele seleciona o próximo servidor íntegro disponível usando a implementação do algoritmo round robin na função getNextServer e faz proxy da solicitação do cliente para esse servidor. Se nenhum servidor íntegro estiver disponível, enviaremos um erro de serviço indisponível ao cliente.
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) })
O método ReverseProxy faz proxy da solicitação para o servidor real e também adicionamos um cabeçalho personalizado X-Forwarded-Server para fins de depuração (embora na produção devamos evitar expor detalhes internos do servidor como este).
Finalmente, iniciamos o balanceador de carga na porta especificada:
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()) }
Nesta postagem, construímos um balanceador de carga básico do zero em Golang usando um algoritmo round robin. Esta é uma maneira simples, mas eficaz, de distribuir o tráfego entre vários servidores e garantir que seu sistema possa lidar com cargas mais altas com eficiência.
Há muito mais para explorar, como adicionar verificações de integridade sofisticadas, implementar diferentes algoritmos de balanceamento de carga ou melhorar a tolerância a falhas. Mas este exemplo básico pode ser uma base sólida para construir.
Você pode encontrar o código-fonte neste repositório GitHub.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3