-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbalancer.go
126 lines (107 loc) · 2.51 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package balancer
import (
"reflect"
"github.com/fufuok/load-balancer/utils"
)
type Balancer interface {
// Select gets next selected item.
// key is only used for ConsistentHash
Select(key ...string) interface{}
// Name load balancer name.
Name() string
// Update reinitialize the balancer items.
Update(choices []*Choice) bool
}
// Choice to be selected for the load balancer
type Choice struct {
// e.g. server addr / node / *url.URL
Item interface{}
// For WeightedRoundRobin / SmoothWeightedRoundRobin / WeightedRand
Weight int
// For SmoothWeightedRoundRobin, optional
CurrentWeight int
}
// Mode defines the selectable balancer algorithm.
type Mode int
const (
// WeightedRoundRobin is the default balancer algorithm.
WeightedRoundRobin Mode = iota
SmoothWeightedRoundRobin
WeightedRand
ConsistentHash
RoundRobin
Random
)
// NewChoice create new items with optional weights.
func NewChoice(item interface{}, weight ...int) *Choice {
w := 1
if len(weight) > 0 {
w = weight[0]
}
return &Choice{
Item: item,
Weight: w,
}
}
// NewChoicesMap map to choices []*Choice
func NewChoicesMap(items interface{}) (choices []*Choice) {
v := reflect.ValueOf(items)
if v.Kind() != reflect.Map {
return
}
n := v.Len()
m := v.MapRange()
choices = make([]*Choice, 0, n)
for m.Next() {
choices = append(choices, &Choice{
Item: m.Key().Interface(),
Weight: utils.MustInt(m.Value().Interface()),
})
}
return
}
// NewChoicesSlice slice to choices []*Choice
func NewChoicesSlice(items interface{}) (choices []*Choice) {
v := reflect.ValueOf(items)
if v.Kind() != reflect.Slice {
return
}
n := v.Len()
choices = make([]*Choice, 0, n)
for i := 0; i < n; i++ {
choices = append(choices, &Choice{
Item: v.Index(i).Interface(),
Weight: 1,
})
}
return
}
// New create a balancer with or without items.
func New(b Mode, choices []*Choice) Balancer {
switch b {
case SmoothWeightedRoundRobin:
return NewSmoothWeightedRoundRobin(choices...)
case RoundRobin:
return NewRoundRobin(choices...)
case WeightedRand:
return NewWeightedRand(choices...)
case ConsistentHash:
return NewConsistentHash(choices...)
case Random:
return NewRandom(choices...)
default:
return NewWeightedRoundRobin(choices...)
}
}
// Discard items with a weight less than 1
func cleanWeight(choices []*Choice) (items []*Choice, n int) {
items = make([]*Choice, 0, len(choices))
for i := range choices {
if choices[i].Weight <= 0 {
continue
}
items = append(items, choices[i])
n++
}
return
}