Dubbo负载均衡的几种方式
Dubbo支持以下几种负载均衡方式:
- Random LoadBalance
- RoundRobin LoadBalance
- LeastActive LoadBalance
- ConsistentHash LoadBalance
- Forking LoadBalance
- Failover LoadBalance
- Failfast LoadBalance
- Failsafe LoadBalance 具体说明如下:
- Random LoadBalance:随机选择一个服务提供者。
- RoundRobin LoadBalance:轮询选择服务提供者。
- LeastActive LoadBalance:选取活跃调用数最小的服务提供者。
- ConsistentHash LoadBalance:一致性哈希负载均衡算法。
- Forking LoadBalance:并行调用多个服务提供者,只要有一个成功就返回。
- Failover LoadBalance:失败自动切换到其他服务提供者,通常用于非幂等性的远程调用。
- Failfast LoadBalance:失败快速失败,通常用于幂等性的远程调用。
- Failsafe LoadBalance:失败安全,总是调用所有服务提供者,通常用于写入审计日志等操作。
Dubbo负载均衡策略
Dubbo负载均衡有两种策略,即随机和权重。下面给出Dubbo配置文件中的负载均衡配置示例:
<dubbo:reference interface="com.alibaba.dubbo.demo.DemoService" loadbalance="random" />
这里设置负载均衡策略为随机,也可以设置为权重策略,示例如下:
<dubbo:reference interface="com.alibaba.dubbo.demo.DemoService">
<dubbo:method name="sayHello" loadbalance="roundrobin" />
</dubbo:reference>
Dubbo负载均衡源码
Dubbo负载均衡的源码在Dubbo的GitHub仓库中,查看地址为:
https://github.com/apache/dubbo/tree/master/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance
Ribbon负载均衡
Ribbon是Netflix开源的负载均衡组件,Dubbo可以集成Ribbon实现负载均衡。Ribbon的负载均衡算法可以自定义实现,Dubbo使用的是RoundRobin策略,示例配置如下:
<dubbo:provider protocol="dubbo" loadbalance="roundrobin" server="netty4" />
Dubbo协议
Dubbo协议是Dubbo RPC通信协议的实现,其主要特点如下:
- Dubbo协议采用NIO异步通信、多路复用技术,可以提高吞吐量。
- Dubbo协议支持长连接,减少连接建立的开销。
- Dubbo协议支持多协议,可以在
dubbo://
、rest://
等多种协议间切换。
Dubbo接口
Dubbo接口是Dubbo服务的提供方和消费方进行通信的契约。Dubbo服务提供者和消费者都必须引用相同的接口。 示例代码:
public interface DemoService {
String sayHello(String name);
}
Dubbo负载均衡算法
Dubbo负载均衡算法有多种实现方式,例如RandomLoadBalance
、RoundRobinLoadBalance
等。下面给出RoundRobinLoadBalance
的算法简述:
- 将所有可用服务提供者存入一个有序列表
list
。 - 如果服务提供者列表为空,则返回空;如果只有一个服务提供者,则返回该服务提供者。
- 如果服务提供者列表不为空,则获取下一个服务提供者并返回。 其Java代码实现如下:
public class RoundRobinLoadBalance extends AbstractLoadBalance {
private final AtomicPositiveInteger sequences = new AtomicPositiveInteger();
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size(); // 调用的服务数
int maxWeight = 0;
int minWeight = Integer.MAX_VALUE;
final LinkedHashMap<Invoker<T>, IntegerWrapper> invokersWightMap = new LinkedHashMap<>();
int weightSum = 0;
for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i);
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "weight", 100);
invokersWightMap.put(invoker, new IntegerWrapper(weight));
weightSum += weight;
maxWeight = Math.max(maxWeight, weight);
minWeight = Math.min(minWeight, weight);
}
// 不同的权重转换为相同的权重
int weightDiff = maxWeight - minWeight;
if (weightDiff > 0) {
for (Map.Entry<Invoker<T>, IntegerWrapper> entry : invokersWightMap.entrySet()) {
entry.setValue(new IntegerWrapper(entry.getValue().get() - minWeight));
}
weightSum -= minWeight * length;
}
// 循环列表进行轮转
int sequence = sequences.getAndIncrement();
if (weightSum > 0 && sequence < Integer.MAX_VALUE) {
int currentWeight = -1;
Invoker<T> selectedInvoker = null;
int currentSequence = -1;
for (int i = 0; i < length; i++) {
sequence++;
if (sequence > weightSum) {
sequence = weightSum;
}
for (Map.Entry<Invoker<T>, IntegerWrapper> entry : invokersWightMap.entrySet()) {
selectedInvoker = entry.getKey();
currentWeight = entry.getValue().get();
currentSequence += currentWeight;
if (currentSequence >= sequence) {
return selectedInvoker;
}
}
currentSequence = 0;
}
}
// 相同权重,随机选择
return invokers.get(ThreadLocalRandom.current().nextInt(length));
}
static class IntegerWrapper {
private int value;
public IntegerWrapper(int value) {
this.value = value;
}
public int get() {
return value;
}
public void set(int value) {
this.value = value;
}
}
}
Dubbo负载均衡原理
Dubbo负载均衡实现的原理如下:
- 获取所有可用服务提供者的列表,计算出他们的权重。
- 根据负载均衡策略选择一个服务提供者。
- 如果服务提供者无法响应,返回到第2步重新选择。
- 返回选取的服务提供者。
Dubbo负载均衡在哪层
Dubbo负载均衡在服务层,属于网络通信层。
Dubbo负载均衡策略如何配置选取
Dubbo负载均衡策略可以在Dubbo配置文件中进行配置,例如:
<dubbo:reference interface="com.alibaba.dubbo.demo.DemoService" loadbalance="random" />
也可以通过代码进行动态设置,例如:
public class DemoConsumer {
public static void main(String[] args) {
ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
reference.setInterface(DemoService.class);
reference.setLoadbalance("roundrobin");
DemoService demoService = reference.get();
String hello = demoService.sayHello("world");
System.out.println(hello);
}
}