负载均衡接口
var (
ErrNotHaveNodes = errors.New("not have node")
)
type LoadBalance interface {
Name() string
Select(ctx context.Context, nodes []*registry.Node) (node *registry.Node, err error)
}
Name接口返回负载均衡的名称
Select接口返回节点node信息,
// 服务节点的抽象
type Node struct {
Id string `json:"id"`
IP string `json:"ip"`
Port int `json:"port"`
Weight int `json:"weight"`
}
1、随机
ype RandomBalance struct {
}
func (r *RandomBalance) Name() string {
return "random"
}
func (r *RandomBalance) Select(ctx context.Context, nodes []*registry.Node) (node *registry.Node, err error) {
if len(nodes) == 0 {
err = ErrNotHaveNodes
return
}
index := rand.Intn(len(nodes))
node = nodes[index]
return
}
2、轮训
type RoundRobinBalance struct {
index int
}
func (r *RoundRobinBalance) Name() string {
return "roundrobin"
}
func (r *RoundRobinBalance) Select(ctx context.Context, nodes []*registry.Node) (node *registry.Node, err error) {
if len(nodes) == 0 {
err = ErrNotHaveNodes
return
}
r.index = (r.index + 1) % len(nodes)
node = nodes[r.index]
return
}
3、权重
关于权重,
type WeightBalance struct {
}
func (r *WeightBalance) Name() string {
return "weight"
}
func (r *WeightBalance) Select(ctx context.Context, nodes []*registry.Node) (node *registry.Node, err error) {
if len(nodes) == 0 {
err = ErrNotHaveNodes
return
}
var totalWeight int
for _, val := range nodes {
if val.Weight == 0 {
val.Weight = DefaultNodeWeight
}
totalWeight += val.Weight
}
curWeight := rand.Intn(totalWeight)
curIndex := -1
for index, node := range nodes {
curWeight -= node.Weight
if curWeight < 0 {
curIndex = index
break
}
}
if curIndex == -1 {
err = ErrNotHaveNodes
return
}
node = nodes[curIndex]
return
}
测试 关于权重, 比如有3个节点
权重是50 + 100 + 150 = 300
假如curWeight = 270
270 - 50 = 220 220 - 100 = 120 120 - 150 = -30 节点3
180 - 50 = 130 130 - 100 = 30 30 - 150 = 120 节点3
150 以上都是节点3 50 以上都是节点 2 50 一下是 节点1 所以 节点3选中的概率是 50 %
func TestSelect(t *testing.T) {
balance := &RandomBalance{}
var weights = [3]int{50, 100, 150}
var nodes []*registry.Node
for i := 0; i < 4; i++ {
node := ®istry.Node{
IP: fmt.Sprintf("127.0.0.%d", i),
Port: 8080,
Weight: weights[i%3],
}
fmt.Printf("node:%#v\n", node)
nodes = append(nodes, node)
}
countStat := make(map[string]int)
for i := 0; i < 1000; i++ {
node, err := balance.Select(context.TODO(), nodes)
if err != nil {
t.Fatalf("select failed, err:%v", err)
continue
}
countStat[node.IP]++
}
for key, val := range countStat {
fmt.Printf("ip:%s count:%v\n", key, val)
}
return
}