Dubbo负载均衡
导言
Dubbo架构,基本的角色分为三者:
- 服务提供者Provider
- 服务消费者Consumer
- 注册中心
Consumer注册过程
- Consumer启动以后,和注册中心建立长连接;
- 注册中心会把Consumer订阅的服务的当前正常在线的Provider的列表提供名单提供给Consumer;
- Consumer会和每个正常在线的Provider建立一个或者多个TCP长连接;
负载均衡
负载均衡的具体逻辑是在Provider服务端进行配置。
| 模式 | 功能 | 使用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| Random | 随机选择 | 缺省 | ||
| RoundRobin | 按公约后的权重设置轮循比率 | |||
| LeastActive | 根据请求调用的次数计数 | 处理请求更慢的节点会受到更少的请求 | ||
| ConsistentHash | 相同参数的请求总是发到同一提供者 | 当某一台提供者挂时,不会引起剧烈变动 |
具体的配置方法:
<dubbo:service interface="com.test.api.XxService" loadbalance="random">
<dubbo:method ... />
</dubbo:service>
内部实现
Random Select策略的实现
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size(); // Number of invokers
int totalWeight = 0; // The sum of weights
boolean sameWeight = true; // Every invoker has the same weight?
for (int i = 0; i < length; i++) {
int weight = getWeight(invokers.get(i), invocation);
totalWeight += weight; // Sum
if (sameWeight && i > 0
&& weight != getWeight(invokers.get(i - 1), invocation)) {
sameWeight = false;
}
}
if (totalWeight > 0 && !sameWeight) {
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
int offset = random.nextInt(totalWeight);
// Return a invoker based on the random value.
for (int i = 0; i < length; i++) {
offset -= getWeight(invokers.get(i), invocation);
if (offset < 0) {
return invokers.get(i);
}
}
}
// If all invokers have the same weight value or totalWeight=0, return evenly.
return invokers.get(random.nextInt(length));
}
算法伪代码:
获得provider的数量
for invoker in invokers:
获得weight
更新总weight
比较invoker的权重,和之前的invoker的权重是否相同
不同的话:sameWeight=false
if totalWeight > 0 && sameWeight == fase:
根据权重生成一个随机值
if sameWeight == true:
返回一个随机的invoker
getWeight功能
protected int getWeight(Invoker<?> invoker, Invocation invocation) {
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
if (weight > 0) {
long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
if (timestamp > 0L) {
int uptime = (int) (System.currentTimeMillis() - timestamp);
int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
if (uptime > 0 && uptime < warmup) {
weight = calculateWarmupWeight(uptime, warmup, weight);
}
}
}
return weight;
}
算法伪代码:
从provider提供的参数中获得,该方法设置的权重
如果权重>0
获取服务注册是的时间timestamp
如果timestamp>0
计算该provider上线的时间
获得该Provider的warmUp的参数
如果上线的时间<warmUp的参数
根据warmup重新计算权重
返回权重
浙公网安备 33010602011771号