
这篇文章描述了因为进程/单线程cpu瓶颈,导致Flink任务延迟的案例,并且分享了从最开始平台工作人员手动去服务器帮用户诊断,再到如何赋能给用户自助诊断的过程。
- 案例一:是TaskManager进程cpu使用率达到瓶颈的案例 (如果读者生产环境未开启cgroup可以跳过这个案例)
- 案例二:是TaskManager中某些线程的cpu使用率到达瓶颈的案例
案例一: 单TaskManager进程的CPU使用率瓶颈导致的任务延迟
现象及解决方案 :
平台上Flink任务延迟,最初我们通过去服务器上使用top + TaskManager的进程id命令,查看TaskManager的CPU使用率是否到达瓶颈。
- 如果到达瓶颈,这个任务可能是cpu密集型的任务,引导用户:
- 增加Flink任务的cpu核数或者并行度
- 通过火焰图之类的工具分析代码是否需要优化
- 查看任务是否fullgc (fullgc会占用很多cpu资源)
- 如果未到达瓶颈,这个任务可能是io密集型的任务,引导用户:
- 保持cpu核数不变,增加并行度,观察是否改善
自助诊断方案 :
提供用户TaskManager进程的cpu使用率 Metric,方便其自助分析任务是 cpu/io 密集型任务 ,进一步优化代码/任务资源。
具体实现 :
添加cpu使用率metric
方案: 一段时间内的 cpu使用时间/程序运行时间

上报cpu核数metric
Flink任务在多核环境运行,所以步骤一上报的cpu使用率metric数值经常都是>100%,需要除以CPU核数才能以0%-100%更加直观地观察cpu使用率。一般情况从Flink配置
yarn.containers.vcores读取cpu核数上报metric即可。之家这边实现了自动伸缩容功能,TaskManager的cpu核数有可能会有变化。这边的方案是在申请TaskManager Container时,把cpu核数存到TaskManager的环境变量中。TaskManager启动后从环境变量获取cpu核数后上报metric即可。

最后配个将步骤1和步骤2的metric相除即可

案例二 :TaskManager 中某个线程cpu使用率瓶颈导致任务延迟
现象
top -Hp TaskManager进程号
TaskManager进程cpu使用率未耗尽,但是单线程的cpu使用率已到瓶颈。
printf '%x\n' 8845获取其线程对应系统的16进制进程号
jstack -l TaskManager 进程号 |grep 228d定位到这个线程

- 通过火焰图发现消耗cpu的方法是这个udf

解决方案
- 优化udf
- 还可以拆开个线程这行逻辑到多个线程
- 添加并行度
自助诊断方案:
扩展个Flink的rest接口,集成到平台,方便用户可以自助去查询TaskManager进程中cpu占用较高的线程。可以借鉴JVM诊断神器arthas的 thread -n 命令实现


原理: 采样一段时间 JVM每个线程的cpu使用时间 除以 这段JVM程序的运行时间 ,最终再排序 获取top n 。
平台上查看 top 5线程使用率及线程栈详情

