2、性能基准与瓶颈分析:吞吐量、延迟、资源利用率、常见的性能瓶颈
性能调优这件事,说白了就是先搞清楚「现在跑得怎么样」,再找到「哪里拖了后腿」。我见过太多团队一上来就改配置、换框架,结果折腾半天发现瓶颈根本不在那。所以这一章,咱们先把基本功打扎实——怎么测、怎么看、怎么定位。
2.1 三个核心指标:吞吐量、延迟、资源利用率
做数据摄取,你盯住这三个数就够了。其他的指标,基本都是它们的衍生。
| 指标 | 定义 | 常用单位 | 我关注的点 |
|---|---|---|---|
| 吞吐量 | 单位时间内成功处理的数据量 | 条/秒、MB/s、GB/h | 峰值吞吐 vs 持续吞吐,差距往往很大 |
| 延迟 | 单条数据从进入系统到处理完成的时间 | ms、μs | P99 延迟比平均延迟更有参考价值 |
| 资源利用率 | CPU、内存、IO、网络的使用百分比 | %、MB、IOPS | 利用率超过 80% 就要警惕了 |
我的习惯:先测吞吐量,再看延迟分布,最后查资源利用率。顺序反了容易浪费时间——资源跑满了但吞吐上不去,说明代码逻辑有问题,加机器也没用。
2.2 吞吐量 vs 延迟:不是非此即彼
很多人觉得吞吐量和延迟是跷跷板,一个高了另一个就低。其实没那么简单。我举个例子:
你用 Kafka 批量消费,一批拉 1000 条,吞吐量上去了,但单条延迟从 10ms 涨到 200ms。这叫「以延迟换吞吐」。反过来,如果你每条都实时处理,延迟降到 1ms,但吞吐量掉到原来的十分之一。这叫「以吞吐换延迟」。
关键是你得知道业务要什么。实时风控系统,延迟必须低;离线数仓导入,吞吐量优先。我见过一个团队把实时流调成秒级批量,结果风控模型全失效了——嗯,这就是没搞清楚优先级。
核心原则:吞吐量和延迟的取舍,取决于业务对「新鲜度」的要求。新鲜度要求越高,延迟越敏感;反之,可以适当牺牲延迟换吞吐。
2.3 资源利用率:四个维度的排查清单
资源利用率是瓶颈分析的入口。我一般按 CPU、内存、IO、网络四个维度排查,每个维度都有典型的「症状」和「病因」。
2.3.1 CPU
- 症状:CPU 使用率持续 >90%,但吞吐量上不去
- 常见原因:序列化/反序列化开销大、正则匹配过多、循环内频繁创建对象
- 我曾经踩过的坑:一个 JSON 解析库在数据量大的时候 CPU 直接飙满,换成流式解析后降了 60%。
2.3.2 内存
- 症状:GC 频繁、堆外内存泄漏、OOM
- 常见原因:缓存未设置上限、批量大小不合理、对象引用未释放
- 避坑指南:我曾经在 Flink 任务里忘了设置 state TTL,结果状态越积越多,最后 OOM 挂掉。从那以后我每个有状态算子都强制配 TTL。
2.3.3 IO(磁盘)
- 症状:磁盘 IO 等待时间长、IOPS 打满
- 常见原因:随机读写多、日志刷盘太频繁、文件系统碎片化
- 我的建议:能用顺序读写就别用随机读写。Kafka 之所以快,就是因为它把随机写变成了顺序追加。
2.3.4 网络
- 症状:连接超时、重传率高、带宽打满
- 常见原因:数据压缩率低、连接数过多、跨机房传输
- 我常用的手段:先看 netstat 的重传率,超过 0.1% 就要查网络链路了。有一次发现是交换机端口协商成了百兆,换了根网线就好了。
2.4 常见的性能瓶颈模式
做久了你会发现,性能瓶颈就那么几种模式。我总结了一张图,方便你对照排查。
2.5 性能基准测试:怎么测才靠谱
测性能不是跑一次就完事。我总结了一套流程,你照着做基本不会漏。
- 确定测试场景:单条写入、批量写入、并发写入,分别测
- 预热系统:先跑 5 分钟,等 JIT 编译完成、缓存填满再记录数据
- 逐步加压:从低并发开始,每次翻倍,直到系统出现明显退化
- 记录关键指标:吞吐量、P50/P99 延迟、CPU/内存/IO/网络
- 重复三次取中位数:避免偶然波动影响判断
注意:不要在开发环境测性能。开发机的磁盘、网络、CPU 跟生产环境差太远。我曾经在 MacBook 上测出每秒 10 万条写入,上了生产只有 2 万——嗯,因为生产是机械盘 RAID5。
2.6 实战:用命令行快速定位瓶颈
你想想看,线上出问题的时候,哪有时间装监控工具?我一般靠这几个命令快速定位:
# 看 CPU 和内存
top -H -p <pid>
# 看磁盘 IO
iostat -x 1
# 看网络
sar -n DEV 1
# 看 GC 情况(Java 应用)
jstat -gcutil <pid> 1000
# 看文件描述符
lsof -p <pid> | wc -l
这几个命令组合起来,5 分钟内基本能判断出瓶颈在哪。我遇到过好几次,一看 iostat 的 %util 到了 99%,就知道是磁盘扛不住了。