先讲一个我特别有画面感的场景:线上出了大故障,复盘会议上投出一张监控大屏,上面赫然写着“本月可用性 99.9%”,但用户侧已经骂了将近一个小时。开发同学一脸无辜,运维同学盯着指标说不出话,老板缓缓问出一句:“我们不是达标了吗,用户为什么在骂?”这个矛盾我经历过不止一次。如果你也遇到过类似场面,那你应该能理解我为什么要写 SLOManager 这个项目——它本质上是把 SLO 从 PPT、文档和口头承诺里捞出来,变成一整套能计算、能告警、能复盘、能推动团队行为的工程机制。标题里那个《九阴真经卷十二》,是我们团队内部给 SRE 系列分享起的外号,写到这里正好第十二篇,主题就是“SLO 管理心法”,于是干脆把项目代号定成 SLOManager。
这套东西不是某个大厂的商业化平台,也不是一个需要很多服务器才能跑起来的重系统,而是一条轻量工具链,配合 Prometheus 生态和现有监控系统,就能让 SLO 真正“活”起来。接下来我按自己做这个项目时的思考过程、核心模型、落地步骤和踩坑记录来展开。
1. 我为什么在N次故障复盘后,决定自己写一个SLO管理工具
1.1 文档型SLO为什么行不通:追责靠猜、指标靠嘴
很多团队并不是没有 SLO,而是 SLO 只存在于一张共享文档里。文档里写了“核心链路可用性 99.9%”“下单接口 P99 延迟 200ms”,看起来非常正式。但一遇到实际故障,这套纸面 SLO 立刻露馅。
头一个问题是“查不到”。线上出事后,打开监控系统发现指标大盘上根本没有一条直接对应 SLO 的曲线,只有游离的 5xx 错误率和接口耗时,得靠人手工拼凑才能还原“当前可用性还剩多少”。
第二个问题是“不可算”。就算找到了错误率,怎么折算成“这个月预算用了多少”也说不清。很多监控工具只展示实时指标,不会按照 30 天滚动窗口把错误时间累加起来。这就导致故障结束后复盘时,大家只能靠感觉争论“这次到底算不算消耗预算”。
第三个问题是“告警靠人肉”。文档里写的 SLO 没有自动绑定告警,线上流量翻倍、错误率抬头时,第一个发现问题的往往是用户的投诉工单,而不是监控系统。SLO 文档再漂亮,如果它连一次真实告警都触发不了,那就是张废纸。
第四个问题是“复盘拍脑袋”。因为前面的数据都没有,复盘会就变成“各自描述自己看到的片段”。有人说错误率不高,有人说延迟有抖动,唯独没人能拿出一个明确的标尺:这次事故消耗了全月错误预算的 40%,我们正处于高风险区域。
这四个问题叠在一起,结论就很简单:SLO 必须被代码化,必须被系统持续计算,必须能自动触发告警。这个想法就是我写 SLOManager 的起点。
1.2 SLOManager要解决的三个核心问题
我构思 SLOManager 的时候,没有一上来就想做一个巨大的平台,而是先拆出三个必须解决的核心问题:定义、计算、反馈。
定义是指把“可用性 99.9%”这种自然语言,转成机器能理解的结构化配置。比如这个 SLO 对应哪个服务的哪些指标、好坏事件怎么判定、时间窗口是多长、目标值是多少、告警阈值怎么设置。
计算是指持续追踪当前窗口内已消耗的错误预算,并给出“剩余多少”“按当前速率还能撑多久”这类决策信息。这里不光是算一个累计值,还要算消耗速度。
反馈是指当预算消耗达到特定水位,或者消耗速率异常时,系统要能分级通知到不同角色,同时自动生成每周复盘数据。没有反馈闭环,前面定义和计算做得再好,最后也会退化成一张没人看的报表。
这三个问题对应着工具的三个模块:配置层、计算层、通知与报告层。项目叫 SLOManager,而不是 SLO-Monitor 或 SLO-Dashboard,就是因为它的核心不只是“看一下”,而是“管起来”。
1.3 项目形态:不是大平台,而是一套轻量工具链
很多团队一听说要做 SLO 管理,下意识就想买一个 SaaS 产品或者自研一个高大上的控制台。我的建议是:在规模还没到那个程度之前,先做一条工具链就够了。
SLOManager 在工程形态上我分成了几块:一份 YAML 配置仓库,定义所有服务和 SLO;一组 Cue/PromQL 模板,从配置生成监控规则;一个定时任务,每天把窗口内的错误预算明细算出来落到一张表里;一套告警路由,接到现有 Alertmanager 或企业微信机器人;最后加上一个能够自动产出周报的脚本。
这样的好处是每个组件都可以单独替换。今天用 Prometheus,明天换 VictoriaMetrics,改动只集中在采集和查询层。如果新接入一个服务,只需要在配置仓库里加一段 YAML,剩下全部自动生成。这个思路让我在推广时少了很多阻力,因为团队不需要“上一个新系统”,只需要“在现有监控上多挂一套规则”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SLOManager的核心模型:SLI、时间窗口与错误预算怎么才算算对了
2.1 SLI定义:先想清楚“什么算坏”,再谈“可用多少”
SLO 不是凭空定的,它上面必须有 SLI。SLI 是“服务质量的量化指标”,SLO 则是给这个指标定一个目标值。项目里最常见的错误是把 SLO 当口号,从没认真定义过 SLI。
比如“可用性 99.9%”,这个 SLI 就需要想清楚:分母是什么,分子是什么。分母是所有到达线上入口的请求总数,还是只统计核心交易链路的请求?分子是非 5xx 请求,还是包含了 4xx?4xx 算不算坏,取决于这个 SLO 是用来衡量“服务有没有认真处理用户请求”,还是只衡量“有没有返回错误”。而延迟类 SLO 更麻烦,P99 低于 200ms 只是一个最终结果,背后的 SLI 实际是一个分布,得先决定用什么百分位、采样周期多长、怎么聚合多个实例的数据。
在 SLOManager 的配置模型里,我把 SLI 抽象成两种基础类型:一种是 ratio(比例型),比如“非 5xx 请求数 / 总请求数”;另一种是 histogram(分布型),比如“请求延迟低于 200ms 的比例”。比值型直接用 counter 算,分布型则要用 histogram 的分位数或阈值计数来算。我强烈建议一个 SLO 只绑定一个核心 SLI,不要试图把可用性和延迟揉成一个“综合可用性指标”,否则后面做多指标聚合时会吃大亏,这一点我在第四部分会专门讲。
以下是一个简化的 SLI 配置示例:
yaml复制service: order-service
slos:
- name: order-availability
sli:
type: ratio
good_selector: "http_requests_total{route='checkout',status!~'5..'}"
total_selector: "http_requests_total{route='checkout'}"
target: "99.9"
window: 30d
这段配置的意思是:只统计 checkout 这条路由的所有请求,只要返回状态不是 5xx 就算“好事件”。目标是在 30 天滚动窗口内,好事件占比不低于 99.9%。
2.2 时间窗口选择:滚动窗口和日历窗口,选错会怎样
时间窗口是 SLO 里最容易选错、也最影响计算稳定性的参数。常见的选择有两种:滚动窗口(如“最近 30 天”)和日历窗口(如“本月”“本周”)。
滚动窗口的好处是没有“月初清零”的割裂感,任何时候看预算消耗,都是过去 30 天的连续状态,能真实反映近期服务质量。缺点是计算量和存储压力大,因为它不是从自然月边界开始,而是每天都要把时间轴往前挪。
日历窗口的优点是理解成本低,团队会议周报都能对上节奏,缺点也很致命:每个月 1 号预算清零,前半月如果出了小事故,错误预算被消耗,团队可能会选择“保守少发版”,避免在预算不足的月份踩线;到了月底发现预算还有很多,又会开始“冲刺式发版”。这种周期性波动对长期稳定性是不利的。
我最后选择的是滚动窗口,但为了保证周报和例会的节奏感,又在此基础上额外输出“本周错误预算增量”和“本自然月累计”两组对照数据。计算累计时用滚动窗口,报告展示时附上日历归档。这样既保证了 SLO 语义的连贯性,也满足了团队日常管理的需要。
窗口长度我一般推荐 30 天或 28 天,不建议太短。7 天滚动窗口对短期变化太敏感,一次夜间小故障就能把剩余预算打没,告警会变得非常神经质。季度窗口又太长,错误预算消耗到 10% 时大家毫无感觉,相当于没有控制作用。30 天是个相对折中的值:够长到能抹平日常噪声,也够短到让团队对“烧预算”有紧迫感。
2.3 错误预算的计算与燃尽率:从公式到一次故障演练案例
把 SLI 和目标值配对之后,就得算错误预算。公式不复杂:错误预算 = 总时间窗口 × (1 - SLO 目标值)。
以 99.9% 和 30 天窗口为例:30 天是 30 × 24 × 3600 = 2,592,000 秒,允许的错误时间就是 2,592,000 × 0.001 = 2,592 秒,折合 43 分 12 秒。也就是说,在这 30 天里,如果完全不服务的“净坏时间”累计超过 43 分钟,SLO 就达标失败。
这里有个很容易绕晕的地方:故障持续 20 分钟,不代表就消耗了 20 分钟预算。因为故障期间的错误率不一定是 100%。我通常用“等效坏时间”来理解:等效坏时间 = 故障持续时间 × 期间实际错误率。
举个例子,一次持续 20 分钟的故障,期间错误率是 10%,那么等效坏时间是 1200 秒 × 10% = 120 秒,消耗的预算比例是 120 / 2592 ≈ 4.6%。如果同样 20 分钟故障但错误率是 100%,等效坏时间就是 1200 秒,直接烧掉全月预算的 46%。这个计算方式能让团队直观感受到:一次 20 分钟的完全不可用,或者三次 20 分钟的半不可用,预算就见底了。
“燃尽率”则是另一维度的指标,用来回答“按当前消耗速度,错误预算还能撑多久”。燃尽率也叫 burn rate,公式是:当前实际错误率 / 目标错误率。
目标错误率就是 1 - SLO,例如 99.9% 对应 0.1%。如果故障期间实际错误率是 1%,燃尽率就是 10 倍。这意味着在这种速率下持续 24 小时,会消耗 24 小时 × 10 的“等效预算日”,相当于一个月 30 天预算里的三分之一。换句话说,如果连续 3 天保持这种故障强度,当月预算就彻底烧完。燃尽率帮我们把“当前有多严重”换算成“多久会死”,这才是告警真正需要的东西。
2.4 告警引擎:Multi-window Multi-burn-rate 是怎么实现的
有了错误预算和燃尽率,下一步就是设计告警。如果只是“预算剩余少于 50% 告警一次”,实践中是不够的,因为这类阈值对突发故障反应太慢。我采用的是 Google SRE 工作手册里推荐的 Multi-window Multi-burn-rate 思路,它已经在 SLOManager 里落地成了标准告警模板。
这个思路的核心是:用多组长短不同的时间窗口和燃尽率阈值,组成两级告警。短的窗口(如 1 小时)负责快速发现突发严重故障,但阈值要设得很高,避免因为抖动误报;长的窗口(如 6 小时或 3 天)负责捕捉缓慢持续的问题,阈值可以低一些,但必须持续一段时间才触发,避免偶发毛刺。
我落地时采用的参数如下:
| 告警级别 | 时间窗口 | 燃尽率阈值 | 持续条件 | 触发含义 |
|---|---|---|---|---|
| Page 级 | 1h | 14.4 | 5 分钟 | 预算将在约 3 天内耗尽,立即处理 |
| Page 级 | 6h | 6 | 30 分钟 | 持续严重,但不必深夜惊动所有人 |
| Warning 级 | 3d | 1 | 1 小时 | 预算正以“刚好耗尽”的速度流失 |
这套参数不是拍脑袋定的。14.4 倍燃尽率意味着实际错误率约为 SLO 允许值的 14.4 倍,如果这种状态持续 24 小时,会烧掉约 14.4 天的预算额度,预算扛不过 3 天,必须 Page。而 6 小时窗口里的 6 倍燃尽率,则表示一天会烧掉 6 天的预算,预算还能撑大约 5 天,给白天上班的人一个半紧急的信号。3 天窗口 1 倍燃尽率则可以理解为“如果这种情况持续到窗口结束,预算正好花完”,用来做趋势预警。
配合 Prometheus 的实现也不复杂。先用 recording rule 把不同窗口的错误率都算好,再除以目标错误率得到 burn rate,然后用 alert rule 加上 for 子句去防抖。
promql复制slo:order_availability:burn_rate_1h > 14.4
slo:order_availability:burn_rate_6h > 6
slo:order_availability:burn_rate_3d > 1
这套告警体系的好处是:重要但没那么紧急的问题不会半夜惊动所有人,而真正会让 SLO 崩溃的故障一定会在很短时间内触发最高级别告警。它把“快”和“稳”这对矛盾拆成了两个维度分别处理。
3. SLOManager落地全流程:从配置到周报,每一步都有产出
3.1 第一步:在配置中心定义Service与SLO(附一个可用模板)
SLOManager 的起点是配置仓库。我把它做成 Git 仓库,每个服务一个目录,目录里是该服务的 SLO 配置。这样配置的变更天然有 review 流程,有迹可循。
完整的配置模板大概长这样:
yaml复制service: order-service
owner: checkout-team
slos:
- name: order-availability
sli:
type: ratio
good_selector: "http_requests_total{route='checkout',status!~'5..'}"
total_selector: "http_requests_total{route='checkout'}"
target: "99.9"
window: 30d
alerting:
page:
- window: 1h
burn_rate: 14.4
for: 5m
- window: 6h
burn_rate: 6
for: 30m
warning:
- window: 3d
burn_rate: 1
for: 1h
- name: checkout-latency
sli:
type: histogram
total_selector: "http_request_duration_seconds_count{route='checkout'}"
good_selector: "http_request_duration_seconds_bucket{route='checkout',le='0.2'}"
target: "99.5"
window: 30d
alerting:
page:
- window: 1h
burn_rate: 10
for: 5m
warning:
- window: 6h
burn_rate: 4
for: 30m
owner 字段是我特意加的。SLO 必须能找得到负责人,否则告警发出去了也没人接。每次新建 SLO 时我都会要求团队填这个字段,不填就不允许合并配置。
在定义这一步最容易忽视的是 selector 的覆盖范围。比如某服务有多个接口,如果只选了核心接口做 SLO,那么某个边缘接口大量 5xx,在 SLO 上完全看不出来。所以我会额外要求:每个 SLO 的 total_selector 背后建议加一条“覆盖率”检查,定期核对这个 selector 命中的请求量占总入口请求量的比例。低于 80% 的覆盖率就说明 SLO 定义得可能太窄,要重新审视。
3.2 采集层:用Recording Rules把原始指标变成错误率指标
配置定义好之后,SLOManager 会从配置生成一组 Prometheus recording rule,把这些规则自动同步到 Prometheus 服务器。这个过程需要谨慎,因为直接让团队手写一堆重复的 rule,极易出错,一旦写错一个 selector,整个 SLO 数据就静默失真。
我生成的 recording rule 大致长这样:
yaml复制groups:
- name: slo-order-service
interval: 30s
rules:
- record: slo:order_service_availability:errors_total
expr: |
sum(increase(http_requests_total{route='checkout',status=~'5..'}[5m]))
or vector(0)
- record: slo:order_service_availability:total_total
expr: |
sum(increase(http_requests_total{route='checkout'}[5m]))
or vector(0)
- record: slo:order_service_availability:error_rate_5m
expr: |
slo:order_service_availability:errors_total
/ clamp_min(slo:order_service_availability:total_total, 1)
几个细节值得说。第一,我用了 or vector(0),是为了避免没有流量时指标缺失变成 NaN,导致告警计算出现空档。第二,分母用 clamp_min 夹到至少 1,是为了防止除数为 0。第三,recording rule 的 interval 设成 30 秒,与普通抓取节奏匹配,给前端告警留出足够的实时性。
从公式可以看到,这里的 errors_total 是 5 分钟窗口内的增量错误数,所以我在此基础上继续生成不同窗口的 burn rate。方法就是换 rate 的窗口:1 小时窗口算一个 burn_rate_1h,6 小时窗口算 burn_rate_6h,3 天窗口算 burn_rate_3d。每个窗口都要有独立的 recording rule。
3.3 告警路由:把Page、企业微信、IM通知分清楚
告警规则生成之后,就得考虑“发给谁”和“怎么发”。SLOManager 对接的是 Alertmanager,我设计了一套分级路由。
Page 级告警对应的是“预算将在 3 天内耗尽”或更严重的情况。这类告警必须发给值班手机,走电话或者小程序强提醒。Page 里只带一句“哪个服务、哪个 SLO、当前 burn rate 是多少、已持续多久”,不需要带完整日志,因为看手机时没时间看长文。
Warning 级告警发给 SLO 的 owner 群,通过企业微信或钉钉机器人,主要是让负责人知道“你负责的系统正在以不可持续的速度消耗预算”,但不强制立刻处理。
除此之外,我还会挂一条“日报”级别的低频告警:每天晚上汇总当前所有 SLO 的剩余预算和消耗速度,发到 SRE 团队群里。这条不是告警,是“天气预报”,让团队每天都有一个全局感知。
yaml复制route:
group_by: ["service", "slo"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: page
receiver: oncall-phone
- match:
severity: warning
receiver: slo-owner-group
这里有个经验:repeat_interval 别设太短,否则 Page 告警会钉着人一直响。我把 Page 的重发间隔设在 4 小时,但每次重发时告警内容里更新“当前剩余预算百分比”,让值班的人知道是不是恶化了,而不是收到一条一模一样的重复消息。
3.4 自动周报:用每日跑批算剩余预算,输出事件明细
实时告警解决的是“当下怎么办”,周报解决的是“这段时间怎么样”。SLOManager 的周报模块是一个 Python 定时任务,每天凌晨从 Prometheus/TSDB 拉取前一天的指标增量,计算出每个 SLO 最近 30 天的累计消耗,并写进一张结果表。
具体的跑批逻辑大致是:
- 对每个 SLO,查询近 30 天的每日错误/请求增量。
- 将每日错误率乘以当日秒数,换算成“等效坏秒”。
- 汇总最近 30 天的坏秒,对比允许坏秒,得出剩余预算。
- 找出最近 7 天内坏秒增量最高的事件时段,作为“高消耗事件”。
每周一生成的周报会包含一张表:
| 服务 | SLO | 目标 | 窗口内累计坏秒 | 剩余预算 | 本周消耗趋势 | 主要高消耗事件 |
|---|---|---|---|---|---|---|
| order-service | checkout 可用性 | 99.9% | 673s | 74.0% | 上升 | 6/12 01:10-01:25 checkout 5xx 高峰 |
| order-service | checkout P99 延迟 | 99.5% | 298s | 76.9% | 平稳 | 6/14 大促流量,P99 触摸阈值 |
这张表比任何监控大盘都更适合在周会上使用,因为它是按时间窗口严格计算过的“账本”。团队看到“剩余预算 74%”时会知道当前处于安全区间;看到“本周消耗趋势上升”时会主动去翻是什么变更导致的。
这个跑批方案还有一个好处:它绕开了 Prometheus 直接查询 30 天 increase 的沉重开销。实时告警用短窗口 rate,累计预算用每日预聚合表,两者互补,既准又不费机器。
4. 踩坑实录:SLOManager落地时我认为最值得写下来的四个教训
4.1 坑1:维护窗口到底要不要从SLO里剔除
第一次把 SLO 正式接入团队时,马上就遇到了“维护窗口算不算故障”的争论。当时线上做大版本升级,计划内维护 15 分钟,期间服务不可用,结果这 15 分钟直接烧掉了当月近 35% 的预算。有同学提出,计划内维护应该从 SLO 统计里剔除,否则“不是我们的锅还要背”。
我纠结了一段时间,最终的决定是:默认不剔除,但在周报里单独标记为“计划内维护事件”。理由很实在:对用户来说,他才不管你是计划内还是计划外,那 15 分钟就是点不开页面、提交不了订单。SLO 如果只统计“非计划内故障”,它就变成了团队内部给自己找借口的指标,而不是用户真实体验的度量。
但是完全不剔除也有问题。比如每天凌晨全量任务跑批时,某个非核心服务会短暂不可用,这类请求本就不该纳入用户体验 SLO。所以我的处理方式是把“剔除什么”交还给配置:如果团队能明确区分出那部分流量不属于用户可感知范围,就把对应 selector 排除在 total 之外;如果只是“我们自己觉得不算”,那就老老实实计入预算。这个原则写进了团队规范,后来的争执少了很多。
4.2 坑2:滚动窗口的对齐方式,导致月末预算数字跳变的坑
滚动窗口听起来很简单,但实现时踩了一个很隐蔽的坑。最初我用“按自然日分组求和”的方式算最近 30 天坏秒,结果每到月末最后几天,预算数字会突然跳变。
原因不复杂:自然日对齐让每一天的区间边界不同,比如 6 月 30 日看“最近 30 天”,其实是 5 月 31 日 0 点到 6 月 30 日 0 点;而 5 月有 31 天,这个切片实际上是 31 个自然日的增量。不同月份之间,同样的“最近 30 天”包含的自然日数量不一致,累计坏秒的基准就漂移了。
后来我改成严格使用 Unix 时间戳对齐:每次计算都以当前时刻往回推 30 × 24 × 3600 秒,不按自然日切割,跑批时也存“第几天、当天坏秒”的明细,然后取最近 720 小时做滚动汇总。这样任何一天看,窗口长度都是恒定的,预算数字不再出现月末跳变。
这个坑提醒我:SLO 计算看起来只是简单的加减法,但时间边界处理不对,所有下游判断都会失真。
4.3 坑3:多SLI聚合时用错了方式,单点故障没有触发告警
早期我犯过一个错误:为了让一个服务只有一个 SLO,把可用性和延迟两个 SLI 做了“平均”。结果某一天延迟指标飙到很高,但因为可用性指标很好,平均下来整体 SLO 仍然显示健康,告警一条都没触发,直到用户投诉才意识到问题。
这个例子说明:多个 SLI 合成为一个 SLO 时,“求平均”是灾难性的。如果你用“任一关键 SLI 异常即算坏”,那就应该用 OR 逻辑做事件合并;如果你非要用一个综合值,应该用“坏事件并集”来算总坏秒,而不是把指标数值平均。
在 SLOManager 里,我后来做了一个限制:一个 SLO 内部可以配置 multiple slis,但计算时默认按“任一 SLI 不达标则整个窗口视为坏窗口”来处理,同时更推荐团队直接拆成多个独立 SLO,分别告警、分别复盘。把两个语义完全不同的指标绑在一起,只会让告警含义变得模糊。
4.4 坑4:告警阈值参数是怎么从“乱Page”调成“两周内耗完才Page”的
告警阈值刚上线时我参照了 Google 推荐值设 14.4 倍燃尽率,但实测下来发现,很多服务在流量高峰的 10 分钟内就烧掉了一天预算,1 小时窗口的 Page 频繁触发,团队开始出现告警脱敏。没人看告警,比没有告警更危险。
后来我调了一个晚上,把 Page 阈值改成“预算将在 2 周内耗尽才触发”。思路是:对于大多数内部服务,用户并不是不可能等几个小时,真正需要半夜爬起来处理的,是那种“如果没人干预,预算铁定撑不过两周”的情况。这样设定的好处是过滤掉了大量短期抖动,保留了真正的紧急。
具体做法是把燃尽率阈值与窗口挂起来:1 小时窗口用的阈值等于“如果持续 24 小时,会烧掉多少天预算”,我喜欢让这个数字对应到 14 天,所以 1 小时窗口阈值取 14,6 小时窗口阈值取 6 左右,3 天窗口阈值取 1。这个参数不是固定的,每个服务可以根据自己的容错能力调整。关键是明确一点:Page 的意义是“现在必须有人处理”,而不是“指标有点不对劲”。
5. 把SLOManager变成团队机制:错误预算文化比工具本身更难
5.1 变更评审绑定SLO风险,而不是绑定负责人
工具搭好之后,我遇到的最大阻力是团队不习惯看 SLO。开发同学提变更时,只会描述功能需求和技术方案,很少主动评估这个变更会影响哪个 SLO。
于是我把 SLO 风险加进了变更评审表单。提变更的人必须回答一个问题:这个变更关联哪些 SLO?在错误预算只剩 20% 的情况下,这个变更如果导致可用性下降,团队能接受吗?如果当前预算充足,那么这个变更引入一个短期小故障也无伤大雅,评审就可以适当放行。
这个机制的效果很直接。以前评审是“这个方案能不能上线”,现在变成了“这次变更对用户承诺的服务质量有没有风险”。团队开始在提测阶段就讨论指标影响,而不是等线上故障之后才追认。SLOManager 在这里的作用是提供那个“当前预算水位”的实时数据,让评审有了客观依据。
5.2 每周一次的SLO复盘会:只看错误预算曲线,不做追责
SLOManager 自动生成的周报在每周例会上会占 15 分钟。我要求复盘会只做三件事:看一眼剩余预算曲线、找出本周消耗最快的事件、决定下周是否调整变更节奏。不许翻旧账,不许追责,因为一旦变成追责会,大家就会想方设法在指标口径上做手脚,而不是真正关注服务质量。
复盘会上最有价值的图是错误预算剩余百分比的历史曲线。它比可用性百分比直观得多,因为 99.9% 和 99.0% 在普通监控图上差别不大,但错误预算从 60% 掉到 20% 是一条非常刺眼的陡坡。人眼对比例变化比对绝对值更敏感,这也是 SLOManager 周报用剩余预算而不是用可用性百分比做主指标的原因。
我记得有次复盘,某团队看到自己负责的域名错误预算只剩 12%,当场没有再争辩“系统一直很稳定”,而是主动列出了三个可能的变更窗口。这就是机制的力量:把模糊的争论转化成明确的优先级。
5.3 SLO不能当KPI:一旦考核,就会被战术性作弊
这是我反复强调的一点。SLOManager 上线的第二个月,有团队因为连续两周错误预算充足,于是搞了次大版本重构,结果一个低级配置错误让可用性掉到 98%,当月预算直接烧光。管理层很自然地想把“SLO 达标率”纳入绩效考核,被我拦住了。
原因很简单:一旦 SLO 和奖金、绩效挂钩,团队就会开始优化“指标表现”而不是优化“用户体验”。例如把坏请求从 selector 里剔除、在低峰期才发版、刻意减少大促流量等等。这些行为都会让 SLO 数字“看起来”达标,但用户感受到的质量并没有提升。SLO 应该当作一个工程决策的信息源,而不是绩效打分表。它告诉你什么时候该激进、什么时候该保守,但不该成为悬在团队头上的奖励之剑。
5.4 《九阴真经》的现代版本:内功心法到底是哪三招
回到标题那个外号。《九阴真经卷十二》为什么是 SLO 管理?因为在我眼里,SLO 就是 SRE 领域里最偏“内功”的一门功夫——它不直接产出功能,但能重塑团队的判断力。外功是监控系统、告警网关、自动化运维平台,内功则是面对不确定时,团队能不能用客观数据做决策。
这套内功心法浓缩下来就三招。第一招是“定义”:把“服务质量”翻译成可计算的指标,让好与坏有明确边界。第二招是“量化消耗”:用错误预算回答“我们还剩多少余地”,用燃尽率回答“按当前速度还能撑多久”。第三招是“闭环反馈”:告警、周报、变更评审,把 SLO 数字变成每次决策时的约束条件。
我在实际推动过程中体会到,最难的从来不是 PromQL 怎么写、告警阈值怎么调,而是让团队愿意承认“我们对用户的承诺可以被度量、可以被消耗、可以被打脸”。只要这一点想通了,SLOManager 这类工具链的价值就会立刻显现。它不会直接让系统变得更快,但会让每一次线上事故,都从一场争吵变成一次有数据支撑的校准。
