想象你是一位认真的健身爱好者。每天起床第一件事,是看手环上的静息心率和昨晚的睡眠报告;每周会站上体脂秤,记录体重和体脂率——这些数字,就是你的 SLI(服务水平指标)。基于数字,你给自己立下规矩:每周至少跑 3 次,每次 30 分钟,心率稳定在 130 到 150——这是你的 SLO(服务水平目标)。而你年初拍着胸脯跟家人保证:今年公司年会 5 公里赛一定完赛,否则承包全家一年奶茶——这是你的 SLA(服务水平协议)。光有目标和承诺还不够,你还悄悄给自己留了一个“偷懒额度”:一个月最多允许 3 次借口不跑。额度用完,再忙也得动起来。这篇文章要讲的 SLO/SLI/SLA 体系,就是给微服务系统做一次同样的“健康管理”——从模糊的“系统很稳”,到量化的指标、目标、承诺,再到驱动日常决策的错误预算。
对 AI 从业者的价值:掌握 SLO/SLI/SLA,你就能把“服务稳不稳”从感性判断变成可度量、可协商、可自动化的工程语言,这是从普通开发走向高可用架构师的关键一步。
可视化演示
展示SLI、SLO、SLA三层可靠性体系,错误预算的消耗与分配机制,以及燃尽率监控告警与超支判断。
本节配有交互动效(进入视口后自动加载,约 3KB)。
三层体系 SLI→SLO→SLA 指标→目标→合同 将可用性从模糊承诺转化为可度量的工程目标。
三层体系总览
你是一名信奉“科学健身”的工程师。手腕上的手环每天记录静息心率、睡眠深度、步数,体脂秤每周给出体脂率和肌肉量。这些数字本身不会让你变强壮,但它们是所有训练计划的起点——没有它们,“今天状态不错”只是一句感觉。在服务可靠性领域,这些原始数字就是 SLI(Service Level Indicator,服务水平指标),它是整座大厦的地基。
有了数字,你得给自己定目标:每周跑 3 次、每次 30 分钟、心率保持 130-150。这个目标只约束你自己,叫 SLO(Service Level Objective,服务水平目标)。而年初你对家人承诺的“5 公里赛完赛否则包一年奶茶”,是带有外部后果的契约,叫 SLA(Service Level Agreement,服务水平协议)。SRE 体系的精髓,就是把“感觉挺稳”翻译成这三层结构。
三层各有分工:SLI 是度量层,回答“我们测什么”;SLO 是目标层,回答“我们希望达到多少”;SLA 是契约层,回答“我们对外担保多少”。一个重要的工程原则是:SLA 的数值必须比 SLO 更宽松。比如内部 SLO 定 99.95%,对外 SLA 只承诺 99.9%,中间的 0.05% 是给意外留的缓冲垫,避免内部一次小失误就直接触发外部赔偿。
这就像你对外只承诺“35 分钟跑完 5 公里”,但训练时按“30 分钟完赛”准备。真到了比赛日,就算脚踝有点小伤、天气闷热,你也大概率能守住对家人的承诺——因为你的真实能力线,永远比对外承诺高出一截。
- SLA 承诺值写在合同里、对客户白纸黑字负责的可用性数值,通常附带赔偿条款,所以必须保守。
- SLO 目标值团队内部追求的可靠性水准,比承诺更严格,是日常工作的准绳。
- 大小关系价格承诺值在数值上不超过目标值,即“对外留余地,对内高标准”。
SLI指标选择
健身新手最容易犯的错是什么都记:体重、BMI、体脂率、臂围、腿围、最大摄氧量……记了两个月,哪个也没坚持下来。真正有效的做法,是围绕目标选 1-2 个强相关指标:想减脂就盯腰围和体脂率,想提升心肺就盯静息心率和配速。
选 SLI 也是同样的道理。一台微服务每秒吐出成千上万个观测信号:CPU、内存、QPS、错误数、延迟、GC 次数、连接池占用……但并不是每个信号都配当 SLI。SLI 必须是“用户能感知、业务能对齐”的指标——CPU 飙升但接口响应正常,用户毫无感觉,它就不该进入 SLO 的考核范围。
最经典的 SLI 是两类:比例型与分位型。比例型的代表是可用性,即成功请求占总请求的比例;分位型的代表是延迟,如 P99 延迟小于 200 毫秒,描述长尾体验而非平均体验。选择的原则有三条:与用户体验强相关、可精确采集、数量少而精——一个核心服务通常 3 到 5 个 SLI 足够。
就像健身房里真正的高手不会拿 20 个指标轰炸自己,而是盯住“静息心率”和“腰围”两个关键数字。服务的 SLI 也应该是这样一个“精简仪表盘”:成功率和 P99 延迟,往往比一整面墙的监控大屏更能说明问题。
- 成功请求数在统计窗口内正常返回的请求总数,是分子。
- 全部请求数成功与失败相加,代表这个窗口的总流量,是分母。
- 比例化成功数除以总数再乘以 100%,得到方便与 SLO 对照的百分数。
SLO目标设定
设定健身目标不能拍脑袋。你上周只能连续跑 3 公里,这周定 3.5 公里是合理挑战;直接定 10 公里,大概率是第一天就把腿拉伤,然后整个计划报废。好的目标,是“踮踮脚能够到”的水平。
SLO 的设定同理。它不是一个拿来炫耀的数字,而是一个“基于证据”的工程决策。团队通常回看过去 3-6 个月的 SLI 数据,找出系统在正常情况下的稳定水平,再在这个水平上留出余量,而不是凭空喊一个 99.999%。
具体做法上,可以取历史 SLI 的分位数作为候选目标。比如过去半年可用性的 P90 是 99.95%,那就把 SLO 定在 99.9% 或 99.95% 之间。这里有个硬约束必须明白:每多一个"9",错误预算就缩小一个量级,而实现和维护成本近乎翻倍。99.9% 允许每月故障 43 分钟,99.99% 只有 4.3 分钟——后者对发布、变更、容灾的要求都苛刻得多。
目标定得越狠,你的“偷懒额度”就越少。一个月只能偷懒 4 分钟,意味着几乎每天都不能出错;而 43 分钟的额度,好歹允许你偶尔熬夜看场球。SLO 不是在比谁的数字漂亮,而是在为团队争取“可持续的喘息空间”。
- 不可用占比1 减去 SLO 得到允许失败的时间比例,SLO 越接近 1,这个数越小。
- 周期总时长T 是统计窗口时长,如 30 天等于 43200 分钟。
- 乘法换算比例乘以总时长,得到窗口内允许中断的最大分钟数,例如 43.2 分钟。
错误预算机制
你给自己定了“每周跑 4 次”的目标。但生活总有意外:出差、加班、暴雨、感冒。所以你在心里设了一个“偷懒额度”:一个月最多允许 3 次不跑。额度用完,剩下的日子哪怕下雨也要在家练核心。这个偷懒额度,就是服务界的“错误预算”(Error Budget)。
错误预算的概念简单到让人怀疑:它是 1 减去 SLO。SLO 是 99.9%,错误预算就是 0.1% 的时间——一个月 43.2 分钟。整个窗口期内,所有故障、发布事故、性能劣化造成的不可用时间,都得从这 43.2 分钟里扣。
关键在“消耗”二字。系统每天都在消耗预算:某天可用性 99.98%,说明当天消耗了 0.02% 的预算;一次 20 分钟的 P0 故障,直接烧掉接近一半。因此团队必须持续追踪两个量:剩余预算(存量)和消耗速率(流量)。如果月初就烧掉了 40 分钟,月底几乎必然破线——这时候 SLO 已经名存实亡。
偷懒额度本质上是风险管理的仪表盘。它不评判“熬夜看球”是对是错,只是冷冰冰地告诉你:额度还剩多少,还能不能浪。服务也一样——错误预算不阻止你发布,但它会诚实记录每一次冒险的代价。
- 预算总额1 减去 SLO 是整个窗口允许的失败比例,是错误预算的本金。
- 每日消耗1 减去第 t 天的 SLI 得到当天实际失败比例,比如可用性 99.98% 就消耗 0.02%。
- 累计求和把整个窗口每一天的消耗累加起来,得到已消耗总额。
- 剩余预算本金减去累计消耗,大于 0 表示安全,小于等于 0 表示破线。
预算驱动决策
当偷懒额度只剩一次时,你的行为会自动改变:推掉晚上的火锅局,取消下周的爬山计划,把时间留给必要的训练。额度余额,成了你安排生活的“总开关”。
错误预算的最大价值,不是“算出来看”,而是“驱动决策”。它把可靠性从一句口号变成一把客观标尺,让发布、救火、扩容这些日常动作都有了统一的依据。
最典型的是三个场景。一是发布门禁:CI/CD 流水线在发布前查询剩余预算,若预算不足或已耗尽,自动拦截版本上线,防止在脆弱的系统上再叠加变更风险。二是故障优先级:多个告警同时爆发时,不再“谁叫得响先救谁”,而是按预算消耗速率排序,优先处理即将击穿 SLO 的故障。三是容量规划:大促前通过压测估算活动会消耗多少预算,反推需要预留多少冗余容量,让“加多少机器”有了数学依据。
这就像游戏里的体力条:体力充足,你可以放心推图、挑战 BOSS;体力见底,系统自动切到“挂机回血”模式。错误预算驱动的服务,也拥有了这样的“体力值”——它让整个团队在同一套规则下行动,而不是每次都由某个人拍脑袋。
- 正余额放行剩余预算大于 0,说明系统还有容错空间,可以接受新变更。
- 零负冻结剩余预算小于等于 0,系统已处于危险区,一切非必要变更暂停。
工程实践落地
光有健身计划和偷懒额度还不够。你还需要手环、体脂秤、训练 App,以及每周日晚上雷打不动的复盘。工具决定数据,数据决定坚持。SLO 体系要真正跑起来,同样需要一套“可观测装备”。
落地可以拆成四件事:埋点采集、实时聚合、告警策略、定期复盘。缺了任何一环,SLO 都只是文档里的一行字。
第一,埋点采集:在服务入口和出口埋下 SLI 相关计数,如请求总数、成功数、耗时分布、错误码,注意用统一协议透传,避免多语言、多团队各搞一套。第二,实时聚合:用 Prometheus 这类系统按滑动窗口计算可用性和延迟分位数,窗口要“滚动”而不是每天重置,才能真实反映累积消耗。第三,告警策略:不要等预算耗尽才告警,而是跟踪消耗速率——例如“按当前速率将在 7 天内耗尽预算”时就触发预警,多窗口配合(短窗口捕捉突变、长窗口判断趋势)减少误报。第四,月度复盘:回顾 SLO 达成率,把预算消耗大的变更和故障拎出来分析,动态调整 SLO 和容量。
手环一周不充电,顶多是少几天数据;可观测系统一旦失灵,架构师就像蒙眼开车。装备齐全之后,“上个月偷懒了几天、哪次熬夜最伤身”就一目了然——服务也一样,数据越完整,决策越清醒。
生产案例复盘
年底的体检报告是最好的老师。去年体脂超标,今年就重点练力量;去年跑量不足,今年就把跑量写进周计划。生产案例复盘,就是服务团队的“年度体检”。
案例一:电商大促的预算预留与大促保护。某电商平台在双 11 前将核心交易链路的 SLO 定为 99.95%,并预留出 50% 的错误预算给大促当天。压测发现商品详情页 P99 延迟超过目标,团队在大促前一周完成缓存优化;活动当天监控显示预算消耗速率逼近预警线,团队果断降级了“个性化推荐”等非核心模块,确保下单主链路没有击穿 SLO。
案例二:支付链路的外部依赖熔断。某支付系统大量依赖第三方结算渠道,渠道抖动直接让可用性 SLI 波动。团队为外部依赖设置了熔断阈值:当依赖失败率超过 SLO 容忍范围时,快速熔断并返回降级提示,避免第三方故障持续消耗错误预算。上线后,因外部原因导致的预算消耗下降了 60%。
用数据说话:假设某服务当月发生两次故障,分别持续 20 和 15 分钟,当月实际可用性可以精确算出。
体检报告不会因为你“感觉身体挺好”就放过你。错误预算同样忠实记录每一次故障、每一次决策失误。复盘的真正价值,是让下一次大促不再踩同一个坑——把经验沉淀成新的 SLO、新的告警、新的容量基线,这才是三层体系持续进化的闭环。
- 总时长43200 是 30 天换算成的分钟数,即 30 乘 24 乘 60。
- 故障时长35 是两次故障的累计分钟数,即 20 加 15。
- 求比值可用时间除以总时长,得到当月实际可用性约为 99.92%。
AI 应用场景
发布门禁:把错误预算写进 CI/CD 流水线
阶段:部署与变更管理
解决的问题:传统发布靠“经验判断”或“人工审批”,无法量化当前风险。基于错误预算的发布门禁,让流水线自动查询剩余预算,不足就拦截,把风险挡在门外。
具体案例:某互联网金融团队在 GitLab CI 中增加“预算检查”阶段:每次合并前查询 Prometheus 中的剩余错误预算,若剩余比例低于 20% 则自动失败,要求先解决可靠性问题再发布。上线后,由发布引发的 SLO 破线事故减少了 70%。
故障分诊:按预算消耗速率排优先级
阶段:告警与事件响应
解决的问题:故障多的时候,值班工程师凭嗓门和直觉救火,容易错过“消耗预算最猛”的严重故障。按预算消耗速率排序,让优先级由数据决定。
具体案例:大促期间同时出现 5 个告警:A 服务错误率微升但预算消耗慢,B 服务 P99 延迟翻倍且按当前速率 3 小时后将耗尽预算。系统自动把 B 标为 P0,值班人员优先处理 B,成功保住核心链路。
容量规划:用预算反推机器数量
阶段:容量与成本规划
解决的问题:大促前“拍脑袋加机器”要么浪费预算、要么不够。通过压测估算活动消耗的错误预算,反推需要多少冗余。
具体案例:某电商平台双 11 前用全链路压测,得到“满负荷 4 小时消耗 15 分钟预算”的结论,据此增加 20% 的冗余节点,确保活动期间 SLO 不破线。
Python 演示
"""SLO/SLI/SLA 落地演示: 可用性计算 + 错误预算消耗跟踪""" def calc_sli(success_count: int, total_count: int) -> float: """计算可用性 SLI: 成功请求数 / 总请求数""" if total_count == 0: return 1.0 return success_count / total_count def calc_error_budget(slo: float, window_days: int) -> float: """计算错误预算: 窗口期内允许的最长故障时长(分钟)""" total_minutes = window_days * 24 * 60 return total_minutes * (1 - slo) def track_budget(budget_minutes: float, daily_failure_minutes: list) -> None: """按日扣减错误预算, 输出每日剩余""" remaining = budget_minutes for day, fail_min in enumerate(daily_failure_minutes, 1): remaining -= fail_min print(f"第{day:>2}天 故障{fail_min:>6.1f}分钟 剩余{remaining:>7.2f}分钟") if remaining <= 0: print(f" >>> 预算耗尽, 冻结发布并优先修复可靠性!") if __name__ == "__main__": slo = 0.999 window_days = 30 budget = calc_error_budget(slo, window_days) print(f"SLO={slo:.1%}, {window_days}天窗口错误预算={budget:.2f}分钟") total_per_day = 10_000_000 fail_counts = [ 420, 380, 505, 460, 610, 355, 7520, 430, 480, 410, 505, 620, 470, 390, 520, 680, 455, 520, 9100, 610, 480, 430, 380, 590, 1500, 760, 980, 470, 410, 380, ] print("\n前 7 天可用性 SLI:") for day in range(7): fail_count = fail_counts[day] sli = calc_sli(total_per_day - fail_count, total_per_day) print(f" 第{day + 1}天 SLI={sli:.6%}") # 折算每日故障分钟数: 假设高峰期每秒处理 5000 个核心请求 daily_failure_minutes = [fail_count / 5000 for fail_count in fail_counts] print("\n错误预算消耗跟踪:") track_budget(budget, daily_failure_minutes)
def calc_sli(success_count: int, total_count: int) -> float:定义可用性 SLI 的计算函数,输入成功数和总数return success_count / total_count返回成功比例,即当天可用性 SLItotal_minutes = window_days * 24 * 60把窗口天数换算成总分钟数,为预算计算做准备return total_minutes * (1 - slo)错误预算等于总分钟数乘以允许失败占比remaining -= fail_min每天把故障分钟数从预算中扣掉,模拟实际消耗if remaining <= 0:判断预算是否耗尽,触发冻结发布的决策信号budget = calc_error_budget(slo, window_days)实例化 30 天 99.9% SLO 的总预算(43.2 分钟)daily_failure_minutes = [fail_count / 5000 for fail_count in fail_counts]把失败请求数折算为故障分钟数,便于预算扣减sli = calc_sli(total_per_day - fail_count, total_per_day)计算当天可用性百分比,展示 SLI 的日常形态
常见误区
误区“老板,我们系统很稳定,SLO 直接定 99.999%!”觉得 9 越多越有面子,对外汇报也好看。
正解每多一个 9,错误预算就缩小一个量级。99.999% 意味着一个月只能坏 43 秒,任何变更都可能瞬间击穿预算,最后团队不敢发版、不敢重构,反而拖慢迭代。SLO 应该是“基于历史数据和用户体验的成本最优解”,不是炫技。就像健身目标定成“每分钟心跳 30 次”,那不是自律,是危险。
为何常见:因为“SLO 越高=越可靠”的直觉,加上对外汇报时数字更好看,容易让人忽略背后的工程代价。
误区“我们把 CPU、内存、磁盘、QPS、GC、错误码全都设为 SLI,这样监控最全面。”
正解SLI 必须与用户体验强相关,不是所有技术指标都配当 SLI。CPU 高但接口响应正常,用户无感,它就不该进入 SLO 考核。指标太多会导致告警泛滥、目标难以收敛,团队在“狼来了”中变得麻木。健身同理:每天记录 30 个数据,不如盯住 1 个静息心率。
为何常见:把“可观测性”误解为“指标越多越好”,忽略了 SLI 的本质是筛选而非堆砌。
误区“SLA 就是 SLO 的书面版,我们定了 SLO 就等于有了 SLA。”
正解SLO 是内部对自己的要求,SLA 是对外的契约,通常附带赔偿条款。SLA 的数值必须比 SLO 更宽松,否则一次内部失误就直接触发外部赔偿。这就像你对家人承诺“5 公里跑 35 分钟”,但自己训练按 30 分钟来,留 5 分钟缓冲。
为何常见:两者都长着“99.9%“的样子,名字里都有”服务“和”水平”,很容易混为一谈。
误区“预算还有一半呢,这周连发三次版本,只要不破 SLO 就行。”
正解预算充足只代表系统“承担得起一定的风险”,不代表变更没有风险。一次发布可能同时消耗多个 SLI 的预算;更合理的做法是给单次发布设“预算消耗上限”,比如一次发布最多消耗 10% 预算,超过就回滚。就像偷懒额度够,你也不能连熬三天夜——身体承受的是系统性风险。
为何常见:把错误预算当成“免费额度”,忽略了变更的叠加风险与恢复成本。
误区“反正有监控,预算归零的时候告警就好了。”
正解预算归零时 SLO 已经失守,告警只是宣告失败。更好的做法是跟踪消耗速率:如果按当前速度会在 7 天内耗尽预算,应提前触发预警,让团队有时间干预。健身里这叫“提前止损”:不是等体检报告亮红灯才调整作息。
为何常见:把错误预算理解成静态存量,忽略了时间维度的消耗速率与预警价值。
面试题
Q1. 在 SLO/SLI/SLA 体系中,把用户可感知的服务质量转化为具体数字的是?
- A.SLA 对外契约
- B.SLI 量化指标← 正确答案
- C.SLO 内部目标
- D.错误预算机制
答案:B。SLI 是把体验变成数字的度量层,比如成功率、P99 延迟。SLA 是契约,SLO 是目标,错误预算由 SLO 推导而来。就像手环上的心率数字是“体验”的量化,属于 SLI 的职责。
Q2. 某服务 SLO=99.9%,则 30 天窗口的错误预算是多少分钟?
- A.约 4.3 分钟
- B.约 43.2 分钟← 正确答案
- C.约 432 分钟
- D.约 720 分钟
答案:B。30 天等于 43200 分钟,错误预算等于 43200 乘以(1 减 0.999),即 43.2 分钟。这就是“偷懒额度”的精确数值。
Q3. 错误预算耗尽后,团队最合理的动作是?
- A.加班发布积压的功能
- B.把 SLO 调低继续发布
- C.冻结高风险变更优先修复← 正确答案
- D.重启服务等待预算恢复
答案:C。预算耗尽意味着系统已处于不可接受的不稳定状态,应冻结高风险变更、集中资源修复可靠性。调低 SLO 是自欺欺人,重启也改变不了已消耗的事实。
Q4. 以下哪些指标适合作为服务的 SLI?
- A.请求成功率← 正确答案
- B.延迟 P99 分位值← 正确答案
- C.服务器风扇转速
- D.代码注释覆盖率
答案:AB。SLI 必须直接反映用户体验。成功率与延迟是最典型的 SLI;风扇转速属于基础设施细节,注释覆盖率是代码质量指标,都不宜作为 SLI。
Q5. SLA 与 SLO 的正确关系是?
- A.SLA 必须比 SLO 更严格
- B.SLA 通常比 SLO 更宽松← 正确答案
- C.两者数值必须完全一致
- D.SLA 由开发团队私下制定
答案:B。对外承诺要留缓冲,所以 SLA 的可用性数值通常小于等于 SLO。比如 SLA 99.9%,内部 SLO 99.95%,即使内部偶尔失守,对外仍不违约。
Q6. 错误预算可以驱动哪些工程决策?
- A.发布节奏门禁← 正确答案
- B.故障处理优先级← 正确答案
- C.容量冗余规划← 正确答案
- D.代码风格统一
答案:ABC。发布前查预算、故障按消耗速率排序、容量按预算消耗反推,都是预算驱动的典型场景;代码风格与可靠性预算无关。
Q7. 某服务 30 天发生两次故障,分别持续 20 和 15 分钟,当月实际可用性约为?
- A.99.88%
- B.99.92%← 正确答案
- C.99.95%
- D.99.98%
答案:B。总时长 43200 分钟,故障共 35 分钟,可用性等于(43200 减 35)除以 43200,约 99.919%,四舍五入为 99.92%。
Q8. 错误预算的计算公式是?
- A.错误预算等于 SLO 乘以 1
- B.错误预算等于 1 减 SLO← 正确答案
- C.错误预算等于 SLO 加 1
- D.错误预算等于 1 除以 SLO
答案:B。总时间为 100%,SLO 承诺了可用占比,剩下的 1 减 SLO 就是允许失败的占比,即错误预算。
Q9. 设定 SLO 目标时,应考虑哪些因素?
- A.近 3-6 个月的历史 SLI← 正确答案
- B.依赖组件的可靠性上限← 正确答案
- C.用户可感知的性能边界← 正确答案
- D.团队代码评审的严格程度
答案:ABC。SLO 要基于历史数据、依赖极限和用户体验边界来定。代码评审严格度影响质量,但不直接决定 SLO 数值。
Q10. 可用性 SLI(成功数/总数)在数学上属于哪种类型?
- A.比例型指标← 正确答案
- B.事件型指标
- C.分位型指标
- D.均值型指标
答案:A。成功数除以总数得到的是一个比例,属于比例型指标。P99 延迟属于分位型,故障次数属于事件型,平均延迟属于均值型。