在介绍 Cluster
之前再来回顾一下集群容错的架构图:

看下官网对 Cluster
的介绍:
Cluster
将Directory
中的多个Invoker
伪装成一个Invoker
,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个
什么意思呢,简单来说就是上层在调用的时候不需要关心具体有多少个 Invoker
,只需要使用 Cluster
包装过的一个 Invoker
即可,同时包装过的 Invoker
包含了容错处理。
下面看下 Cluster
的类图:

可以看到,具体有9个实现类,分别对应不同的容错处理策略。
Cluster
接口的定义:
|
|
该接口只有一个方法,根据 SPI
的注解可知,默认的策略是 FailoverCluster
。下面分别来看下具体的实现。
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2"
来设置重试次数(不含第一次)。
FailoverCluster:
|
|
上面说到, Cluster
的作用是将多个 Invoker
包装成一个 Invoker
来实现对上层的透明,所以每种类型的 Cluster
都有不同的 Invoker
的实现,看下 FailoverClusterInvoker
中的 doInvoke
方法:
|
|
可以看到这里使用了 for
循环来实现重试的操作。看下如下的一行代码:
Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
通过前几篇的分析可以知道, select
方法最终会通过 LoadBalance
选取出一个 Invoker
,然后执行具体的调用:
Result result = invoker.invoke(invocation);
如果没有异常,说明调用成功,则返回,否则按照设置的重试次数进行重试。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
FailfastClusterInvoker:
|
|
如果调用失败,则立即报错。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
|
|
在调用出错时,会调用 addFailed
方法进行定时重发,使用 ScheduledExecutorService
来实现,默认时间是5秒一次。在线程池用调用 retryFailed
进行具体的重试调用,如果调用成功,则将此次的调用从 failed
中删除。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2"
来设置最大并行数。
ForkingClusterInvoker:
|
|
为了实现并行的调用,在 for
循环中,将具体调用放入线程池中执行,并将结果放入阻塞队列 ref
中,下面通过 poll
方法来获取结果,如果在超时时间过后还没有调用的结果,则抛出异常,如果有调用的结果,不管是哪一次调用,则返回。
MockClusterWrapper
这个类比较特殊,它主要是用来进行本地伪装,看下官网的描述:
本地伪装通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过
Mock
数据返回授权失败
也就是说,在服务提供者都不可用的情况下,会调用本地的 Invoker
来返回调用结果,看下 join
方法的实现:
|
|
可以看到这里通过 MockClusterInvoker
包装了一层 Invoker
,比如说上面提到的 FailoverClusterInvoker
,这里的 MockClusterInvoker
也是实现了 Invoker
接口,具体的分析打算在以后单独写一篇 本地伪装
的文章中分析,这里简单看下 invoke
方法的实现:
|
|
分析一下执行过程:
- 通过
URL
参数来判断是否传了mock
参数; - 如果有
mock
参数并且为false
,则通过具体的invoker
来调用,比如说使用FailoverClusterInvoker
来调用; - 如果有
mock
参数并且值为force
,则说明强制使用本地伪装,调用doMockInvoker
方法; - 如果
mock
为true
,则在具体的调用失败的时候进行本地伪装。
其他几种的实现特别简单,这里就不介绍了。 这里还有一种 MergeableCluster
,它是用来进行 分组聚合
的功能,这个会在以后进行介绍。