几年前的一个下午 , 公司里码农们正在安静地敲着代码 , 突然很多人的手机同时“哔哔”地响了起来 。本来以为发工资了 , 都挺高兴!打开一看 , 原来是告警短信 。
文章插图
图片来自 Pexels
故障回顾
告警提示“线程数过多 , 超出阈值” , “CPU 空闲率太低” 。打开监控系统一看 , 订单服务所有 20 个服务节点都不行了 , 服务没响应 。
查看监控(一个全链路性能监控工具) , 每个 Spring Boot 节点线程数全都达到了最大值 。但是 JVM 堆内存和 GC 没有明显异常 。
CPU 空闲率基本都是 0% , 但是 CPU 使用率并不高 , 反而 IO 等待却非常高 。
下面是执行 top 命令查看 CPU 状况的截图:
文章插图
从上图 , 我们可以看到:
- CPU 空闲率是 0%(上图中红框 id) 。
- CPU 使用率是 22%(上图中红框 us 13% 加上 sy 9% , us 可以理解成用户进程占用的 CPU , sy 可以理解成系统进程占用的 CPU) 。
- CPU 在等待磁盘 IO 操作上花费的时间占比是 76.6% (上图中红框 wa) 。
大量的磁盘读写导致了系统线程资源耗尽 , 最终导致订单服务无法响应上游服务的请求 。
IO , 你不知道的那些事儿
既然 IO 对系统性能和稳定性影响这么大 , 我们就来深入探究一下 。
所谓的 I/O(Input/Output)操作实际上就是输入输出的数据传输行为 。程序员最关注的主要是磁盘 IO 和网络 IO , 因为这两个 IO 操作和应用程序的关系最直接最紧密 。
磁盘 IO:磁盘的输入输出 , 比如磁盘和内存之间的数据传输;网络 IO:不同系统间跨网络的数据传输 , 比如两个系统间的远程接口调用 。
下面这张图展示了应用程序中发生 IO 的具体场景:
文章插图
通过上图 , 我们可以了解到 IO 操作发生的具体场景 。一个请求过程可能会发生很多次的 IO 操作:
- 页面请求到服务器会发生网络 IO 。
- 服务之间远程调用会发生网络 IO 。
- 应用程序访问数据库会发生网络 IO 。
- 数据库查询或者写入数据会发生磁盘 IO 。
不少攻城狮会这样理解 , 如果 CPU 空闲率是 0% , 就代表 CPU 已经在满负荷工作 , 没精力再处理其他任务了 。真是这样的吗?
我们先看一下计算机是怎么管理磁盘 IO 操作的 。计算机发展早期 , 磁盘和内存的数据传输是由 CPU 控制的 , 也就是说从磁盘读取数据到内存中 , 是需要 CPU 存储和转发的 , 期间 CPU 一直会被占用 。
我们知道磁盘的读写速度远远比不上 CPU 的运转速度 。这样在传输数据时就会占用大量 CPU 资源 , 造成 CPU 资源严重浪费 。
后来有人设计了一个 IO 控制器 , 专门控制磁盘 IO 。当发生磁盘和内存间的数据传输前 , CPU 会给 IO 控制器发送指令 , 让 IO 控制器负责数据传输操作 , 数据传输完 IO 控制器再通知 CPU 。
因此 , 从磁盘读取数据到内存的过程就不再需要 CPU 参与了 , CPU 可以空出来处理其他事情 , 大大提高了 CPU 利用率 。
这个 IO 控制器就是“DMA” , 即直接内存访问 , Direct Memory Access 。现在的计算机基本都采用这种 DMA 模式进行数据传输 。
文章插图
通过上面内容我们了解到 , IO 数据传输时 , 是不占用 CPU 的 。
当应用进程或线程发生 IO 等待时 , CPU 会及时释放相应的时间片资源并把时间片分配给其他进程或线程使用 , 从而使 CPU 资源得到充分利用 。
所以 , 假如 CPU 大部分消耗在 IO 等待(wa)上时 , 即便 CPU 空闲率(id)是 0% , 也并不意味着 CPU 资源完全耗尽了 , 如果有新的任务来了 , CPU 仍然有精力执行任务 。
推荐阅读
- 深圳|总投资3.6万亿!深圳2022重大项目曝光:两大先进芯片厂在列
- 猪肉没了儿时的味道,问题在这儿……
- 交通事故鉴定申请书需要什么材料
- 发生交通事故后如何赔付?30个问题一篇讲清!
- 微信小程序直播功能开通及小程序直播常见问题解答!
- 怎样避免ios开发者账号封禁问题
- 世界上最难去的10个国家和地区,迈过这些坎,周游世界就不是问题
- 罚0元记0分?这样的罚单不管它,问题会很大!
- 什么是缓存一致性问题?如何解决呢?
- 彻底解决MySQL中的乱码问题