Cluster接口
Cluster接口提供了集群容错的功能。在 Dubbo 中,通过 Cluster 这个接口把一组可供调用的 Provider 信息组合成为一个统一的 Invoker 供调用方进行调用。经过 Router 过滤、LoadBalance 选址之后,选中一个具体 Provider 进行调用,如果调用失败,则会按照集群的容错策略进行容错处理。
Cluster接口的工作流程
Cluster接口工作流程分为两步:
- 在Consumer进行服务引用的时候,会创建对应Cluster实现类的集群容错策略对应的ClusterInvoker。也就是说在Cluster接口实现中,都会创建对应的Invoker对象,这些都继承自AbstractClusterInvoker抽象类。
- 调用时使用ClusterInvoker实例,内部会实现集群容错的逻辑,且会依赖Directory、Router、LoadBalance等组件得到最终要调用的Invoker对象。
也就是说,因为Cluster在服务引用的过程中将多个Invoker伪装为带有集群容错的ClusterInvoker实现,所以在调用的时候可以在对应集群容错逻辑下,再对Invokers进行服务目录、服务路由过滤、负载均衡选址选出真正调用的Invoker发起远程调用逻辑。
常见的几种集群容错的方式
Dubbo中的AbstractClusterInvoker
了解了 Cluster Invoker 的继承关系之后,我们首先来看 AbstractClusterInvoker,它有两点核心功能:一个是实现的 Invoker 接口,对 Invoker.invoke() 方法进行通用的抽象实现;另一个是实现通用的负载均衡算法。
在 AbstractClusterInvoker.invoke() 方法中,会通过 Directory 获取 Invoker 列表,然后通过 SPI 初始化 LoadBalance,最后调用 doInvoke() 方法执行子类的逻辑。在 Directory.list() 方法返回 Invoker 集合之前,已经使用 Router 进行了一次筛选。
1 |
|
在子类实现的doInvoke方法中,调用了在抽象类中提供的select()方法,来完成负载均衡。这里没有去直接委托给LoadBalance去做负载均衡,而是在 select() 方法中会根据配置决定是否开启粘滞连接特性,如果开启了,则需要将上次使用的 Invoker 缓存起来,只要 Provider 节点可用就直接调用,不会再进行负载均衡。这里知道即可。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation,
List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
if (CollectionUtils.isEmpty(invokers)) {
return null;
}
// 方法名称
String methodName = invocation == null ? StringUtils.EMPTY_STRING : invocation.getMethodName();
// 获取sticky配置,sticky表示粘滞连接,所谓粘滞连接是指Consumer会尽可能地调用同一个Provider节点,除非这个Provider无法提供服务
boolean sticky = invokers.get(0).getUrl()
.getMethodParameter(methodName, CLUSTER_STICKY_KEY, DEFAULT_CLUSTER_STICKY);
//ignore overloaded method
if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {
stickyInvoker = null;
}
//ignore concurrency problem
if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {
if (availablecheck && stickyInvoker.isAvailable()) {
return stickyInvoker;
}
}
// doSelect选择新的Invoker
Invoker<T> invoker = doSelect(loadbalance, invocation, invokers, selected);
if (sticky) {
stickyInvoker = invoker;
}
return invoker;
}
Dubbo中的AbstractCluster
常用的 ClusterInvoker 实现都继承了 AbstractClusterInvoker 类型,对应的 Cluster 扩展实现都继承了 AbstractCluster 抽象类。AbstractCluster 抽象类的核心逻辑是在 ClusterInvoker 外层包装一层 ClusterInterceptor,从而实现类似切面的效果。
1 |
|
Dubbo中具体的集群容错实现
FailOverCluster
默认是FailOverCluster,可以看到其实现的doJoin方法就是创建一个对应的FailOverClusterInvoker对象并返回。1
2
3
4
5
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
// 直接委托给FailoverClusterInvoker
return new FailoverClusterInvoker<>(directory);
}
而在FailOverClutserInvoker中实现的doList方法中,有对失败重试容错的实现:
1 |
|