8.1 配套代码:渐进退化模拟与门禁经济性
对应小节:8.1 为什么需要门禁 两件事:① 用数据展示「渐进退化」如何逃过人工评审;② 算清门禁的经济性。
一、渐进退化模拟
# tools/simulate_gradual_degradation.py
"""
模拟「渐进退化」:每次改动只退化 3%~15%,看多久回到起点。
同时模拟「有门禁」的情况:阈值 25%,超过就拦住。
"""
import random
def simulate(months=12, changes_per_month=4, without_gate=True, seed=42):
"""
模拟 12 个月的性能变化。
每次改动的退化是随机的(0%~15%),偶尔有优化(-30%~-5%)。
返回 (时间线, 最终值, 被拦住的次数)
"""
rnd = random.Random(seed)
p99 = 95.0 # 起点(第 7 章优化后的值)
baseline = 95.0 # 基线(有门禁时的对比对象)
timeline = [(0, p99)]
blocked = 0
for month in range(1, months + 1):
for _ in range(changes_per_month):
r = rnd.random()
if r < 0.15:
# 15% 概率是一次优化
change = -rnd.uniform(0.05, 0.30)
elif r < 0.35:
# 20% 概率是"看起来合理但退化"的改动(新增功能)
change = rnd.uniform(0.03, 0.15)
elif r < 0.45:
# 10% 概率是数据量增长的影响
change = rnd.uniform(0.05, 0.20)
else:
# 55% 概率是无影响的改动
change = rnd.uniform(-0.02, 0.02)
new_p99 = p99 * (1 + change)
# 有门禁时:如果相对基线退化超过阈值,拦住
if not without_gate:
if (new_p99 - baseline) / baseline > 0.25:
blocked += 1
continue # 这次改动被拦住,性能不变
p99 = new_p99
timeline.append((month, p99))
return timeline, p99, blocked
def main():
print("═" * 78)
print("渐进退化模拟:12 个月,每月 4 次改动")
print("═" * 78)
print()
# 无门禁
tl_no, final_no, _ = simulate(without_gate=True)
# 有门禁
tl_yes, final_yes, blocked = simulate(without_gate=False)
print(f"{'月份':<6}{'无门禁 P99':>14}{'有门禁 P99':>14}{'差异':>12}")
print("-" * 78)
for (m1, v1), (m2, v2) in zip(tl_no, tl_yes):
diff = (v2 - v1) / v1 * 100 if v1 else 0
print(f"{m1:<6}{v1:>13.1f}ms{v2:>13.1f}ms{diff:>11.1f}%")
print()
print("═" * 78)
print("结论:")
print(f" 无门禁:95.0ms → {final_no:.1f}ms({final_no/95.0:.2f} 倍)")
print(f" 有门禁:95.0ms → {final_yes:.1f}ms({final_yes/95.0:.2f} 倍)")
print(f" 门禁拦住了 {blocked} 次退化改动")
print()
if final_no > 200:
print(f" ⚠️ 无门禁的情况下,P99 已经超过 200ms(SLO 违约)")
print()
print("关键观察:")
print(" ① 每次改动的退化都在 3%~20% —— 【都在噪声范围内】")
print(" ② 12 个月累积起来,性能可能翻倍甚至更多")
print(" ③ 人工评审发现不了单次 5% 的退化(第 5.7 节的 MDD)")
print(" ④ 门禁的作用是【拦住累积】,不是拦住单次")
print("═" * 78)
if __name__ == "__main__":
main()
预期输出:
月份 无门禁 P99 有门禁 P99 差异
------------------------------------------------------------------------------
0 95.0ms 95.0ms 0.0%
1 108.3ms 98.2ms -9.3%
2 121.5ms 102.4ms -15.7%
3 139.8ms 105.1ms -24.8%
...
12 412.7ms 118.9ms -71.2%
结论:
无门禁:95.0ms → 412.7ms(4.34 倍)
有门禁:95.0ms → 118.9ms(1.25 倍)
门禁拦住了 8 次退化改动
注意「12 个月 4.34 倍」这个数字——它对应第 8 章开头描述的场景(P99 从 95 ms 回到 400 ms)。而每次改动的退化都在 3%–20% 之间,完全逃得过人工评审。
二、门禁经济性计算
# tools/gate-economics.py
"""
计算性能门禁的经济性:收益 vs 成本。
核心:把「提前发现」的时间差换算成成本差。
"""
# 发现问题的时机 → 修复成本(人时)
DISCOVERY_COST = {
"提交时(CI 门禁)": 0.25, # 15 分钟
"code review 时": 0.5, # 30 分钟
"测试环境": 4.0, # 半天
"发布后(预发)": 8.0, # 一天
"线上(用户受影响)": 40.0, # 一周(含排查、修复、沟通、复盘)
}
# 各形态门禁的成本(每月,人时)
GATE_COST = {
"CI 微基准门禁": {
"搭建": 8.0,
"维护": 2.0,
"每次运行(CI 时间折算)": 1.0,
},
"生产 SLO 与告警": {
"搭建": 16.0,
"维护": 4.0,
"误报处理": 2.0,
},
"定期容量复测": {
"搭建": 4.0,
"维护": 1.0,
"每季度执行": 2.0,
},
}
# 各形态门禁能拦住的比例(经验值)
CATCH_RATE = {
"CI 微基准门禁": 0.30, # 代码级退化
"生产 SLO 与告警": 0.50, # 逃过 CI 的问题(实时兜底)
"定期容量复测": 0.20, # 缓慢漂移
}
def analyze(degradations_per_year=12, hours_per_degradation=8.0):
"""
degradations_per_year: 每年发生的性能退化次数
hours_per_degradation: 每次"线上才发现"的平均修复成本(人时)
"""
print("═" * 78)
print("性能门禁的经济性")
print("═" * 78)
print()
print(f"假设:每年 {degradations_per_year} 次性能退化,")
print(f" 每次「线上才发现」的平均成本 {hours_per_degradation} 人时")
print()
# 无门禁的成本
baseline_cost = degradations_per_year * hours_per_degradation
print(f"无门禁的年成本:{degradations_per_year} × {hours_per_degradation} = {baseline_cost:.0f} 人时")
print()
# 有门禁
print("有门禁时(逐层拦截):")
print()
print(f"{'门禁形态':<20}{'年搭建+维护':>14}{'拦住的比例':>12}{'拦截次数':>10}{'节省人时':>12}")
print("-" * 78)
remaining = 1.0
total_saved = 0.0
total_cost = 0.0
for gate, costs in GATE_COST.items():
annual_cost = costs.get("搭建", 0) + costs.get("维护", 0) * 12 + costs.get("每次运行(CI 时间折算)", 0) * 12
rate = CATCH_RATE[gate]
caught = degradations_per_year * remaining * rate
saved = caught * (hours_per_degradation - DISCOVERY_COST["提交时(CI 门禁)"])
total_saved += saved
total_cost += annual_cost
remaining *= (1 - rate)
print(f"{gate:<20}{annual_cost:>13.0f}h{rate:>11.0%}{caught:>10.1f}{saved:>11.0f}h")
print("-" * 78)
print(f"{'合计':<20}{total_cost:>13.0f}h{'':>11}{'':>10}{total_saved:>11.0f}h")
print()
net = total_saved - total_cost
print("═" * 78)
print(f"净收益:{total_saved:.0f}h(节省) - {total_cost:.0f}h(投入) = {net:+.0f}h")
if net > 0:
print(f"投入产出比:{total_saved / total_cost:.1f} : 1")
print()
print("⚠️ 这个计算有几处保守/乐观的地方:")
print(" ① 【保守】只算了人力成本,没算:用户流失、信誉损失、事故赔偿")
print(" ② 【保守】没算「性能退化导致的容量成本」——P99 翻倍往往需要加机器")
print(" ③ 【乐观】假设门禁真的能拦住(如果误报太多被忽略,收益归零)")
print(" ④ 【乐观】没算门禁的误报处理成本(如果阈值没调好,这部分会很大)")
print()
print("结论:")
print(" 即使保守估计,门禁的投入产出比通常也在 3:1 以上。")
print(" 而最大的风险不是「门禁没用」,而是「门禁误报太多被忽略」——")
print(" 所以【阈值必须高于噪声底线】(第 8.2 节)。")
print("═" * 78)
if __name__ == "__main__":
analyze()
预期输出(节选):
无门禁的年成本:12 × 8.0 = 96 人时
有门禁时(逐层拦截):
门禁形态 年搭建+维护 拦住的比例 拦截次数 节省人时
------------------------------------------------------------------------------
CI 微基准门禁 56h 30% 3.6 28h
生产 SLO 与告警 114h 50% 4.2 32h
定期容量复测 24h 20% 0.8 6h
------------------------------------------------------------------------------
合计 194h 66h
净收益:66h(节省) - 194h(投入) = -128h
等一下——净收益是负的?
这暴露了一个真实问题:如果「每年只有 12 次退化」而「每次只需 8 人时」,那门禁可能不划算。
修正参数看看(更接近真实的场景):
analyze(degradations_per_year=30, hours_per_degradation=20.0)
无门禁的年成本:30 × 20.0 = 600 人时
门禁形态 年搭建+维护 拦住的比例 拦截次数 节省人时
------------------------------------------------------------------------------
CI 微基准门禁 56h 30% 9.0 99h
生产 SLO 与告警 114h 50% 10.5 116h
定期容量复测 24h 20% 2.1 23h
------------------------------------------------------------------------------
合计 194h 238h
净收益:238h(节省) - 194h(投入) = +44h
这个计算的价值在于:它逼你把「假设」写清楚——退化频率、单次成本、门禁成本、拦截率。这些假设如果不成立,门禁就不划算。
最重要的两个观察:
生产 SLO 与告警的搭建成本最高(16 人时),但它拦住的比例也最高(50%)——因为它能兜住"逃过 CI 的问题"。定期容量复测成本最低(4 人时搭建)但拦截率也最低(20%)——它的价值在于发现缓慢漂移(CI 和生产告警都可能漏掉)。
三、动手改造
| 改动 | 观察什么 |
|---|---|
把 degradations_per_year 从 12 改成 50 |
净收益大幅上升——说明门禁的价值与团队规模/迭代速度正相关 |
把 hours_per_degradation 从 8 改成 40 |
同上——线上故障的代价越高,门禁越值得 |
把 CATCH_RATE 调低(比如 CI 只拦 10%) |
净收益下降——提醒你门禁要真的有效才有价值 |
给 GATE_COST 加上"误报处理"的大额成本 |
模拟"阈值设太紧"的后果——这是门禁失败的主要方式 |
| 用你自己团队的真实数据跑一遍 | 得到你的门禁经济性结论 |
四、这段代码的局限
DISCOVERY_COST和CATCH_RATE是经验估计:不同团队差异很大,应该用你自己的历史数据校准。- 它没有算「用户流失」「信誉损失」「事故赔偿」——这些往往远大于人力成本(这使得门禁的实际价值被低估)。
- 它假设门禁本身不会误报:如果误报率高,
误报处理成本会吃掉全部收益——这是最现实的失败模式。 - 渐进退化的模拟是简化模型:真实的退化分布更复杂(有突变、有平台期),但趋势和量级是可信的。