Sling Academy
Home/Golang/Load Balancing HTTP Servers in Go

Load Balancing HTTP Servers in Go

Last updated: November 27, 2024

Load balancing is a crucial strategy for distributing network traffic across multiple servers to ensure availability and reliability. By spreading the load, you can avoid overloading a single server, which helps in improving response times and ensures no single server becomes a point of failure.

Setting Up a Simple Load Balancer in Go

In Go, we can create a simple HTTP load balancer using the net/http package. Here, we will demonstrate steps to write a basic load balancer that distributes HTTP requests across an array of backend servers.

Step 1: Import the Necessary Packages

To get started, you need to import certain Go packages. Here's how you can do this:

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "sync/atomic"
)

Step 2: Define the Server Pool

A pool of backend servers is necessary for load balancing. We will use a slice to store URLs of our servers.

type ServerPool struct {
    servers []*url.URL
    current uint32
}

Step 3: Add Servers to the Pool

We write a method to add multiple servers to the load balancer pool. These servers will handle the traffic once the load balancer is up and running.

func (s *ServerPool) addServer(server *url.URL) {
    s.servers = append(s.servers, server)
}

Step 4: Implement Round-Robin Selection

Load balancers often distribute requests using a round-robin scheduling technique. Let's implement this for our server pool:

func (s *ServerPool) getNextServer() *url.URL {
    next := atomic.AddUint32(&s.current, 1)
    return s.servers[(int(next)-1)%len(s.servers)]
}

Step 5: Proxy Method for Forwarding Requests

The load balancer should forward the client's request to an appropriate backend server. We do this using HTTP reverse proxies in Go.

func (s *ServerPool) proxy(w http.ResponseWriter, r *http.Request) {
    serverURL := s.getNextServer()
    proxy := httputil.NewSingleHostReverseProxy(serverURL)
    r.Host = serverURL.Host
    proxy.ServeHTTP(w, r)
}

Step 6: Initialize and Start the HTTP Server

Finally, we instantiate our server pool, add backend servers, and start listening for incoming HTTP requests to distribute across the pool.

func main() {
    servers := []string{
        "http://localhost:8081",
        "http://localhost:8082",
    }

    var serverPool ServerPool
    for _, server := range servers {
        url, err := url.Parse(server)
        if err != nil {
            log.Fatal("Failed to parse server URL", err)
        }
        serverPool.addServer(url)
    }

    handler := func(w http.ResponseWriter, r *http.Request) {
        serverPool.proxy(w, r)
    }

    http.HandleFunc("/", handler)

    log.Print("Starting load balancer at port 8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal("Failed to start server", err)
    }
}

Conclusion

This simple implementation illustrates a basic HTTP load balancer using Go. It handles load distribution using the round-robin method, which can be replaced with more sophisticated algorithms or rule-based strategies as required.

Next Article: Using TLS and Certificates for Secure Networking in Go

Previous Article: Handling Concurrent Requests in Go Servers

Series: Networking and Server

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant