记一次dubbo的死循环


1. 事件
现象一个核占用一直100%
程序经排查,有程序出现死循环
涉及工具linux常用指令、Arthas
解决方案修改导致死循环的代码段
开源库dubbo(2.5.3)
在排查问题的过程中,查到dubbo issue中有提到这个问题,并且在之后的版本中修复了 issue
2. 正文

遇到了一个线上问题,cpu一个核一直处于100%; 先直接说下结论就是死循环了,后面在来说说分析过程

  1. 来看看这个导致死循环的代码段,这个代码段大致的逻辑是执行dubbo的rpc超时逻辑,dubbo的rpc超时控制使用了一个额外的线程来做的,这样做的好处是可以做到一个全局的控制,并且在做完一次后,sleep(30)来让出cpu; 在来具体看看这个代码段,注释也写的很清楚,1. 创建一个异常response; 2. 设置timeout状态;3. 处理这个response,然后把这个future从map中删除掉,然后这个for循环就可以走完了,等30ms, 在进行下一次处理逻辑; 而且for循环还用了try/catch包裹,防止异常挂掉这个线程,乍一看没有什么问题。但是出现了死循环,那就是没有走到Thread.Sleep(30),难道是一直在执行for语句么,其实这里还隐藏着一个执行流,如果for语句里面出现异常,会走到catch代码段,而且出现异常代码块的下面的逻辑就走不下去了,catch之后打印一条日志后继续跑去执行for语句了,假如抛出异常出现在remove掉元素之前,那么会导致FUTURES里面一直有元素,而且这个元素走里面的流程一直会throw exception,这样又会被catch住,这样就死循环了。

/*
1. dubbo的rpc调用的超时控制在额外启动了一个线程来做,每次做完sleep(30)来让出cpu给其他线程调度
*/
private static class RemotingInvocationTimeoutScan implements Runnable {

        public void run() {
            while (true) {
                try {
                    for (DefaultFuture future : FUTURES.values()) {
                        if (future == null || future.isDone()) {
                            continue;
                        }
                        if (System.currentTimeMillis() - future.getStartTimestamp() > future.getTimeout()) {
                            // 1. create exception response.
                            Response timeoutResponse = new Response(future.getId());
                            // 2. set timeout status.
                            timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT);
                            timeoutResponse.setErrorMessage(future.getTimeoutMessage(true));
                            // 3. handle response.
                            DefaultFuture.received(future.getChannel(), timeoutResponse);
                        }
                    }
                    Thread.sleep(30);
                } catch (Throwable e) {
                   	// 4. catch exception
                    logger.error("Exception when scan the timeout invocation of remoting.", e);
                }
            }
        }
    }
  1. 排查过程

    1. 早上过来看监控,一台机器cpu突然在某个时刻使用率上去了,而且一直下不来了,看比列也是差不多是一个核满负载在跑;
    2. 登录到机器的console,top了下,发现某个Java进程的cpu直接100%;
    3. java -jar arthas-boot.jar {pid}运行,dashboard 查看进程的运行情况,然后就找到了RemotingInvocationTimeoutScan这个线程的cpu一直在100%,那就是这个线程导致了cpu突然飚上去了,可以用**thread {tid}**看到线程的执行栈,这样就可以清楚的知道dubbo源码中的执行流程;
    4. 然后就有开头的分析过程,代码中出现了异常,并且导致了死循环,由于服务器多核cpu,这个问题并没有导致我们的业务受到很大的影响,我们还没有找到是那个请求超时导致这个线程不能正常的运行下去了;
    5. 在测试环境我们模拟了这个服务所有请求rpc的调用的超时情况,找到了导致这个触发的原因。
  2. 解决方案,两个解决方案

    1. 找到触发dubbo控制的超时逻辑线程不能正常工作的原因,修复它;
    2. 直接升级dubbo的版本,高版本的已经处理了这个问题。

    我们暂时先选择了方案1。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值