Implementing Nginx Round‑Robin and Weighted‑Round‑Robin Load Balancing in Go
This article explains how Nginx performs round‑robin and weighted‑round‑robin load balancing, shows the underlying algorithms, and provides complete Go implementations with configuration examples, code snippets, and test outputs for both basic and weighted scenarios.
1. Nginx Load Balancing – Round Robin
Before discussing weighted round‑robin, a brief overview of the basic round‑robin algorithm is given. It simply cycles through a list of N servers, selecting each one in turn for every incoming request.
Configuration example
upstream cluster {
server 192.168.0.14;
server 192.168.0.15;
}
location / {
proxy_set_header X-Real-IP $remote_addr; // return real IP
proxy_pass http://cluster; // proxy to cluster
}Characteristics
Round‑robin distributes requests evenly when all servers have similar performance. If server capacities differ, the algorithm can cause overload on weaker nodes and under‑utilisation of stronger ones.
Go implementation of round‑robin
type RoundRobinBalance struct {
curIndex int
rss []string
}
func (r *RoundRobinBalance) Add(params ...string) error {
if len(params) == 0 {
return errors.New("params len at least 1")
}
addr := params[0]
r.rss = append(r.rss, addr)
return nil
}
func (r *RoundRobinBalance) Next() string {
if len(r.rss) == 0 {
return ""
}
lens := len(r.rss)
if r.curIndex >= lens {
r.curIndex = 0
}
curAdd := r.rss[r.curIndex]
r.curIndex = (r.curIndex + 1) % lens
return curAdd
}Test
func main() {
rb := new(RoundRobinBalance)
rb.Add("127.0.0.1:80")
rb.Add("127.0.0.1:81")
rb.Add("127.0.0.1:82")
rb.Add("127.0.0.1:83")
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
}Running the program yields the sequence: 127.0.0.1:80, 127.0.0.1:81, 127.0.0.1:82, 127.0.0.1:83, 127.0.0.1:80, 127.0.0.1:81.
2. Nginx Load Balancing – Weighted Round Robin
When server capacities differ, weighted round‑robin assigns a weight to each server so that the number of requests a server receives is proportional to its weight.
Configuration example
http {
upstream cluster {
server 192.168.1.2 weight=5;
server 192.168.1.3 weight=3;
server 192.168.1.4 weight=1;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://cluster;
}
}Algorithm description
Weight : the static weight configured for each node.
currentWeight : the node's current weight, updated on each selection.
effectiveWeight : starts equal to Weight ; it is decreased when a node fails and increased when it succeeds, enabling dynamic weight adjustment.
The algorithm works as follows:
Calculate totalWeight as the sum of all nodes' effectiveWeight .
For each node, add its effectiveWeight to its currentWeight and select the node with the highest currentWeight .
Subtract totalWeight from the selected node's currentWeight .
Go implementation of weighted round‑robin
type WeightRoundRobinBalance struct {
curIndex int
rss []*WeightNode
}
type WeightNode struct {
weight int // configured weight
currentWeight int // changes over time
effectiveWeight int // may be adjusted on failures
addr string
}
func (r *WeightRoundRobinBalance) Add(params ...string) error {
if len(params) != 2 {
return errors.New("params len need 2")
}
addr := params[0]
w, err := strconv.ParseInt(params[1], 10, 64)
if err != nil {
return err
}
node := &WeightNode{
weight: int(w),
effectiveWeight: int(w),
currentWeight: int(w),
addr: addr,
}
r.rss = append(r.rss, node)
return nil
}
func (r *WeightRoundRobinBalance) Next() string {
if len(r.rss) == 0 {
return ""
}
totalWeight := 0
var maxNode *WeightNode
for i, node := range r.rss {
totalWeight += node.effectiveWeight
node.currentWeight += node.effectiveWeight
if maxNode == nil || node.currentWeight > maxNode.currentWeight {
maxNode = node
r.curIndex = i
}
}
maxNode.currentWeight -= totalWeight
return maxNode.addr
}Test
func main() {
rb := new(WeightRoundRobinBalance)
rb.Add("127.0.0.1:80", "4")
rb.Add("127.0.0.1:81", "2")
rb.Add("127.0.0.1:82", "1")
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
fmt.Println(rb.Next())
}Running the program produces a request distribution that respects the configured weights (4:2:1), demonstrating how weighted round‑robin balances load proportionally.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
