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.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Implementing Nginx Round‑Robin and Weighted‑Round‑Robin Load Balancing in Go

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendGolangRound RobinWeighted Round Robin
MaGe Linux Operations
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.