8.8 性能评审与组织落地
上一节:8.7 容量规划 | 下一节:8.9 Lab 8 配套代码:08-continuous-performance/08-review-and-org
一句话结论
技术手段只能解决技术问题,而「性能持续不退化」最终是一个流程问题。 需要三样东西:评审清单(把性能纳入 review)、明确的责任人(谁对整体指标负责)、能被执行的语言(用业务方听得懂的方式讲性能)。
一、用「起飞前检查单」理解评审清单
飞行员起飞前不会凭记忆,而是逐项核对检查单:
| 为什么用清单 | 对应性能评审 |
|---|---|
| 人会忘(尤其疲惫时) | 开发者专注于功能正确性,会忽略性能影响 |
| 清单是最低标准 | 保证没人漏掉关键项 |
| 事后可追溯 | “这个检查项当时做了吗?” |
| 不依赖个人经验 | 新人也能按清单执行 |
航空业的经验:清单化的流程比个人能力更可靠。
二、性能评审清单(新功能上线前)
## 性能评审清单
### 数据访问
- [ ] 这个功能对每个请求增加了多少次 IO / RPC / 序列化?
- [ ] 有没有循环里的数据库调用(N+1)?
- [ ] 新增的查询走索引吗?在数据量增长 10 倍后还快吗?
- [ ] 有没有可以批处理的机会?
### 资源与边界
- [ ] 是否引入了无界的缓存、队列或内存结构?
- [ ] 新增的缓存/队列有淘汰策略吗?有容量上限吗?
- [ ] 是否引入了新的线程/协程池?并行度是多少?
- [ ] 是否引入了新的连接池?它与数据库的 `max_connections` 匹配吗?
### 超时与失败
- [ ] 每个新增的下游调用都有超时吗?
- [ ] 超时是否小于上游给的预算?(逐层递减)
- [ ] 超时后是否正确释放资源?
- [ ] 失败时是快速失败还是排队等待?
- [ ] 失败会不会放大(重试风暴)?重试有次数上限、退避、抖动吗?
- [ ] 这个调用是幂等的吗?(决定能否重试)
### 可观测性
- [ ] 新增的接口有延迟、错误率、饱和度指标吗?
- [ ] 新增的依赖有独立的计时指标吗?
- [ ] 出现问题时能否回答「这个接口的 P99 里,数据库占多少毫秒」?
- [ ] 指标标签里有没有无界维度(用户 ID / URL 全路径)?
### 兼容性与影响
- [ ] 这个改动会不会影响其他接口?(性能回归)
- [ ] 是否改变了共享资源的用量(连接池、线程池、缓存)?
- [ ] 是否需要更新容量规划?
- [ ] 是否需要更新 SLO 或告警规则?
### 验证
- [ ] 做了组件基准或集成基准吗?
- [ ] 关键路径做了性能对比吗?(before/after)
- [ ] 引入新组件时做了长稳(浸泡)验证吗?
注意最后一段:验证是清单的一部分——不是"有空再做"。
清单怎么用才不会被忽略
| 做法 | 效果 |
|---|---|
| 放在 PR 模板里作为 checkbox | ✅ 强制看到 |
| 在 code review 时由 reviewer 检查 | ✅ 有第二个人把关 |
| 只写在文档里 | ❌ 没人看 |
| 每个 PR 都要全部打勾(包括无关项) | ❌ 会变成形式主义(“全勾”) |
推荐:PR 模板里只放最关键的 5 项,详细的清单放在文档里按需查阅。
<!-- .github/pull_request_template.md -->
## 性能影响
- [ ] 这个改动增加了 IO / RPC / 序列化次数吗?(如果是,说明增加了多少)
- [ ] 引入了无界的缓存/队列吗?
- [ ] 新增的下游调用有超时吗?(且小于上游预算)
- [ ] 需要更新 SLO / 告警 / 容量规划吗?
- [ ] 关键路径做了性能验证吗?(附实验编号,或说明为什么不需要)
三、谁对性能负责
最常见的问题是「没人负责整体」:
❌ 现状:
- 每个开发者只对自己写的代码负责
- SRE 负责"系统不挂",但不负责"P99 是否退化"
- 架构师负责设计,但不跟踪上线后的指标
→ 结果:渐进退化无人发现(第 8.1 节)
三种责任模型
| 模型 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 平台团队负责 | 专门的性能团队维护门禁与容量 | 专业、统一 | 容易与业务脱节 |
| SRE 负责 | SRE 兼顾性能 | 与可靠性结合 | 精力分散 |
| 开发者负责 + 平台提供工具 | 每个团队对自己服务的性能负责 | 责任清晰 | 需要工具支持与培训 |
推荐第三种:
① 平台团队提供:
- 门禁工具与模板(第 8.2、8.3 节)
- 观测体系(指标、追踪、日志)
- 压测环境与脚本模板
- 培训与文档(本书)
② 业务团队负责:
- 自己服务的 SLO 定义与达标
- 性能评审清单的执行
- 退化时的定位与修复
- 容量需求的提出
③ 明确的接口:
- 谁批准 SLO 变更?(一般需要业务方参与)
- 谁批准基线更新?(性能负责人)
- 谁决定扩容?(团队 + 成本负责人)
四、用业务语言讲性能
技术指标对业务方没有意义:
| ❌ 技术语言 | ✅ 业务语言 |
|---|---|
| 「P99 从 400ms 降到 95ms」 | 「页面打开时间从 1.2 秒降到 0.4 秒」 |
| 「错误预算消耗 60%」 | 「这个月我们已经用掉 60% 的可靠性额度」 |
| 「需要暂停功能开发」 | 「建议先投一周在稳定性上,否则有 30% 概率本月出现故障」 |
| 「加了缓存,P50 降 70%」 | 「大部分用户的等待时间降低 70%,但最慢的那 1% 没有改善」 |
| 「需要 3 台新机器」 | 「按当前流量增长,下季度需要增加 3 台(成本 X)」 |
为什么这很重要:
① 性能预算的决策权常常在业务方("要不要为性能投人力/机器")
② 业务方听不懂 P99,但听得懂"用户等多久"
③ 用他们能理解的语言,才能拿到资源与优先级
一个实用的翻译模板
## 性能现状(给业务方)
### 用户现在的体验
- 打开订单页面:**平均 0.4 秒**,最慢的 1% 用户要等 **1.2 秒**
- 下单成功率:**99.2%**(1000 单里有 8 单失败)
### 与我们的承诺相比
- 承诺:0.5 秒内打开、99.5% 成功
- 现状:✅ 打开时间达标 ❌ 成功率差 0.3 个百分点
### 可能的影响
- 按每天 5 万单计算,每天约 **400 单**失败
- 成功率每下降 0.1%,每月约损失 **XXX 元**(估算)
### 建议
1. 短期(1 周):修复下单失败的主要原因(预计成功率回到 99.4%)
2. 中期(1 个月):加错误处理与重试(预计 99.6%)
### 需要的投入
- 1 名工程师 × 1 周
- (无人力投入的话,失败率可能继续恶化)
五、性能文化的三件事
❶ 让性能「可见」
❌ 性能数据在 Grafana 里,没人看
✅ 每周在团队频道发一次「性能周报」(3 个数字 + 1 个趋势)
周报模板:
## 性能周报(第 3 周)
| 指标 | 本周 | 上周 | 趋势 |
| --- | --- | --- | --- |
| 订单接口 P99 | 98 ms | 95 ms | ⚠️ +3% |
| 错误预算剩余 | 78% | 85% | ⚠️ 消耗加快 |
| 峰值 QPS / 安全容量 | 62% | 58% | 观察 |
**本周关注**:P99 已连续两周缓慢上升,可能与上周新增的「用户画像查询」有关,已安排排查。
❷ 让性能「有代价」
如果性能退化没有代价,它就不会被优先处理。
| 机制 | 做法 |
|---|---|
| 门禁失败阻塞合并 | 第 8.2 节 |
| 错误预算耗尽冻结发布 | 第 8.4 节 |
| 性能问题计入技术债看板 | 有可见的跟踪 |
| 容量需求走正式流程 | 需要评估与批准 |
❸ 让性能「有奖励」
这一条最容易被忽略:
❌ 只有出问题时才谈性能(= 性能是"救火")
✅ 主动的性能改进也被看见(= 性能是"工程价值")
具体做法:在季度回顾里列出「本季度性能改进」(降低的延迟、节省的机器成本、避免的故障)。
六、一个常见的组织反模式
❌ 反模式:性能是"上线前的一次性关卡"
流程:
开发 → 测试 → 【性能验证】→ 发布
↑
只有这里管性能
而且常常因为"赶进度"被跳过
问题:
① 上线后没有持续监控(退化了也不知道)
② 性能验证被跳过时没有替代方案
③ 性能问题的修复优先级总是低于新功能
✅ 正确模式:性能贯穿全流程
设计(评审清单)→ 开发(微基准)→ 验证(集成基准)
→ 发布(金丝雀)→ 运维(SLO 告警)→ 定期(容量复测)
↑ │
└──────────── 反馈与改进 ←────────────────────┘
关键差异:性能不是"一道关卡",而是"贯穿全流程的约束"。
七、本节小结
- 评审清单的价值在于「不依赖个人记忆」——像飞行员的起飞检查单。
- 清单的关键 5 项放 PR 模板,详细清单放文档按需查阅(避免形式主义)。
- 责任模型推荐第三种:开发者对自己服务的性能负责 + 平台团队提供工具与培训。
- 必须明确三个接口:谁批准 SLO 变更、谁批准基线更新、谁决定扩容。
- 用业务语言讲性能:P99 → 用户等待时间;错误预算 → 可靠性额度。
- 性能文化的三件事:让性能可见(周报)、有代价(门禁与预算)、有奖励(季度回顾)。
- 最大的组织反模式:把性能当作"上线前的一次性关卡"——性能应该贯穿全流程。
八、自测
- 一个团队的 PR 模板里有 30 项性能检查清单,但每个人都直接全勾。请诊断这个问题,并给出改进方案。
- 产品经理问:「为什么我们要花一周做性能优化,而不是做新功能?」请用业务语言回答(不要说 P99)。
- 为什么「性能是上线前的一道关卡」是一种组织反模式?请说出至少三个问题,以及正确的模式是什么。
- 诊断:清单太长导致形式主义——当清单内容远超 PR 的实际影响范围时(比如一个改文案的 PR 也要勾"有没有 N+1"),开发者会机械地全勾,清单失去了筛选作用。根本问题:清单的目的是"不漏掉关键项",而不是"覆盖所有可能"。改进方案:① PR 模板只保留最关键的 5 项(且用"是否需要"而非"是否做了"的措辞,允许"不适用");② 详细清单移到文档,按需查阅(比如涉及数据访问时才看那一节);③ 在 code review 时由 reviewer 针对性地提问——比如新增了数据库查询就问"走索引吗",比让作者自己勾更有效;④ 对无关的 PR(纯文案、纯样式)明确声明"无性能影响"即可,不必逐项勾选。
- 业务语言的回答:「这一周投入能换来三件事:第一,用户投诉会减少——我们的订单页最慢的 1% 用户现在要等 1.2 秒,优化后是 0.4 秒,按每天 5 万单算,每天有 500 个用户从"明显卡顿"变成"流畅";第二,避免损失——目前下单成功率 99.2%,低于承诺的 99.5%,每天约 400 单失败,优化能把它拉回承诺线以上;第三,省成本——优化后单机能扛更多流量,下季度可以少买 3 台机器(约 X 元/年)。如果不做:这 1% 的慢请求正在缓慢扩大(上个月是 0.6%,这个月是 1%),按这个趋势,两个月后会有 5% 的用户受影响,那时修复的成本是现在的 3–5 倍,而且可能在某个流量高峰直接导致故障。」
- 三个问题:① 上线后没有持续监控——性能验证通过是一次性的,但退化是持续发生的(第 8.1 节:数据量增长、配置漂移、依赖演进),没有持续监控就发现不了;② 这个关卡容易被跳过——当"赶进度"时,性能验证往往是第一个被牺牲的,而且跳过后没有替代保障(没有告警、没有门禁兜底);③ 修复优先级总是最低——因为性能不是"功能",在需求排期里没有位置,导致问题被无限期积压;④ 第四个问题:责任不清晰——关卡由谁把关?谁来跟踪上线后的指标?往往是"大家都觉得有人管,实际上没人管"。正确的模式:性能贯穿全流程——设计阶段过评审清单 → 开发阶段跑微基准 → 验证阶段跑集成基准 → 发布阶段用金丝雀 → 运维阶段靠 SLO 告警 → 定期做容量复测。关键差异:不是"一道关卡",而是"一系列持续运行的约束"——每一环都不需要人记得,机制会自己提醒。