点击上方“方志朋”,选择“置顶或者星标”

你的关注意义重大!

本文转载于公众号 crossoverJie

前言

到了年底果然都不太平,最近又收到了运维报警:表示有些服务器负载非常高,让我们定位问题。

还真是想什么来什么,前些天还故意把某些服务器的负载提高(没错,老板让我写个 BUG!),不过还好是不同的环境互相没有影响。

定位问题

拿到问题后首先去服务器上看了看,发现运行的只有我们的 Java 应用。于是先用 ps 命令拿到了应用的 PID

接着使用 ps-Hppid 将这个进程的线程显示出来。输入大写的 P 可以将线程按照 CPU 使用比例排序,于是得到以下结果。

果然某些线程的 CPU 使用率非常高。

为了方便定位问题我立马使用 jstack pid>pid.log 将线程栈 dump 到日志文件中。

我在上面 100% 的线程中随机选了一个 pid=194283 转换为 16 进制(2f6eb)后在线程快照中查询:

因为线程快照中线程 ID 都是16进制存放。

发现这是 Disruptor 的一个堆栈,前段时间正好解决过一个由于 Disruptor 队列引起的一次 OOM:强如 Disruptor 也发生内存溢出?

没想到又来一出。

为了更加直观的查看线程的状态信息,我将快照信息上传到专门分析的平台上。

http://fastthread.io/

其中有一项菜单展示了所有消耗 CPU 的线程,我仔细看了下发现几乎都是和上面的堆栈一样。

也就是说都是 Disruptor 队列的堆栈,同时都在执行 java.lang.Thread.yield 函数。

众所周知 yield 函数会让当前线程让出 CPU 资源,再让其他线程来竞争。

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

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

解决问题

而后我查看了代码,发现是根据每一个业务场景在内部都会使用 2 个 Disruptor 队列来解耦。

假设现在有 7 个业务类型,那就等于是创建 2*7=14Disruptor 队列,同时每个队列有一个消费者,也就是总共有 14 个消费者(生产环境更多)。

同时发现配置的消费等待策略为 YieldingWaitStrategy 这种等待策略确实会执行 yield 来让出 CPU。

代码如下:

初步看来和这个等待策略有很大的关系。

本地模拟

为了验证,我在本地创建了 15 个 Disruptor 队列同时结合监控观察 CPU 的使用情况。

创建了 15 个 Disruptor 队列,同时每个队列都用线程池来往 Disruptor队列 里面发送 100W 条数据。

消费程序仅仅只是打印一下。

跑了一段时间发现 CPU 使用率确实很高。


同时 dump 线程发现和生产的现象也是一致的:消费线程都处于 RUNNABLE 状态,同时都在执行 yield

通过查询 Disruptor 官方文档发现:

YieldingWaitStrategy 是一种充分压榨 CPU 的策略,使用 自旋+yield的方式来提高性能。 当消费线程(Event Handler threads)的数量小于 CPU 核心数时推荐使用该策略。


同时查阅到其他的等待策略 BlockingWaitStrategy (也是默认的策略),它使用的是锁的机制,对 CPU 的使用率不高。

于是在和之前同样的条件下将等待策略换为 BlockingWaitStrategy


和刚才的 CPU 对比会发现到后面使用率的会有明显的降低;同时 dump 线程后会发现大部分线程都处于 waiting 状态。

优化解决

看样子将等待策略换为 BlockingWaitStrategy 可以减缓 CPU 的使用,

但留意到官方对 YieldingWaitStrategy 的描述里谈道: 当消费线程(Event Handler threads)的数量小于 CPU 核心数时推荐使用该策略。

而现有的使用场景很明显消费线程数已经大大的超过了核心 CPU 数了,因为我的使用方式是一个 Disruptor队列一个消费者,所以我将队列调整为只有 1 个再试试(策略依然是 YieldingWaitStrategy)。

跑了一分钟,发现 CPU 的使用率一直都比较平稳而且不高。

总结

所以排查到此可以有一个结论了,想要根本解决这个问题需要将我们现有的业务拆分;现在是一个应用里同时处理了 N 个业务,每个业务都会使用好几个 Disruptor 队列。

由于是在一台服务器上运行,所以 CPU 资源都是共享的,这就会导致 CPU 的使用率居高不下。

所以我们的调整方式如下:

  • 为了快速缓解这个问题,先将等待策略换为 BlockingWaitStrategy,可以有效降低 CPU 的使用率(业务上也还能接受)。

  • 第二步就需要将应用拆分(上文模拟的一个 Disruptor 队列),一个应用处理一种业务类型;然后分别单独部署,这样也可以互相隔离互不影响。

当然还有其他的一些优化,因为这也是一个老系统了,这次 dump 线程居然发现创建了 800+ 的线程。

创建线程池的方式也是核心线程数、最大线程数是一样的,导致一些空闲的线程也得不到回收;这样会有很多无意义的资源消耗。

所以也会结合业务将创建线程池的方式调整一下,将线程数降下来,尽量的物尽其用。

本文的演示代码已上传至 GitHub:

https://github.com/crossoverJie/JCSprout

-更多文章-

Spring AOP 增强框架 Nepxion Matrix 详解

一个故事讲清楚NIO

现身说法:37岁老码农找工作

线程池的工作原理与源码解读

-关注我-


http://www.taodudu.cc/news/show-123283.html

相关文章:

  • Java中锁的分类
  • Java并发编程73道面试题及答案——稳了
  • 2018年文章汇总
  • CopyOnWriteArrayList实现原理及源码分析
  • 数据库分库分表,何时分?怎样分?
  • Spring Boot Admin 2.1.0 全攻略
  • Spring Cloud 随笔:记录在使用 OAuth2 遇到的巨坑
  • 阿里分布式事务框架GTS开源了!
  • 当CPU飙高时,它在做什么
  • Redis 为什么这么快?
  • 如何合理地估算线程池大小?
  • 『浅入浅出』MySQL 和 InnoDB
  • 谈 Kubernetes 的架构设计与实现原理
  • 浅析几种线程安全模型
  • Spring AOP是什么?你都拿它做什么?
  • 面试被问烂的 Spring IOC(求求你别再问了)
  • SpringMVC工作原理详解
  • Spring Cloud Greenwich版本已发布!
  • 好文推荐,15 分钟教你搞懂 Git!
  • 小说:白话幂等性设计
  • MongoDB是个好东西,希望你也会
  • 为了效率,扎克伯格的26张PPT
  • MAT入门到精通(二)
  • 这 10 款插件让你的 GitHub 更好用、更有趣
  • spring cloud config将配置存储在数据库中
  • 刚出炉的一套面试题(JAVA岗)
  • 聊聊 SpringCloud 中的父子容器
  • 再有人问你Netty是什么,就把这篇文章发给他
  • 这 10 道 Spring Boot 常见面试题你需要了解下
  • 面试季,Java中的static关键字解析

一次生产 CPU 100% 排查优化实践相关推荐

  1. CPU 100%排查及常见案例

    CPU 100%排查及常见案例 这篇文章主要分享一般线上项目遇到CPU%时排查的方式,并提供了几个典型案例来帮助大家熟悉排查过程,我会先以 "死循环" 为例子来为大家演示一遍整体的 ...

  2. java线程死锁 cpu 100%_Java死锁排查和Java CPU 100% 排查的步骤整理

    工欲善其事,必先利其器 简介 本篇整理两个排查问题的简单技巧,一个是java死锁排查,这个一般在面试的时会问到,如果没有写多线程的话,实际中遇到的机会不多:第二个是java cpu 100%排查,这个 ...

  3. 数据库周刊54丨2020 年度报告:PingCAP、腾讯云数据库、人大金仓、GoldenDB ;CPU 100% SQL优化案例;Mysql内存溢出处理;避免删库跑路黑天鹅……

    热门资讯 [1.PingCAP 2020 年度报告|相信开放的力量 [摘要]本文为PingCAP 2020年度报告.盘点了PingCAP里程碑大事件:完成D轮2.7亿美元融资,创造全球数据库历史新的里 ...

  4. Java死锁和Java进程Java CPU 100%排查

    三板斧:top -> top -Hp ->jstack 通过 top 命令找到 CPU 消耗最多的进程号: 通过 top -Hp 进程号 命令找到 CPU 消耗最多的线程号(列名仍然为 P ...

  5. 爱奇艺视频千万级生产 Kubernetes 集群优化实践!

    本文介绍爱奇艺针对视频生产场景.在 Kubernetes(以下简称 K8s) 集群优化方面的实践:如何使高优先级任务获得更多的 CPU 资源,更快完成任务. 01    背景 视频生产集群所面临的一个 ...

  6. 高cpu_再一次生产 CPU 高负载排查实践

    (给ImportNew加星标,提高Java技能) 作者:crossoverJie segmentfault.com/a/1190000019507028 前言 前几日早上打开邮箱收到一封监控报警邮件: ...

  7. java获取cpu使用率_再一次生产 CPU 高负载排查实践

    前言 前几日早上打开邮箱收到一封监控报警邮件:某某 ip 服务器 CPU 负载较高,请研发尽快排查解决,发送时间正好是凌晨. 其实早在去年我也处理过类似的问题,并记录下来:<一次生产 CPU 1 ...

  8. qt获取cpu使用率_又一次生产 CPU 高负载排查实践

    以下文章来源于crossoverJie ,作者crossoverJie 前言 前几日早上打开邮箱收到一封监控报警邮件:某某 ip 服务器 CPU 负载较高,请研发尽快排查解决,发送时间正好是凌晨. 其 ...

  9. java线程死锁 cpu 100%_一文学会Java死锁和CPU 100% 问题的排查技巧

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开 工欲善其事,必先利其器 00 本文简介 作为一名搞技术的程序猿或者是攻城狮,想必你应该是对下面这两个问题有所了解,说不定你在 ...

最新文章

  1. Leangoo领歌敏捷项目管理工具新增测试管理功能
  2. Java源码详解五:ArrayList源码分析--openjdk java 11源码
  3. Linux kernel 不输出log信息
  4. 地址引用PHP,浅谈PHP变量作用域以及地址引用问题
  5. 一本很好的书LearnOpenGL
  6. ELK学习3_使用redis+logstash+elasticsearch+kibana快速搭建日志平台
  7. Git分支操作命令:删除与恢复
  8. 数值的加减会改变python中id,在python中调用Nan值并更改为数字
  9. TestNG或JUnit
  10. 加密服务器显示到期,注册加密卡成功了,打开软件还是提示演示到期了,怎么解决?...
  11. 希望直接访问系统内某个链接,跳过登录验证等过程
  12. 电脑排行榜笔记本_2019联想笔记本电脑排行榜
  13. 关于提高网站性能的几点建议(二)
  14. 一起学习Spring boot 2.1.X | 第十五篇:登陆拦截器
  15. debugger工具的使用以及调试
  16. Spring Boot整合Admin
  17. 调节阀振动原因分析及解决方案
  18. 小白的proxmox ve(pve)打造AIO(all in boom)折腾日记 (二)装机篇(爱国者m2装机不完全教程)
  19. javaweb复习笔记总结
  20. mysql kv_KV数据存储:持久化

热门文章

  1. python学习笔记(一)之入门
  2. spine - unity3D(摘自博主softimagewht)
  3. Android Java使用JavaMail API发送和接收邮件的代码示例
  4. LeetCode Add Binary
  5. 让VirtualBox的虚拟机器在电脑开机时自动启动
  6. 【组队学习】【30期】6. 树模型与集成学习
  7. 技术图文:01 面向对象设计原则
  8. Numpy入门教程:练习作业02
  9. LeetCode刷题-8
  10. Pandas 多层级索引的数据分析案例,超干货!