当前位置: 首页 > news >正文

慢半拍的 Flink TaskManager——问题不在代码中

背景

用户发现自己的 flink程序出现多个TaskManager cpu使用率相差 10%的现象。
他们排除了数据差异,TaskManager基本都是相似结构的数据,程序处理起来不会有这么大的区别。
期待我找出原因,这样方便用户规划规模和扩量。

排查历程

60 秒快速扫描

用户做了基本的自查,但是并不能作为排查进行的证据,先把 flink 的运行指标汇聚到一起进行快速了解。可以看到如下的内容。

  1. 多个TaskManager cpu使用率出现恒定高低变化。高的一直高,低的一直低。
  2. 高 cpu使用率的heap 内存占用比低cpu 使用率的高。
  3. 高 cpu使用率的gc 次数比低cpu 使用率的多。
  4. 两者线程数相同。

这里看到内存和 gc 有差异,flink 本身没有心跳超时表现,直接忽略 gc 时延的影响。转换成gc吞吐,两者都是 90 左右,影响不大,不存在吞吐太低拉长运行时长的情况,说明这个现象是状态下的结果,不是原因。
gc 吞吐的公式如下:

GC吞吐量 = (总时间 - GC总耗时) / 总时间 × 100%

jmx 和 gc日志都可以计算出吞吐量,只是精度问题,日常用jmx 即可,并不是只有 gc日志才能计算。

profiling

经过快速扫描,排除了简单的问题场景。cpu 的使用率变化还可能是程序代码本身带来的,例如不同的分支处理逻辑不一样。用户代码也是多人开发,可能存在理解和实际运行不一致的情况。
我们用 jdk 自带的 jfr 进行 oncpu 采集分析,看看高cpu和低 cpu 使用率堆栈上的差异。

jcmd pid JFR.start duration=2m filename=/tmp/my.jfr

上面是一个采集 2min 的命令。拿到文件先快速统计一下事件差异。这里可以利用jdk 自带的 jfr命令统计。

jfr summary my.jfr

cpu使用率高的进程采样次数为

jdk.ExecutionSample 4261

cpu 使用率低的进程采样次数为

jdk.ExecutionSample 3773

jdk.ExecutionSample只会采集 java代码的堆栈,也就是说 cpu 使用率高的程序采样到的 oncpu 的java 代码多。我们需要分析代码上的差异。jfr 的可视化不好,可以使用我的火焰图转换工具。
# JFR转化火焰图工具

经过做火焰图的差分对比,发现没有代码路径上的差异,堆栈调用基本是等比率增长。

排查 jit

等比率增长的情况下说明问题已经不是编写出的 java 代码本身了。怀疑热点的代码是否是编译出了相同的机器码。可能是 jit 出来的代码效率不高,导致代码跑起来性能不好,相同的 cpu 使用率下执行的代码处理的数据少。
没有提前开启打印 jit 的参数,我们选择 jcmd 导出正在运行的编译情况。

jcmd pid Compiler.codelist

这里导出的数据很多,需要保存到一个文件中。我们可以看到如下内容

33566 3 2 org.jsoup.parser.HtmlTreeBuilderState$7.inBodyStartTag(Lorg/jsoup/parser/Token;Lorg/jsoup/parser/HtmlTreeBuilder;)Z [0x00007f55b3ba7190, 0x00007f55b3ba8d60 - 0x00007f55b3bb9e58]

这里需要重点看的是第二列,表示编译等级。

Level编译器特点
0解释器无编译,纯解释执行
1C1无 profiling,快速轻量编译
2C1轻量 profiling,收集基本调用信息
3C1完整 profiling,收集方法计数、类型统计等
4C2最高优化级别,基于 level 3 收集的 profiling 数据做激进优化
通过对比火焰图的热点方法,发现热点方法的编译等级基本是一样的。jdk 也是相同版本,及时编译出的代码区别不大。

排查cpu

虚拟机层已经排除完了,最大可能就是 2 个机器上 cpu 执行相同的代码本身有差异。我们使用 perf stat 快速统计。可以看到如下的结果:
cpu 使用率高的cycles如下,频率是2.545 GHz

1,809,708,584 cycles # 2.545 GHz

cpu 使用率低的cycles如下,频率是3.055 GHz

2,003,433,272 cycles # 3.055 GHz

可以发现两个机器的频率差异比较大。这里破案了,频率高的机器执行的速度快,从 cpu 使用率低角度看on cpu 的时间少,使用率低。
这里协调了运维把低频机器剔除,TaskManager的表现基本一致了。

总结

回头看这个排查过程,从 Flink 指标面板一路追到 CPU 频率。
堆内存和 GC 次数的差异是「高频低利用率」和「低频高利用率」的副产品,不是原因。很多人走到这里就会开始调 GC 参数,试图让两边的内存曲线对齐。但方向已经错了。
火焰图差分显示热点代码等比率增长,说明不是某条分支路径在拖后腿。JIT 编译等级一样,JDK 版本一样,应用层和 JVM 层已经排除。
最后两行perf stat的输出摆在面前——2.545 GHz vs 3.055 GHz,差距接近 20%。频率低的机器跑同样的指令,要花更多的 CPU 时间。我们看到的10% 的 CPU 使用率差异,根因就在这里。
CPU 使用率本质上是一段时间内 CPU 处于非空闲状态的时间占比,无法表达程序处理的快慢。

相关链接

http://www.cnnetsun.cn/news/3009945.html

相关文章:

  • AI转行不晚:从问题闭环到能力锚点的实战路径
  • 电商评论情感分析驱动的内容推荐系统实战
  • 【从零开始学架构:业务思考】像架构师一样思考:从业务价值出发
  • 海尔智家回报股东:回购是去年5倍,注销是去年10倍
  • 2轴舵机控制板
  • 第6篇:《串口长线乱码排查:TTL电平传5米,信号反射振铃全波形分析》
  • 偏相关系数的计算
  • 软件部署中的持续交付流水线建设
  • 【Java踩坑笔记】【基础语法篇】05_重写equals不重写hashCode会怎样?
  • windows安装Claude
  • Vue 2 vs Vue 3:核心特性与差异全解析
  • UE5.6 GAS学习笔记(2)-->GA篇 [2.分析GA类基本内容]
  • .NET开发者集成YOLO目标检测:yolodotnet实战指南
  • 2026实测|个人免费AI编程工具全对比,vibe coding副业开发者必看
  • 铁电MEMS突触技术:神经形态计算新突破
  • 国企央企官网的工程化设计:多专题内容管理、安全合规与无障碍实现
  • 当智能体真正走进办公室,它的成绩单好看吗?
  • 高阶03:国产EAP vs 进口Applied EAP全维度对比与迁移改造
  • Hermes 上手指南:真实开发里的落地路径
  • Plotly实现印度数字体系(Lac/Crore)数据可视化
  • Agent可,使由之;不可,使知之。
  • Keras Functional API:构建多输入多输出复杂模型的工程实践
  • 一文彻底搞懂 Loop Engineering
  • 2026实测|Claude Code平价替代深度对比,国产AI原生IDE平替方案
  • 从Swagger/HAR到JMeter脚本:构建自动化性能测试工具链的工程实践
  • TypeScript的类型推断:infer关键字的强大能力
  • 如何用genshin-fps-unlock突破原神60帧限制:技术原理与实战指南
  • SimCLRv2:工业级自监督预训练落地实践指南
  • XUnity自动翻译器终极指南:5分钟实现Unity游戏无障碍本地化
  • MCU与DSP融合:56F8000 DSC在数字电源与电机控制中的实战解析