dubbo集群容错模式
- Failover Cluster:失败重试
- Failover Cluster:快速失败
- Failsafe Cluster:失败安全
- Failback Cluster:失败自动恢复
- Forking Cluster:并行调用
- Broadcast Cluster:广播调用
dubbo负载均衡策略
- Random LoadBalance:随机策略
- RoundRobin LoadBalance:轮询策略
- LeastActive LoadBalance:最少活跃调用数
- ConsisentHash LoadBalance:一致性Hash策略
差异:
- 随机策略完全是随机
- 轮询策略优点是实现简单,易水平扩展,且比较均衡分发到所有实例,缺点无法知道所有的实例的情况
- 最少活跃调用策略考虑了服务器处理能力的不同
- 一致性Hash策略设置了虚拟节点,能使分配更均匀
轮询策略:
public class RoundRobinLoadBalance extends AbstractLoadBalance {
public static final String NAME = "roundrobin";
// 记录所有提供服务的数据,<serviceKey+methodName, 调用次数>
private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
@Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
// 被调用实例数
int length = invokers.size(); // Number of invokers
// 最大权重值
int maxWeight = 0; // The maximum weight
// 最小权重值
int minWeight = Integer.MAX_VALUE; // The minimum weight
// 记录每个实例以及对应的权重
final LinkedHashMap<Invoker<T>, IntegerWrapper> invokerToWeightMap = new LinkedHashMap<Invoker<T>, IntegerWrapper>();
// 权重之和
int weightSum = 0;
// 遍历所有被调用实例
for (int i = 0; i < length; i++) {
// 获取对应实例的权重值
int weight = getWeight(invokers.get(i), invocation);
// 设置最大、最小权重值
maxWeight = Math.max(maxWeight, weight); // Choose the maximum weight
minWeight = Math.min(minWeight, weight); // Choose the minimum weight
if (weight > 0) {
// 只添加有权重的实例
invokerToWeightMap.put(invokers.get(i), new IntegerWrapper(weight));
weightSum += weight;
}
}
// 获取该服务的调用次数
AtomicPositiveInteger sequence = sequences.get(key);
if (sequence == null) {
// 没有调用记录则添加数据
sequences.putIfAbsent(key, new AtomicPositiveInteger());
sequence = sequences.get(key);
}
// 调用次数加一
int currentSequence = sequence.getAndIncrement();
// 实例有权重,则根据权重大小分配
if (maxWeight > 0 && minWeight < maxWeight) {
// 将调用次数 % 权重总数,得出偏移量 mod
int mod = currentSequence % weightSum;
// 遍历最大的权重值,
// 为什么会遍历它?
// 因为每一次循环就遍历所有的实例,一个实例最大的权重为 maxWeight,
// 最多遍历 maxWeight 次所有实例就可以找到想要的实例
for (int i = 0; i < maxWeight; i++) {
// 遍历所有的实例
for (Map.Entry<Invoker<T>, IntegerWrapper> each : invokerToWeightMap.entrySet()) {
final Invoker<T> k = each.getKey();
final IntegerWrapper v = each.getValue();
if (mod == 0 && v.getValue() > 0) {
// mod 为 0 表示选中了,但要满足该实例的权重大于 0
return k;
}
if (v.getValue() > 0) {
// 实例没选中,则权重减 1,相当于选中机会少了
v.decrement();
// 偏移量也减 1
mod--;
}
}
}
}
// 没有权重则 调用次数 % 实例数量 对应下标的实例返回
// Round robin
return invokers.get(currentSequence % length);
}
}