dubbo广播模式的坑

3 篇文章 0 订阅
1 篇文章 0 订阅

dubbo集群广播模式的坑

场景:消费者需要依次调用某个服务的所有实例,当某个实例报错则消费者能得到异常信息。
dubbo官网的介绍如下:
https://dubbo.gitbooks.io/dubbo-user-book/content/demos/fault-tolerent-strategy.html

Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
于是乎,看代码:
消费者端:

@RestController
public class UserController {
    @Reference(cluster="broadcast")
    private UserService us;
    @RequestMapping("/")
    public String index() {
        String s = null;
        try {
            s = us.getName();
        } catch (Exception e) {
            System.out.println("客户端开始报错了");
            e.printStackTrace();
        }
        return s;
    }
}

服务1:

@Service(cluster="broadcast")
public class UserServerImpl implements UserService{
    public String getName() throws Exception {
        System.out.println("UserService.getName1...");
        int i = 1/0;
        return "UserService.getName1...";
    }
}

服务2:

@Service(cluster="broadcast")
public class UserServerImpl implements UserService{
    public String getName() {
        System.out.println("UserService.getName2...");
        return "UserService.getName2...";
    }
}

启动2个服务,接着启动消费者,调用UserController接口,效果为依次调用了2个服务的getName()方法。
但是,调用了n遍,服务1报错,服务2正常,消费端却没有得到异常信息,这并不是我们想要的结果,因为,某个服务异常,我们需要消费端得到通知并做相应的处理。
于是乎,在消费端debug,进入dubbo源码分析,层层进入,最终到达
com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol这个类的refer()方法:

public <T> Invoker<T> refer(final Class<T> type, final URL url) throws RpcException {
        final Invoker<T> tagert = proxyFactory.getInvoker(doRefer(type, url), type, url);
        Invoker<T> invoker = new AbstractInvoker<T>(type, url) {
            @Override
            protected Result doInvoke(Invocation invocation) throws Throwable {
                try {
                    Result result = tagert.invoke(invocation);
                    Throwable e = result.getException();
                    if (e != null) {
                        for (Class<?> rpcException : rpcExceptions) {
                            if (rpcException.isAssignableFrom(e.getClass())) {
                                throw getRpcException(type, url, invocation, e);
                            }
                        }
                    }
                    return result;
                } catch (RpcException e) {
                    if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) {
                        e.setCode(getErrorCode(e.getCause()));
                    }
                    throw e;
                } catch (Throwable e) {
                    throw getRpcException(type, url, invocation, e);
                }
            }
        };
        invokers.add(invoker);
        return invoker;

请看第9行,debug的结果表明,e就是服务1抛出的异常。
但是,程序并没有走到throw getRpcException(type, url, invocation, e);这一步。
再看rpcExceptions的值:
这里写图片描述
org.springframework.remoting.RemoteAccessException
java.rmi.RemoteException
而e.getClass()为:java.lang.ArithmeticException,所以该异常并不会抛给消费者。
解决方法:
服务1抛出的异常封装为RemoteAccessException或者RemoteException。

@Service(cluster="broadcast")
public class UserServerImpl implements UserService{
    public String getName() throws RemoteException {
        try {
            System.out.println("UserService.getName1...");
            int i = 1/0;
        }catch (Exception e) {
            throw new RemoteException(e.getMessage(),e);
        }
        return "UserService.getName1...";
    }
}

此时,服务1抛异常,消费者能接收到了。
over

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下一页天空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值