一份十分完整的CPU 100%排查优化指南

  • 发布时间:2019-04-30 10:55
  • 来源:九卅娱乐app下载

最近又收到了运维报警:表示有些服务器负载非常高,让我们定位问题。 还真是想什么来什么,前些天还故意把某些服务器的负载提高(没错,老板让我写个Bug!),不过还好是不同的环境,互相没有影响。 拿到问题后首先去服务器上看了看,发现运行的只有我们的Java应用。 于是先用PS命令拿到了应用的PID。 接着使用top-Hppid将这个进程的线程显示出来。

输入大写的P可以将线程按照CPU使用比例排序,于是得到以下结果:果然某些线程的CPU使用率非常高。

为了方便定位问题我立马使用将线程栈Dump到日志文件中。 我在上面100%的线程中随机选了一个pid=194283转换为16进制(2f6eb)后在线程快照中查询,因为线程快照中线程ID都是16进制存放。 发现这是Disruptor的一个堆栈,前段时间正好解决过一个由于Disruptor队列引起的一次OOM,没想到又来一出。 为了更加直观的查看线程的状态信息,我将快照信息上传到专门分析的平台上:http:///其中有一项菜单展示了所有消耗CPU的线程,我仔细看了下发现几乎都是和上面的堆栈一样。 也就是说都是Disruptor队列的堆栈,同时都在执行函数。 众所周知yield函数会让当前线程让出CPU资源,再让其他线程来竞争。

根据刚才的线程快照发现处于Runnable状态并且都在执行yield函数的线程大概有30几个。

因此初步判断为大量线程执行yield函数之后互相竞争导致CPU使用率增高,而通过对堆栈发现是和使用Disruptor有关。

而后我查看了代码,发现是根据每一个业务场景在内部都会使用2个Disruptor队列来解耦。 假设现在有7个业务类型,那就等于是创建2*7=14个Disruptor队列,同时每个队列有一个消费者,也就是总共有14个消费者(生产环境更多)。 同时发现配置的消费等待策略为YieldingWaitStrategy这种等待策略确实会执行yield来让出CPU。 代码如下:初步看来和这个等待策略有很大的关系。 为了验证,我在本地创建了15个Disruptor队列同时结合监控观察CPU的使用情况。