文档目录

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

这个计算的价值在于:它逼你把「假设」写清楚——退化频率、单次成本、门禁成本、拦截率。这些假设如果不成立,门禁就不划算。

最重要的两个观察:

  1. 生产 SLO 与告警 的搭建成本最高(16 人时),但它拦住的比例也最高(50%)——因为它能兜住"逃过 CI 的问题"。
  2. 定期容量复测 成本最低(4 人时搭建)但拦截率也最低(20%)——它的价值在于发现缓慢漂移(CI 和生产告警都可能漏掉)。

三、动手改造

改动 观察什么
把 degradations_per_year 从 12 改成 50 净收益大幅上升——说明门禁的价值与团队规模/迭代速度正相关
把 hours_per_degradation 从 8 改成 40 同上——线上故障的代价越高,门禁越值得
把 CATCH_RATE 调低(比如 CI 只拦 10%) 净收益下降——提醒你门禁要真的有效才有价值
给 GATE_COST 加上"误报处理"的大额成本 模拟"阈值设太紧"的后果——这是门禁失败的主要方式
用你自己团队的真实数据跑一遍 得到你的门禁经济性结论

四、这段代码的局限

  • DISCOVERY_COST 和 CATCH_RATE 是经验估计:不同团队差异很大,应该用你自己的历史数据校准。
  • 它没有算「用户流失」「信誉损失」「事故赔偿」——这些往往远大于人力成本(这使得门禁的实际价值被低估)。
  • 它假设门禁本身不会误报:如果误报率高,误报处理 成本会吃掉全部收益——这是最现实的失败模式。
  • 渐进退化的模拟是简化模型:真实的退化分布更复杂(有突变、有平台期),但趋势和量级是可信的。