负载均衡算法常见实现
1 随机负载均衡较为简单,获取指定服务列表,根据大小生成大小区间的随机数,注册中心使用的consul,先根据服务名称拉取服务列表,省略(服务端存储的服务以双map形式,请求后转为切片)。
func (r *RandomLoadBalance) SelectService(services []*ServiceInstance) (*ServiceInstance, error) {if services == nil || len(services) == 0 {return nil, errors.New("service instances are not exist")}return services[rand.Intn(len(services))], nil
}
2 加权轮询负载实现:重点在轮询意味这儿有一个循环点,其次是加权,这意味这在一次循环中,权越重越优先,所以怎么设计?
具体实现方式如下:
func (r *WeightRoundRobinLoadBalance) SelectService(services []*ServiceInstance) (best *ServiceInstance,err error) {if services == nil || len(services) == 0 {return nil, errors.New("service instances are not exist")}total := 0for i := 0; i < len(services); i++ {w := services[i]if w == nil {continue}w.CurWeight += w.Weight //当前固定分配的权重total+=w.Weightif best==nil||w.CurWeight>best.CurWeight{best=w}}if best==nil {return nil,nil}best.CurWeight-=totalreturn best ,nil
}
1 每个服务有自己固定的权重和用于计算的当前权重分别为weight和CurWeight,Weight配置的服务实例的权重,固定不变;
2curWeight是服务实例目前的权重,为了统一获取动态的最大值,每个实例权重都要动态变化,计算到都有可能最大值的标识,一开始都为0,之后会动态调整。
每次当请求到来,选取服务实例时,该策略会遍历服务实例队列中的所有服务实例。对于每个服务实例,让它的curwiight增加它的weight值,同时累加所有放入服务实例的Weight,并保存在toal,
遍历所有服务之后,如果当前的实例的curweight最大则就返回该实例,把最后该实例的curWeight-total赋值当前的CurWright意味刚调用过的会进入其他所有节点的权重总和的相反数,即去除权重的优势,每一个节点都会如此,直到下一轮又回到每个节点的curWight为0 0 0进入新循环
举例说明 A、B、C权重为 3、2、1初始化的curweight全为0,每个节点的curweight的计算过程如下:
请求序号 | 计算前的CurWeight | 选择的实例 | 计算后的CurWeight |
1 | {3,2,1}=n | a | {-3,2,1}=t |
2 | {t}+{n}={0,4,2} | b | {0,-2,2} |
3 | {3,0,3} | a | {-3,0,3} |
4 | {0,2,4} | c | {0,2,-2} |
5 | {3,4,-1} | b | {3,-2,-1} |
6 | {6,0,0} | a | {0,0,0} |
发现计算后的的t他们的权重和为0,就是被选择实例后CurWeight=CurWeight-total的结果,是其他当前实例的当前权重和的相反数,对于最后的CurWeight回归到初始的{0,0,0}就是轮询,至于为什么会回归,这个可以多尝试几组数据理解。