本文基于dubbo v2.6.x
1. 介绍
本文主要是讲解下dubbo集群 快速失败与广播 实现(为了节省文章资源,咱们一块讲解,),首先说下快速失败怎么一回事,比如说服务调用者在进行远程调用的时候,如果出现了异常,它不像我们在《深度解析dubbo集群之失败重试实现》一文中讲解的失败重试一样,而是失败就抛出异常,达到快速失败的效果,其对应的invoker实现是FailfastClusterInvoker类。广播就是 服务调用者在进行远程调用的时候会将调用信息发送给对应的所有服务提供者,有一个异常将会抛出异常,没有异常则会返回最后一个服务提供者返回的结果,其对应的invoker实现类是BroadcastClusterInvoker。
2. 配置
在服务调用者端:
注解配置 快速失败:
@Reference(cluster ="failfast" )
注解配置 广播方式:
@Reference(cluster ="broadcast" )
xml配置 快速失败:
<dubbo:reference interface="com.xuzhaocai.dubbo.provider.IHelloProviderService" id="iHelloProviderService" cluster="failfast"></dubbo:reference>
xml配置 广播方式:
<dubbo:reference interface="com.xuzhaocai.dubbo.provider.IHelloProviderService" id="iHelloProviderService" cluster="broadcast"></dubbo:reference>
3. FailfastClusterInvoker源码解析
FailfastClusterInvoker是快速失败实现invoker, 这里比较简单,我们就直接上源码了
public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> {
public FailfastClusterInvoker(Directory<T> directory) {
super(directory);
}
@Override
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
// 判断invokers 是否为空
checkInvokers(invokers, invocation);
// 使用负载均衡算法选取invoker
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
try {
return invoker.invoke(invocation);
} catch (Throwable e) {
// 如果是RpcException 并且是业务异常, 直接抛出
if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.
throw (RpcException) e;
}
// 其他的异常 使用RpcException 包装抛出
throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
}
}
}
可以看出FailfastClusterInvoker 类继承AbstractClusterInvoker 抽象类,重写 doInvoke方法,在doInvoke 中首先是判断 服务提供者们是否为空,接着使用select 选择一个合适的invoker,这个select 方法是抽象类AbstractClusterInvoker提供的,在《深度解析dubbo集群之抽象实现》一文中有详细的讲解,我们这里就不再啰嗦了,最后就是进行调用,如果出现异常 直接抛出。
4. BroadcastClusterInvoker源码解析
BroadcastClusterInvoker类 主要是实现类广播调用方式的功能,该类的实现也是比较简单,我们直接上源码:
public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class);
public BroadcastClusterInvoker(Directory<T> directory) {
super(directory);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
// 检查 invokers 是否为空
checkInvokers(invokers, invocation);
// 将invokers 塞到context中
RpcContext.getContext().setInvokers((List) invokers);
RpcException exception = null;
Result result = null;
// 遍历invokers 执行, 结果只要最后一个不报错的result
for (Invoker<T> invoker : invokers) {
try {
result = invoker.invoke(invocation);
} catch (RpcException e) {
exception = e;
logger.warn(e.getMessage(), e);
} catch (Throwable e) {
exception = new RpcException(e.getMessage(), e);
logger.warn(e.getMessage(), e);
}
}
// 如果出现一个异常, 抛出异常
if (exception != null) {
throw exception;
}
return result;
}
}
BroadcastClusterInvoker也是继承AbstractClusterInvoker抽象类,实现doInvoke 方法,我们来看下doInvoke方法具体实现,先是检查服务提供者们是否为空,接着就是遍历 服务提供者者们进行调用,如果期间某次调用出现异常,记录下来。调用完成后,如果调用期间有异常,则抛出,如果没有,则是将最后一次调用的结果返回。
5.总结
本文主要讲解了dubbo集群的两个实现,分别是快速失败,广播调用,在文章开始主要是介绍了这个两个含义,然后讲解了在使用的时候怎样配置,最后分别对他们的源码进行了解析。