推荐阅读:

阿里巴巴4面Java岗位:算法+性能调优+并发+多线程+数据库

Dubbo+Kafka+MyBatis+reids+Spring+多线程等,学完就去面试BAT

问题描述

  • 线上突然出现Dubbo超时调用,时间刚好为Consumer端设置的超时时间。
  • 有好几个不同的接口都报超时了
  • 第1次调用超时,第2次(或第3次)重试调用非常快(正常水平)
  • Dubbo调用超时的情况集中出现了3次,每次都是过一会自动恢复

排查

排查日志

看到调用超时,首先就拿着traceId去服务提供方查日志。 奇怪的是,在服务提供方的业务日志里面,只有正常的调用日志(耗时正常),没有超时调用的日志。 从正常的调用日志里面看,一切都是正常的,看不出所以然。 给人的感觉就是超时那次请求的调用没有达到服务提供方。

此时系统活动情况

通过系统历史监控,我们发现除了gc比平时稍微高一点外(也在正常水位),没有其他的异常;CPU、内存、网络等指标都在正常范围。

查看Dubbo线程活动情况

第2次系统集中超时报警的做的第一件事就是登录到那台服务器查看dubbo线程活动情况:看下能不能找到阻塞在哪一行代码。很遗憾,所有的dubbo线程都没有阻塞,都是正常的WAITING状态。

并没有明显表明阻塞在某段代码,这可难倒我们了:如果没有阻塞的话,为什么dubbo调用方会报超时?继续看代码

该接口是否存在阻塞的代码?

硬着头皮重新看代码每一个分支,突然发现底层的一个方法中有http调用!会不会是这个http调用导致的超时?如果是的话,那么不同的接口调用超时的情况就说的通了,因为上层大部分接口都会调用这个底层方法。

怀揣着激动的心,仔细看了http调用的逻辑:用的是JDK提供的HttpURLConnection,其中只用了HttpURLConnection#getContentLength方法,并且也在finally代码块中将这个连接关闭了。好像也不是这个引起的,起初还以为getContentLength会把文件给下载下来,但是看了接口文档以后发现只会去读头信息中的ContentLength。

    /**     * Returns the value of the {@code content-length} header field.     * 

* Note: {@link #getContentLengthLong() getContentLengthLong()} * should be preferred over this method, since it returns a {@code long} * instead and is therefore more portable.

* * @return the content length of the resource that this connection's URL * references, {@code -1} if the content length is not known, * or if the content length is greater than Integer.MAX_VALUE. */ public int getContentLength() { long l = getContentLengthLong(); if (l > Integer.MAX_VALUE) return -1; return (int) l; }

代码阻塞的情况可能性也不大,因为重试请求不会超时:如果代码阻塞,那么重试请求大概率也会超时。

数据访问层是否有异常情况

既然代码没有阻塞,那么有没有可能是数据访问层的异常造成的呢?毕竟不止一个接口存在超时的问题,如果是底层数据访问层的异常导致,那么也说得通。

重点排查了mysql,但结果是令人失望的:并没有慢SQL;并且dubbo超时期间,mysql实例的CPU和内存水位都是正常的。

除了mysql、redis实例本身指标正常外,基于上面同样的理由:如果数据访问层有问题,那么重试基本上也会超时。所以数据访问层导致超时的线索也被排除。

有没有可能是Dubbo层面的问题

排查再次陷入僵局,逼迫着我们重新梳理排查思路:

  1. 除了代码阻塞
  2. 除了数据访问层异常
  3. 除了超时请求,其他请求的日志都是正常的

那么还有可能会导致超时呢?会不会是Dubbo本身异常导致的?

此时有一个关键的线索进入我们的视野:超时的那次请求去哪儿了?

在服务提供方的日志里面没有超时请求的的日志,只有重试请求成功的业务日志。太奇怪了,就算超时总的留下日志的吧,日志都不留,欺负我胖虎吗?!

到这里想到超时的请求可能是一个突破口,于是开始看Dubbo的相关的源码和文档。

从官方文档中的服务端调用链一层层往下查

在AllChannelHandler源码中看到了令人兴奋的注释:

兴奋之余,为了避免理解偏差,还特地用百度翻译了一下

没错,如果线程池已经满了,那么服务端不会返回,直到客户端超时!这不是正式我们碰到的问题吗?! 并且此时还没有进入业务代码,所以没有打印业务日志,这样就可以解释为什么没有服务提供方没有超时请求的日志了。

别激动,这里明明有返回threadpool is exhausted异常信息,怎么能说没有返回呢? 别急,这是另外一个项目引用的dubbo,版本是2.6.2。 回到出问题的那个项目,查看dubbo版本:2.8.6,查看AllChannelHandler源码:是的在2.8.6版本中,并没有返回这个错误

问题好像找到了,OK,剩下的就是验证了。

验证

准备

  • 将DubboServerHandler线程池的最大线程数调到5
  • 使用Apache Bench进行压测:200请求、并发10个线程

case1:复现问题

  • Dubbo使用2.8.6版本
  • 预期:部分请求超时报错,重试耗时正常
  • 压测结果符合预期:部分接口报错超时,并且重试请求耗时正常

case2:验证猜想

  • Dubbo使用2.6.2版本
  • 预期:部分请求报错线程池耗尽threadpool is exhausted,并且重试大概率也会报该错误
  • 压测结果符合预期

至此,基本判定线上Dubbo调用超时的问题就是因为线程池耗尽引起的。

这个超时问题前前后后查了一周左右,排查过程中试了很多排查方向,为了叙述方便就没有展开。


避坑指南

  1. 合理设置Dubbo线程池大小。默认是200
  2. 合理设置超时时间。如果真出现了Dubbo调用超时的情况,合理的超时时间能够避免服务调用方被打爆
  3. Dubbo接口必须有返回值。从AllChannelHandler#received的源码和注释中可以看到只有有返回值的接口才会返回线程池耗尽的错误信息;其它的情况则不会将错误信息返回给调用方,直到调用方超时。

dubbo日志关闭_不可忽视的Dubbo线程池避坑指南相关推荐

  1. win10 SystemParametersInfo 设置屏保 不好使_[教程]win10 ,ubuntu双系统安装避坑指南

    这篇博客可以解决1.如何安装win10,ubuntu双系统2.如何使用win10引导Ubuntu,并且设置win10引导界面 点击阅读原文获取更多信息. win10,ubuntu双系统的安装 为什么要 ...

  2. dubbo官方文档_不可忽视的Dubbo线程池

    问题描述 线上突然出现Dubbo超时调用,时间刚好为Consumer端设置的超时时间. 有好几个不同的接口都报超时了 第1次调用超时,第2次(或第3次)重试调用非常快(正常水平) Dubbo调用超时的 ...

  3. dubbo 服务压测_不可忽视的Dubbo线程池

    问题描述 线上突然出现Dubbo超时调用,时间刚好为Consumer端设置的超时时间. 有好几个不同的接口都报超时了 第1次调用超时,第2次(或第3次)重试调用非常快(正常水平) Dubbo调用超时的 ...

  4. 线程池踩坑记 --load飙高的原因

    去年处理过一个美图的问题,最近又碰到类似问题了,发现跟美图那个案例原因是一样的,在这里拿出来给大家分享一下. 应该是去年6月底,我们私有化发布了新版本,然后就拿去给美图客户安装部署了,美图的美拍应用访 ...

  5. future.cancel不能关闭线程_彻底弄懂线程池-newFixedThreadPool实现线程池

    public class ExecutorServiceTest { public static void main(String[] args) throws IOException, Interr ...

  6. java 关闭阻塞线程池_如果优雅地关闭ExecutorService提供的java线程池

    每一个线程都会占用系统资源,因此线程池的关闭与清理同样重要,本文介绍我们如何优雅地关闭线程池. 一. ExecutorService中关闭线程池的方法 1. shutdown() 停止接收新任务,原来 ...

  7. mysql 线程池源码模块_易语言Mysql线程池2.0模块源码

    易语言Mysql线程池2.0模块源码 易语言Mysql线程池2.0模块源码 系统结构:GetThis,初始化,关闭类线程,线程_测试,其他_附加文本,连接池初始化,取mysql句柄,释放mysql句柄 ...

  8. main线程 子线程 顺序_面试官:线程池如何按照core、max、queue的执行顺序去执行?详解...

    前言 这是一个真实的面试题. 前几天一个朋友在群里分享了他刚刚面试候选者时问的问题:"线程池如何按照core.max.queue的执行循序去执行?". 我们都知道线程池中代码执行顺 ...

  9. hystrix 源码 线程池隔离_基于hystrix的线程池隔离

    hystrix进行资源隔离,其实是提供了一个抽象,叫做command,就是说,你如果要把对某一个依赖服务的所有调用请求,全部隔离在同一份资源池内 对这个依赖服务的所有调用请求,全部走这个资源池内的资源 ...

最新文章

  1. 包含锚点平滑滚动效果/解决锚点链接碰到固定定位问题/导航选中背景变色/固顶/返回顶部效果全...
  2. python定义全局变量
  3. 用偷梁换柱法清除腾讯QQ迷你首页的方法
  4. 百度吹过的牛实现了,你的呢?5本书带你搞定AI前沿技术
  5. [转]IIS的各种身份验证详细测试
  6. 【JVM】垃圾回收器
  7. 杨凌职业技术学院计算机专业宿舍,杨凌职业技术学院宿舍条件怎么样
  8. 24有几种封装尺寸_mmWave设备的封装应该如何处理
  9. swagger3 设置值可以为空_swagger3.0使用及https问题处理
  10. Atitit easyui翻页组件与vue的集成解决方案attilax总结
  11. cisco路由器OSPF基础配置命令
  12. linux把终端嵌入桌面,在你的Ubuntu Linux桌面上嵌入终端窗口
  13. Android平板的磁盘分区,平板电脑硬盘分区 Original Pad到PC:教您将Win10安装到Android平台...
  14. 30个编程领域的趣图
  15. android+ts+播放器,开源播放器ijkplayer的编译
  16. 计算机参数含义,电脑内存条参数各有什么含义?
  17. 个人微信公众号对接自动回复电影网站接口又能实现菜单功能
  18. 流行的几种世界观来源
  19. 电商女装评论数据集分析
  20. 数据分析 第三讲 matplotlib常用统计图

热门文章

  1. jQuery获取url地址
  2. 面向对象设计的六大原则简介
  3. 关于c++中运算符的总结
  4. Spring+SpringMVC+MyBatis+Maven框架整合
  5. tornado异步客户端(Future)
  6. Javascript 调用百度地图不显示
  7. Android 图片缩略图显示
  8. secucrecrt配置文件导入和保存
  9. 关于虚拟化 云计算
  10. 关于 LDTP 操纵 windows 控件。