收到报警,dubbo调用有5w多次失败的,找到开始报错的时间点,搜业务日志发现线程池耗尽了。

再看业务日志,有调个推超时的日志,但看不出来到底是超时多久,然后翻开代码看个推客户端源码;

可以通过 

System.setProperty("gexin_http_connecton_timeout","自定义请求连接超时时间(单位毫秒),默认60秒");  //定义连接超时时间

System.setProperty("gexin_http_so_timeout","1000");  //设置读超时时间

但如何验证是否生效呢,设置较小的超时时间,看是否复现read timed out异常?

首先查看个推接口的时间消耗,连接建立,读数据时间等等

while 1>0;do /usr/bin/curl -o /dev/null -s -m 20 -w "%{time_namelookup}::%{time_connect}::%{time_appconnect}::%{time_starttransfer}::%{time_total}::%{http_code}\n" "http://sdk.open.api.igexin.com/apiex.htm";done

(1)time_namelookup: DNS解析时间
(2)time_connect:TCP 连接建立的时间,就是三次握手的时间 ,计算方式:time_connect - (3)time_namelookup 
(4)time_appconnect:SSL/SSH 等上层协议建立连接的时间,比如 connect/handshake 的时间
(7)time_starttransfer: 从请求开始到第一个字节将要传输的时间

没有使用System.setProperty之前

第一次稍微慢些:

后面就快了

设置完System.setProperty 超时时间之后,连接超时1毫秒,读超时30毫秒,但感觉没起作用呢

原来个推的sdk里httpclient是一个static对象,第一次初始化时的超时时间一旦设置了,后面用的是map里缓存的对象执行操作,后面设置就无效了;

        重启java进程,发现推送线程好像停了,只能输出开始,没有结束日志,奇不奇怪!服务器上测试不行,只能本地debug打开 dubbo直连方式(dubbo调用方通过指定url='127.0.0.1:dubbo服务提供者端口' 看看到底堵塞在哪儿

这里是dubbo提供者的日志,没有任何异常...

下面2个图是dubbo调用方收到的异常

在看sdk的源码,发现httpclient里的重试次数必须大于0,否则会抛出异常

但为什么抛出的这个异常没有try catch(Exception e)捕获到呢?反而异常输出到调用方的日志里了?但日志里捕获异常这块为什么没输出日志呢?导致以为程序卡死

dubbo提供方下方源码捕获Exception没有输出...

dubbo调用方拿到了异常,但实际上本地测试的时候dubbo调用方拿到的是个error错误,而error就没法通过try Exception捕获到,需要改成throwable

果然改成Throwable可以看到e就是一个Error而不是源码里的那个IllegalArgumentException,可能个推的sdk源码里还有其他代理层封装吧

那明明初始化GtHttpClient的时候抛出的是IllegalArgumentException  怎么变成 ExceptionInInitializerError了?

原来这个类的对象是static类型的,static类型对象如果初始化中发生了异常,不管是什么异常最终都会封装成ExceptionInInitailizerError。

         ExceptionInInitializerError是Java中的一个错误(Error),它表示在静态初始化块或者静态变量初始化期间发生了异常。这个错误通常是因为在类加载的过程中,当执行静态代码块(使用static {}包围的代码部分)或者初始化静态变量时抛出了异常。例如,在初始化一个静态变量时可能会出现空指针异常(NullPointerException)、算术异常(ArithmeticException)等,这些异常会被包装在ExceptionInInitializerError中抛出

至此所有疑惑都得到了验证,困扰了2,3天也算有个圆满结束了。。。

附:java异常的继承关系

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐