Load Balancer Strategy
Suppose you are implementing the load balancing strategy for a nginx-liked web server. Given a list of ip [1, 2, 3], return the next round-robined result.
Basic Version
At the first glance, we can use a counter to track the number of the next ip.
package main
import "fmt"
func main() {
ips := []int{1, 2, 3}
lb := NewLB(ips)
for i := 0; i < 10; i++ {
fmt.Printf("%v\n", lb.Next())
}
}
type LB struct {
ips []int
count int
size int
}
func NewLB(ips []int) *LB {
return &LB{
ips: ips,
count: 0,
size: len(ips),
}
}
func (lb *LB) Next() int {
lb.count += 1
lb.count %= lb.size
return lb.ips[lb.count]
}
func (lb *LB) Next1() int {
lb.count += 1
if lb.count == lb.size {
lb.count = 0
}
return lb.ips[lb.count]
}
package main
import (
"fmt"
"sync"
)
func main() {
ips := []int{1, 2, 3}
lb := NewLB(ips)
wg := &sync.WaitGroup{}
for j := 0; j < 3; j++ {
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
fmt.Printf("%v\n", lb.Next())
}
wg.Done()
}()
}
wg.Wait()
}
type LB struct {
ips []int
count int
size int
m *sync.Mutex
}
func NewLB(ips []int) *LB {
return &LB{
ips: ips,
count: 0,
size: len(ips),
m: &sync.Mutex{},
}
}
func (lb *LB) Next() int {
lb.m.Lock()
defer lb.m.Unlock()
lb.count += 1
if lb.count == lb.size {
lb.count = 0
}
return lb.ips[lb.count]
}
Concurrency Version
We could use a mutex lock to protect the counter.
package main
import (
"fmt"
"sync"
)
func main() {
ips := []int{1, 2, 3}
lb := NewLB(ips)
wg := &sync.WaitGroup{}
for j := 0; j < 3; j++ {
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
fmt.Printf("%v\n", lb.Next())
}
wg.Done()
}()
}
wg.Wait()
}
type LB struct {
ips []int
count int
size int
m *sync.Mutex
}
func NewLB(ips []int) *LB {
return &LB{
ips: ips,
count: 0,
size: len(ips),
m: &sync.Mutex{},
}
}
func (lb *LB) Next() int {
lb.m.Lock()
defer lb.m.Unlock()
lb.count += 1
if lb.count == lb.size {
lb.count = 0
}
return lb.ips[lb.count]
}
Grouped Ips
Follow-Up: Suppose ips are grouped. e.g. A: [1, 2, 3], B: [1, 4, 5]. Get the next round-robined result for the specified group combination. Input A means selecting from the group A. Input B means select from the group B. Input AB means select from the intersection of group A and B. Empty means select from all ips.