背景

 简单的系统架构图如下,核心代码在service action模块当中,其中service action是一个通过java的ExecutorService实现并发的多任务处理,在单个任务当中做的主要包括3大块:分别是大量for循环计算fastjson反序列化大量的Double.parsedouble计算

解决思路

 其实在整个问题排查过程中,我们也是摸着石头过河,把一个个的性能损耗的代码逐个排除。整个解决思路大概是下面这样一个过程:

  • 减少不必要的for循环,我们把从数据源头上限制了for循环次数,但优化效果有限。
  • 减少不必要的fastjson反序列化,但优化效果也同样有限。
  • 剩下的代码逻辑只有大量的并发的Double.parseDouble的计算逻辑,剩下的唯一怀疑对象。
  • 在​​dalelane​​的链接上找到了这个问题的原因,概括来说就是在jdk1.7下并发的大量Double.parseDouble操作会引起锁竞争引起连锁性能问题。
  • 这句话是为了SEO优化,本质上Double.parseDouble在单次调用下性能非常客观,但是在多线程并发调用的情况下会因为lock锁竞争机制导致速度非常慢,而且这个问题只在jdk1.7上才出现,在jdk1.8上已经修复解决了。

jdk1.7下Double.parseDouble性能问题排查_sed

jdk1.7下Double.parseDouble性能问题排查_for循环_02

发现问题

    本质解决问题的前提是需要发现问题,而我之所以遇到这个问题是因为我想可视化内部系统调用耗时,也是出于这个目的我引入Hystrix这个熔断神器用来发现超时问题。
 众所周知dubbo服务可以在provider配置超时限制,但是从provider的角度来说很难知道自己内部的耗时详情,所以在dubbo的filter层当中引入Hystrix的超时机制,Hystrix设置超时后可以对外服务时候实现超时提前结束请求,内部其实还是在继续执行的,所以我详细记录了每个超时范围内的请求个数,从而可以明确的知道耗时情况,然后发现问题并准备解决。
 让整个执行过程可视化是一个很好且很实用的原则。

优化效果

 性能直接提升50%,以下图中可以看出耗时基本腰斩(40ms降到20ms),超时次数跌0.

jdk1.7下Double.parseDouble性能问题排查_for循环_03

参考:​​​http://dalelane.co.uk/blog/?p=2936​