Dubbo IO异常的捕获

需求

为什么要写这么一个小问题呢,可能有同学说了,发生异常后不是自动就体现到日志里面去了吗?有啥可捕获的?

想想这么一个场景:

生产环境中众多日志中发现了如下异常信息:

[New I/O worker #1][Log4j2Logger.java:73] - 
Data length too large: 1895857664, max payload: 8388608, 
channel: NettyChannel [channel=[id: 0xbe23f2b5, 
/172.31.5.38:36596 => /172.31.2.196:21880]]\n\"\

用过Dubbo的都知道,这是因为 RPC接口的返回值过大,超出了设定的响应最大值,可以通过修改 payload 参数来解决。

通过这个信息你大致可以知道是 哪两个服务 交互时发生的异常,但是无法知道具体是哪个接口、哪个方法、什么参数情况下产生的这个异常,里面也没有logId。

这就是老吕要捕获它的原因,我要把产生这个错误时对应的 logId,接口名称,方法名称,和参数值 全部记录下来,方便业务开发的同学进行优化改进。

logId在每一个业务线程中都会绑定,发生业务异常时日志中就会自动记录下 logId,开发人员可以方便的检索 分布式链路日志解决问题。但是这个IO异常是产生的IO线程上的,大家都知道在NIO架构中IO线程是所有业务线程共享的,这就意味着 IO线程上不可能绑定业务logId这个东西,所以它出来的异常中是没有logId这个东西的。

解决方案

关于Dubbo IO线程模型的先不说了,下面直接给出一个针对此问题的可行的解决方案:

由于这个IO异常的根源产生在提供者端,我一直想在提供者端捕获,最终证明不太可行(有知道的同学可以通知我下),还是要到消费者端捕获。

我分别写了2个过滤器,一个是提供者端过滤器,一个是消费者端过滤器,看里面的注释就知道怎么做了,如下:

##提供者过滤器(无法感知Duboo IO异常,这里只是为了说明问题)

public class MyProviderFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long startTime = System.currentTimeMillis();
        try {
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                //是否有异常,异常处理,这里可以感知所有的业务线程异常,但无法感知Dubbo的IO异常
            }
            return result;
        }catch (Throwable e){
            //这里也无法感知IO异常
            e.printStackTrace();
            throw e;
        }finally {
            String log = invoker.getInterface().getCanonicalName()+","+invocation.getMethodName();
            System.out.println(log+","+(System.currentTimeMillis()-startTime));
        }


    }
}

##消费者过滤器(可以感知Dubbo IO异常,但是也需要特殊处理才行)

public class MyConsumerFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long startTime = System.currentTimeMillis();
        try {
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                //是否有异常,异常处理,这里无法感知Dubbo IO异常
            }
            return result;
        }catch (Throwable e){
            //这里可以感知IO异常
            dubboRpcLog(invoker,invocation,e.getMessage());
            throw e;
        }finally {
            String log = invoker.getInterface().getCanonicalName()+","+invocation.getMethodName();
            System.out.println(log+","+(System.currentTimeMillis()-startTime));
        }


    }




    /**
     * 记录调用日志
     * @param invoker
     * @param invocation
     */
    private void dubboRpcLog(Invoker<?> invoker, Invocation invocation,String errorMsg) {


        StringBuilder message = new StringBuilder();
        message.append("dubboUrl:").append(invoker.getUrl()).append(";");
        message.append("interface:").append(invoker.getInterface().getName()).append(";");
        message.append("methodName:").append(invocation.getMethodName()).append(";");


        Class<?>[] parameterTypes = invocation.getParameterTypes();
        Object[] arguments = invocation.getArguments();


        if (parameterTypes!=null||parameterTypes.length>0) {
            message.append("arguments:");
            try {
                message.append(JSON.json(arguments));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(message.toString());
    }
}

今天就到这里,希望对你有所帮助

38229414e9c5056a8c7ef1d5d943b02c.png

扫码加微信技术群

7d7da86d6c84bbf0eeba757e0f66bdde.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吕哥架构

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

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

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

打赏作者

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

抵扣说明:

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

余额充值