8.2 性能调优方法论复盘 本节摘要:性能问题的第一杀手不是慢,是"凭感觉优化"。本节从一次"调优变降优"的翻车讲起,建立指标体系(RT/QPS/并发的关系)、USE 与自上而下两条定位方法论、压测的正确姿势、优化优先级排序,以及连续剖析的火焰图读法。 翻车现场:一次教科书级的错误调优 订单服务 RT 偏高,团队里最积极的工程师连夜做了四个"优化":缓存加了一层本地 Map、线程池翻倍、几个查询改成并行、JVM 换成 ZGC。上线一周后复盘:P50 略降,P99 反而恶化,还附赠了一个新问题——本地缓存与数据库不一致引发的资损工单。 四个动作四个错:本地缓存没有过期与一致性策略(引入正确性问题);线程池翻倍把压力传导到数据库(第 7.3 章的连接池成为新瓶颈);
本节摘要:性能问题的第一杀手不是慢,是"凭感觉优化"。本节从一次"调优变降优"的翻车讲起,建立指标体系(RT/QPS/并发的关系)、USE 与自上而下两条定位方法论、压测的正确姿势、优化优先级排序,以及连续剖析的火焰图读法。
订单服务 RT 偏高,团队里最积极的工程师连夜做了四个"优化":缓存加了一层本地 Map、线程池翻倍、几个查询改成并行、JVM 换成 ZGC。上线一周后复盘:P50 略降,P99 反而恶化,还附赠了一个新问题——本地缓存与数据库不一致引发的资损工单。
四个动作四个错:本地缓存没有过期与一致性策略(引入正确性问题);线程池翻倍把压力传导到数据库(第 7.3 章的连接池成为新瓶颈);并行化的是本来就快的分支(Amdahl 定律:快的地方再快也没用);ZGC 治的是 GC 停顿,而 GC 日志显示停顿本来只占 RT 的 2%(药不对症)。没有一个动作是从"瓶颈在哪"的测量出发的——这是性能工作里最常见的浪费:把优化当态度,不当工程。
三个指标由利特尔法则绑定:并发数 = QPS × 平均 RT(同一时刻系统内的请求数)。这个公式是容量规划的罗塞塔石碑:QPS 想翻倍,要么 RT 减半,要么并发容量翻倍。看懂它就能识破很多"玄学":
性能看板最低配置四条线:P50/P99 RT、QPS、错误率、资源利用率(CPU、内存、GC、连接池)。P99 比 P50 重要——用户流失发生在尾部;而"平均 RT"这种指标会掩盖一切(长尾被平均数洗白)。分位数要分机器看:单机 P99 都正常、集群 P99 很差,说明流量或数据倾斜,不是代码问题。
自上而下(Top-Down):从架构层往下问,瓶颈在哪一层?网络(带宽、RTT)→ 应用(锁、线程模型、算法复杂度)→ 容器/框架(序列化、反射)→ JVM(GC、JIT)→ OS(CPU 调度、IO)。每层用该层的工具排除或确认,像二分查找一样收窄。第 4 章"线程多 CPU 低 → 阻塞在 IO"、第 6 章"P99 尖刺对 GC 日志"都是这方法的实例。
USE 方法(对每类资源):检查 Utilization(利用率)、Saturation(饱和度,排队)、Errors(错误)。CPU 的饱和度是运行队列长度,磁盘是 IO 等待,连接池是等待获取的线程数(第 7.3 章的核心观察项)。USE 适合系统性巡检——饱和度比利用率更早报警(CPU 80% 但队列空是健康的,60% 但队列堆积是病态的)。

压测的三条纪律:生产等价的数据量与分布(长尾数据才能暴露第 1 章那类边界坑);预热后再采样(JIT 编译、缓存填充稳定后的数字才有意义);阶梯加压找拐点而不是一把轰到目标值(拐点前的最大吞吐才是真实容量)。回放生产流量(录制真实请求样本)优于合成压测——合成的数据分布往往太均匀。
**连续剖析(Profiling)**首选 async-profiler:低开销(可生产环境常开采样)、输出火焰图。火焰图读法一句话:横宽是占用 CPU 时间占比,看最宽的柱子;栈深是调用路径,看谁把它压在下面。第 3.3 节反射的 fillInStackTrace 粗柱、第 5.2 节锁竞争的 BLOCKED 堆积,在火焰图与 jstack 里各有典型形态。内存剖析用 MAT(第 6.1 节的支配树),分配剖析看"谁在制造垃圾"(第 6.2 节:GC 优化的第一优先级)。
性能工作的投入产出排序,从高到低:
每一步之后回到指标验证:改了什么、哪条曲线动了多少、有没有新的恶化(P50 降 P99 升是常见副作用,如引入缓存后的序列化开销集中到尾部)。没有对照组的优化报告都是故事。
⚠️ 常见坑:在低频路径上精雕细琢。一天调用 100 次的管理后台接口从 200ms 优化到 50ms,省下的时间不够写这份优化文档的。优化的对象选择也要看 ROI。
💡 关键直觉:性能优化是测量驱动的科学,不是灵感驱动的艺术。定位占八成时间,修改只占两成——那些上来就改代码的,大多在优化没有瓶颈的地方。
还有一个常被忽略的维度:性能工作的组织方式。单人闭门调优的产出,往往压不过"改完没人说得清为什么"。值得推荐的形式是性能专项的"结对面查":一人操作工具、一人记录假设与结论,每个假设与验证结果当场写进共享文档。这份文档事后就是天然的性能基线档案——下次响应时间涨了,先对照基线看哪条曲线变了,而不是从零再猜一遍。团队应该维护的正是这份"指标画像":正常时段的 P50 与 P99 曲线形态、GC 节奏、连接池水位、线程数基线。有了画像,异常是"与历史对比"的判断,五分钟出结论;没有画像,一切都是凭感觉的玄学。性能工程的复利,来自把每次测量都沉淀成下次的参照物。
最后一节:事故发生时与发生后的动作规范。