常见的负载均衡的几种方式
- 随机
- 轮询
- hash
- 一致性hash
- 权重
- 最小链接
- 最短响应时间
今天先来看下dubbo怎么实现权重的负载均衡的,其实各种组件实现基本也一致,权重简单介绍下就是常见的设置,比如
server1 weight=1;
server2 weight=2;
server3 weight=1;
就是说现在来了100个请求,怎么能把对应的请求按照权重进行分配,server1占1/4 也就是分25个,server2一半,50个,server3 1/4 也就是25个
先看下dubbo怎么实现的,关键代码如下
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + RpcUtils.getMethodName(invocation);
ConcurrentMap<String, WeightedRoundRobin> map = ConcurrentHashMapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>());
int totalWeight = 0;
long maxCurrent = Long.MIN_VALUE;
long now = System.currentTimeMillis();
Invoker<T> selectedInvoker = null;
WeightedRoundRobin selectedWRR = null;
// 所有的实例列表
for (Invoker<T> invoker : invokers) {
// 根据url得到的标识
String identifyString = invoker.getUrl().toIdentityString();
// 获取对应的权重
int weight = getWeight(invoker, invocation);
// 对应的权重类
WeightedRoundRobin weightedRoundRobin = ConcurrentHashMapUtils.computeIfAbsent(map, identifyString, k -> {
WeightedRoundRobin wrr = new WeightedRoundRobin();
wrr.setWeight(weight);
return wrr;
});
if (weight != weightedRoundRobin.getWeight()) {
//weight changed
weightedRoundRobin.setWeight(weight);
}
// 这里是每次遍历都要加上对应的权重,但是到后面选中的会减去,也就是大的都是需要被选中执行的
long cur = weightedRoundRobin.increaseCurrent();
weightedRoundRobin.setLastUpdate(now);
if (cur > maxCurrent) {
// maxCurrent就是在计算所有invoke里面的最大的cur,然后让其选中
maxCurrent = cur;
selectedInvoker = invoker;
selectedWRR = weightedRoundRobin;
}
totalWeight += weight;
}
if (invokers.size() != map.size()) {
map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);
}
if (selectedInvoker != null) {
// 减去对应的值,下次如果不大于,totalWeight就是所有成员的总大小,
selectedWRR.sel(totalWeight);
return selectedInvoker;
}
// should not happen here
return invokers.get(0);
}
大致总结下实现原理呢,就是把所有的服务提供者先列出来,放入到对应的map,有存储对应的服务者的权重信息,然后给其一个记录值 cur,然后每次遍历这些服务提供者,对其cur加上对应的权重值,然后找到cur最大的,选中让其执行,选中执行的,执行一次之后把对应的cur减去总的weight,举个例子,默认cur大家开始都是0,现在开始遍历
server1 cur = cur+weight;// cur = 1,
server2 cur = cur+weight;// cur=2
server3 cur = cur+weight; //cur=1
totalweight = server1的weight+server2的weight+server3的weight 就是4
这时候选中的就是服务2,然后服务2对应的cur 减去totalweight 变为了-2;
下一轮遍历
server1 cur = cur+weight;// cur = 2,
server2 cur = cur+weight;// cur=0
server3 cur = cur+weight; //cur=2
遍历完就是选中server1,然后server1的cur = cur-totalweight,cur变为-2;
就是这样一遍遍的选择,选择cur最大的,因为cur是根据权重增加的,所以,权重大的被选中的次数更高,实现的很巧妙,也不至于出现不均衡