sre

SRE 工具

不含糊的 SRE 算术:SLI、SLO、SLA 有什么区别,每一个可用性目标换算成真实分钟是多少,以及燃烧率如何把一个 SLO 变成告警阈值。

3 工具

§01 领域指南

SLI、SLO、SLA 是三个不同的数

SLI 是一次测量:好事件除以有效事件——在到达负载均衡器的全部请求里,300 毫秒内以 非 5xx 状态被应答的那些。SLO 是这个比值在某个窗口上的目标,比如滚动 30 天内 99.9%SLA 则是把钱挂到一个通常更宽松的目标上的合同。把它们混为一谈,就会出现 凌晨 3 点为一个谁都没答应要守住的数字把人叫起来。

难的地方是 SLI 的定义,不是那个百分比。两个都声称 99.9% 的团队,含义可能完全不同: 429 算不算错误、健康检查是否进分母、测量点在 CDN 边缘还是在服务内部。先把分子和 分母定下来,再去争几个九。

SLO 随后会导出唯一一个真正改变行为的数:错误预算100% − SLO。在 30 天窗口上 的 99.9%,你可以失败 0.1% 的请求,或者完全宕机 43.2 分钟。它是一种货币——发布和迁移 在花它,新窗口会补充它,而一个月结束时停在 100% 通常意味着你发布得太慢了。

把可用性目标换成真实分钟

几个九反直觉,分钟不会。每多一个九,允许的停机就除以十。

可用性每年(365 天)每 30 天月每周每天
99%3 天 15.6 小时7.2 小时1.68 小时14.4 分钟
99.5%1 天 19.8 小时3.6 小时50.4 分钟7.2 分钟
99.9%8.76 小时43.2 分钟10.1 分钟1.44 分钟
99.95%4.38 小时21.6 分钟5.04 分钟43.2 秒
99.99%52.6 分钟4.32 分钟60.5 秒8.64 秒
99.999%5.26 分钟25.9 秒6.05 秒0.86 秒

到 99.9% 为止,一个人还能在预算之内察觉、诊断并修复。到了 99.99%,每月的额度是 4.32 分钟——那是关于自动故障切换的承诺,不是关于值班的承诺。

燃烧率:从 SLO 到告警阈值

燃烧率是观测到的错误率除以 SLO 允许的错误率。真正有用的恒等式是 已消耗预算 = 燃烧率 × (窗口 ÷ SLO 周期):它把一次短时间的观测变成关于整个月的论断。

燃烧率99.9% SLO 下的错误率全新的 30 天预算多久烧完典型响应
0.1%30 天不告警
0.6%5 天呼人(6 小时窗口,已烧 5%)
14.4×1.44%50 小时呼人(1 小时窗口,已烧 2%)
100×10%7.2 小时立刻呼人
1000×100%,完全宕机43.2 分钟定为事故

给每个快速阈值配一个更短的确认窗口(14.4× 配 5 分钟, 配 30 分钟),这样事故 结束时告警也会跟着解除。慢速燃烧属于工单,不属于呼人。

哪个工具回答哪个问题

手上是一个百分比、需要它的时间等价值时,找 SLA 正常运行时间计算器: 它把 0 到 100 之间的任意值换算成每年、每 30 天月、每周和每天允许的停机时长,预设从 90%99.999%。这是合同评审用的工具。

当这个数字必须驱动工程决策时,改用 错误预算计算器。给它一个 SLO、一个以天为单位的窗口和预期流量;它会把预算同时表示成百分比、允许停机时长,以及 可以失败的请求数——30 天窗口的 99.9% 下,一百万里面允许 1,000 个,这个数字在部分降级 的场景下仍然成立,而停机时长不成立。

先要定下哪些响应算“坏”。HTTP 状态码参考 是一个码到含义的查询表—— 每个码给出名称、分类和一行描述,可按数字或关键词过滤——于是 400(“无法理解该请求”) 和 422(“格式正确但语义无效”)当场就能分清。它标出了 307308 保留方法,但对 301 会对 POST 做什么只字未提:客户端可能把它改写成 GET 并丢掉请求体,这也是为什 么一个永久迁移的 POST 端点需要 308。要看一个线上端点实际返回什么, HTTP 头信息检查工具api.sitekits.dev 发起请求,报告最终状态、 重定向跳数、响应时间和每一个响应头;正文从不获取,私有地址或 localhost 目标会被它的 SSRF 防护拒绝。需要请求体、认证头或者 POSTREST API 测试器 从你的浏览器直连目标,所以目标的 CORS 策略会生效。更多内容在 HTTP 工具集 里,那边的重定向矩阵把 301302303307308 并排对照。

要延迟方面的证据,就在 HAR 文件查看器 里打开 DevTools 的导出:每个 请求的方法、状态、类型、大小和耗时,4xx/5xx 高亮。附到工单之前先用 HAR 文件清洗器 脱敏——authorizationcookiex-api-key、 形似令牌的参数和所有正文都会变成 [REDACTED]

排程、窗口与时钟

cron 是可靠性工作悄悄崩掉的地方。Crontab 表达式编辑器 解析五 字段表达式,并按浏览器本地时区列出接下来八次触发时间。这张表要当两件事来读:所有 cron 共有的字段取值范围,以及这个编辑器实际能解析的那套更窄的语法——整数与 *、列表、范围 和步长的组合,别的都不行。

字段范围编辑器接受的形式别处合法、这里被拒
0–59*5,200-30*/15
0–23同上
1–31同上LW(Quartz、AWS)
1–12同上JANDEC 名称(Vixie、cronie)
0–60 = 周日)同上7 表示周日以及 SUNSAT(Vixie、cronie);5#3(Quartz)

最后那一列里的所有东西都以同一条消息失败—— Invalid cron expression (expected 5 fields)——即使字段确实有五个,所以 0 3 * * 7 看起来像是数错了,其实是用词不对。周日要写成 0。行级宏(@daily@reboot)和带秒的六字段方言会以同样方式被拒,反向范围也一样——22-2 要写成 22-23,0-2。有一种形式则是静默地失败——5/15 被读成单个值 5,而 Kubernetes 风格的 解析器会把它展开成 5-59/15,所以请把范围写全。

还有三件表格显示不了的事。在日期组合上,编辑器应用 POSIX 的“任一匹配”规则——当日和周 两个字段都被限定时,0 0 1 * 1 表示每月 1 日以及每个周一——但它是按文本来判断 是否被限定的,把任何以 * 开头的日期字段都算作未限定。步长会从这个判断里溜过去: 日字段里的 */3 被读成未限定,于是 0 0 */3 * 1 变成关系,只在落在 1、4、7 号等等的周一触发。把那些日子写成 1-31/3,就能把“任一匹配”规则拿回来。步长切分的是 字段而不是时钟——分钟上的 */7 会在 :00 到 :56 运行,然后带着一个 4 分钟的间隙重新 开始。另外,预览用的是你浏览器的时区,而宿主机时钟通常是 UTC。

事故时间线需要同样的严谨:Unix 时间转换器 把小于 1e12 的值读作秒、更 大的读作毫秒,而 时区转换工具 会在你宣布维护窗口之前,把 同一个时刻钉在 12 个 IANA 时区上并带上正确的 DST 偏移。更多值班工具箱内容: 面向 SRE 的工具

常见错误

合同里的“月”不是计算器里的“月”

计算器用的是固定的 30 天月和 365 天年。按自然月算,一个 99.9% 的 SLO 在 28 天的二月 允许 40.32 分钟,在七月允许 44.64 分钟——同样的措辞,摆动了 10%。

可用性在依赖链上是乘出来的

三个各自 99.9% 的强依赖串联起来,得到 0.999³ = 99.70%:大约每月 2.16 小时停机,不是 43.2 分钟。没有冗余,你能承诺的上限就是关键路径的乘积。

基于时间和基于请求数的预算不能互换

允许停机时长这个数字假设宕机期间错误率是 100%。一次让 5% 请求失败的降级,会以 50× 烧掉 99.9% 的请求预算,而由合成探测驱动的正常运行时间钟表几乎不动。

你的探测间隔就是分辨率的下限

60 秒一次的合成检测看不见一次 20 秒的中断,而每一次漏掉的探测大约记成一分钟——已经是 99.99% 月度预算的 23%。三个九以上,请从请求日志测量,而不是靠轮询。

FAQ
99.9% 的可用性到底允许多长的停机?
每年 8.76 小时,30 天的月份 43.2 分钟,每周 10.1 分钟,每天 1.44 分钟。如果你的合同按自然月计量,同一个 99.9% 的目标会随月份长度变化:28 天的二月是 40.32 分钟,31 天的月份是 44.64 分钟。比数字之前,先看 SLA 的计量条款。
错误预算燃烧率是什么,什么时候该呼人?
燃烧率是你观测到的错误率除以 SLO 允许的错误率,所以一个 99.9% 的 SLO 上出现 1.44% 的错误,就是 14.4 倍在烧。已消耗预算等于燃烧率 × (告警窗口 ÷ SLO 窗口),这就是为什么 14.4 倍持续 1 小时会花掉 30 天预算的 2%、值得呼人,而 1 倍持续 3 天花掉 10%、只值得开一张工单。给每个阈值再配一个更短的确认窗口(14.4 倍配 5 分钟,6 倍配 30 分钟),可以避免恢复之后告警反复抖动。
内部 SLO 应该和我对外卖的 SLA 一样吗?
不应该——SLO 要比 SLA 更紧,因为这段差距就是你的运营余量。一个内部 99.9% 的 SLO 挡在 99.5% 的合同 SLA 前面,会在“没达到自己的目标”(43.2 分钟)和“要赔服务积分”(3.6 小时)之间留出大约 2.9 小时的月度余地。如果两者相等,第一次违约就同时是工程信号和账单事件。
我的 cron 任务为什么在错误的时间触发?
通常有三个原因。宿主机时钟是 UTC,而你是按本地时间推理的,所以 UTC 服务器上的 0 3 * * * 会在 Asia/Tokyo 的 12:00 触发。夏令时会让一个 02:30 的本地任务在切换日跑两次或一次都不跑。还有,当日和周两个字段都被限定时,POSIX cron 会把它们做“或”处理,于是 0 0 1 * 1 会在每月 1 日以及每个周一都运行——不是只在恰好是 1 日的周一运行。
要测一个 99.99% 的 SLO,合成检测得多久跑一次?
答案是“比现实可行的频率更频繁”:在 99.99% 上,整个 30 天预算只有 4.32 分钟,所以 60 秒一次的探测根本看不见一次 20 秒的中断,而漏掉一次探测就大约记成一分钟——一个数据点吃掉整月的 23%。探测间隔是测量分辨率的下限,所以三个九以上请从请求日志测 SLI(好事件除以有效事件),把合成检测留给粗粒度的可达性和第三方检查。在 99.9% 上预算是 43.2 分钟,60 秒的探测就是相称的。