forked from yeqown/fasthttp-reverse-proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
balancer.go
109 lines (90 loc) · 2.01 KB
/
balancer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package proxy
import (
"sync"
)
// IBalancer .
type IBalancer interface {
Distribute() int
}
// W is an interface which should be implemented by the type
// which will be used in balancer.
type W interface {
Weight() int
}
// Weight .
type Weight uint
func (w Weight) Weight() int {
return int(w)
}
// NewBalancer constructs a IBalancer instance which implements roundrobin algorithm.
func NewBalancer(ws []W) IBalancer {
rrb := roundRobinBalancer{
// choices: ws,
mutex: sync.Mutex{},
weights: make([]int, len(ws)),
maxWeight: 0,
maxGCD: 1,
lenOfWeights: len(ws),
i: -1,
cw: 0,
}
tmpGCD := make([]int, 0, rrb.lenOfWeights)
for idx, w := range ws {
rrb.weights[idx] = w.Weight()
if w.Weight() > rrb.maxWeight {
rrb.maxWeight = w.Weight()
}
tmpGCD = append(tmpGCD, w.Weight())
}
rrb.maxGCD = nGCD(tmpGCD, rrb.lenOfWeights)
return &rrb
}
// roundRobinBalancer is a uniform-distributed balancer.
type roundRobinBalancer struct {
// choices []W
mutex sync.Mutex
weights []int // weight
maxWeight int // 0
maxGCD int // 1
lenOfWeights int // 0
i int // last choice, -1
cw int // current weight, 0
}
// Distribute to implement round-robin algorithm, returns the idx of the choosing in ws ([]W)
// TODO(@yeqown): changing to no lock call
func (rrb *roundRobinBalancer) Distribute() int {
rrb.mutex.Lock()
defer rrb.mutex.Unlock()
for {
rrb.i = (rrb.i + 1) % rrb.lenOfWeights
if rrb.i == 0 {
rrb.cw = rrb.cw - rrb.maxGCD
if rrb.cw <= 0 {
rrb.cw = rrb.maxWeight
if rrb.cw == 0 {
return 0
}
}
}
if rrb.weights[rrb.i] >= rrb.cw {
return rrb.i
}
}
}
// gcd calculates the GCD of a and b.
func gcd(a, b int) int {
if a < b {
a, b = b, a // swap a & b
}
if b == 0 {
return a
}
return gcd(b, a%b)
}
// nGCD calculates the GCD of numbers.
func nGCD(data []int, n int) int {
if n == 1 {
return data[0]
}
return gcd(data[n-1], nGCD(data, n-1))
}