以下代码均用go实现
普通轮询算法
func main() {
r := new(RoundRobinBalance)
r.Add("127.0.0.1:80")
r.Add("127.0.0.1:81")
r.Add("127.0.0.1:82")
fmt.Println(r.Next())
fmt.Println(r.Next())
fmt.Println(r.Next())
fmt.Println(r.Next())
fmt.Println(r.Next())
}
type RoundRobinBalance struct {
curIndex int
rss []string
}
func (r *RoundRobinBalance) Add(params ...string) error {
if len(params) == 0 {
return errors.New("params len 1 at least")
}
addr := params[0]
r.rss = append(r.rss, addr)
return nil
}
func (r *RoundRobinBalance) Next() string {
rLen := len(r.rss)
if rLen == 0 {
return ""
}
if r.curIndex >= rLen {
r.curIndex = 0
}
cur := r.rss[r.curIndex]
r.curIndex = (r.curIndex + 1) % rLen
return cur
}
加权轮询算法
在 Nginx加权轮询算法 中,每个节点都有3个权重的变量
Weight : 配置的权重,根据配置文件初始化每个服务器节点的权重
currentWeight : 节点的当前权重,初始化时是配置的权重,随后会一直变更
effectiveWeight : 有效的权重,初始值为 weight ,通讯过程中发现节点异常,则 -1 ,之后再次选择本节点,调用成功一次则 +1 ,直到恢复到 weight。这个参数可以用于做降权。或者说是你的设置的权限修正。
Nginx加权轮询算法 的逻辑实现
轮询所有节点,计算当前状态下所有的节点的 effectiveWeight 之和 作为 totalWeight;
更新每个节点的 currentWeight , currentWeight = currentWeight + effectiveWeight;选出所有节点 currentWeight 中最大的一个节点作为选中节点;
选择中的节点再次更新 currentWeight, currentWeight = currentWeight - totalWeight;
注意:实现中不考虑健康检查,即所有的节点都是100%可用的,所以 effectiveWeight 等于 weight
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())
}
type WeightRoundRobinBalance struct {
curIndex int
rss []*WeightNode
}
type WeightNode struct {
weight int
currentWeight int
effectiveWeight int
addr string
}
func (w *WeightRoundRobinBalance) Add(params ...string) error {
if len(params) != 2 {
return errors.New("params len need 2")
}
addr := params[0]
parInt, err := strconv.ParseInt(params[1], 10, 64)
if err != nil {
return err
}
node := &WeightNode{
weight: int(parInt),
currentWeight: int(parInt),
effectiveWeight: int(parInt),
addr: addr,
}
w.rss = append(w.rss, node)
return nil
}
func (w *WeightRoundRobinBalance) Next() string {
if len(w.rss) == 0 {
return ""
}
totalWeight := 0
var maxWeightNode *WeightNode
for key, node := range w.rss {
totalWeight += node.effectiveWeight
node.currentWeight += node.effectiveWeight
if maxWeightNode == nil || maxWeightNode.currentWeight < node.currentWeight {
maxWeightNode = node
w.curIndex = key
}
}
maxWeightNode.currentWeight -= totalWeight
return maxWeightNode.addr
}
数学真的太漂亮了吧~