SLO、SLA 与错误预算
正在读取学习记录…
用户希望资料助手在2秒内给出可用答案。运营团队需要知道过去一天是否做到了,并决定今天能否发布新版本。SLI(服务水平指标)是实际测出来的质量比例;SLO(服务水平目标)是希望该比例达到的目标;SLA(服务水平协议)是对外约定的承诺,以及未达到时怎样处理。
正常例子中,1000次有效请求有990次业务成功且在2秒内完成,SLI为99%;目标99%时刚好达到SLO。SLA还需要约定统计窗口、适用范围和违约后果,例如服务抵扣,不能从一个内部指标自动推导合同承诺。Google SRE 的服务目标章节对这三个概念及目标选择有系统说明。
先决定一次请求怎样算好
“HTTP返回200”与“用户得到可用答案”之间还有距离。这里把好请求定义为:业务成功完成,并且端到端耗时不超过2000毫秒。有效请求包括超时、下游失败和容量不足的业务请求;无效输入如何排除,要预先定义并固定,避免为提高指标临时改分母。
固定窗口包含950次成功400毫秒、30次成功800毫秒、20次失败3000毫秒。这1000条是教学数据,程序负责按统一判据统计。
| 指标 | 公式及代入 | 结果 |
|---|---|---|
| 好请求比例SLI | 980 ÷ 1000 | 98% |
| 目标SLO | 给定目标0.99 | 99% |
| 允许坏请求 | 1000 × (1 − 0.99) | 10次 |
| 实际坏请求 | 1000 − 980 | 20次 |
| 剩余错误预算 | 10 − 20 | −10次 |
错误预算是服务目标允许的失败空间。剩余为负表示已超出窗口预算;团队可约定暂停增加风险的发布,优先恢复可靠性。预算是运营策略输入,并不会自动修复故障。
图上方按1000条固定记录画出980个好请求占98%、20个坏请求占2%的比例;下方单独比较允许10次与实际20次,帮助看出预算超支。
计算预算并检查延迟分位数
p95表示排序后覆盖95%样本的延迟。示例使用最近秩法:位置 ceil(0.95 × 1000) = 950,第950项是400毫秒。因此p95看起来很快,但20次失败仍消耗预算。可用性与延迟指标要分别观察,不能只选最好看的那个。
建立新文件夹 l8-slo,保存 error_budget.py 和 test_error_budget.py。程序使用固定记录与十进制目标,直接输出预算和发布策略。
先在 PowerShell 创建并进入目录,再保存下方两份文件:
New-Item -ItemType Directory -Force l8-slo
cd l8-slomacOS 终端:
mkdir -p l8-slo
cd l8-slo"""从预设请求记录计算用户可感知成功率和错误预算。"""
from decimal import Decimal
from math import ceil
TARGET = Decimal("0.99")
# 每项为(服务是否成功完成、端到端毫秒数);共1000条固定记录。
REQUESTS = [(True, 400)] * 950 + [(True, 800)] * 30 + [(False, 3000)] * 20
def summarize(requests, target):
if not Decimal("0") < target <= Decimal("1"):
raise ValueError("目标必须大于0且不超过1")
if not requests:
raise ValueError("窗口内没有有效请求")
total = len(requests)
# 业务成功且在2秒内完成才算好请求,超时也消耗错误预算。
good = sum(ok and elapsed <= 2000 for ok, elapsed in requests)
bad = total - good
allowed = Decimal(total) * (1 - target)
remaining = allowed - bad
# 用最近秩定义p95:排序后第 ceil(0.95*N) 项。
latencies = sorted(elapsed for _, elapsed in requests)
p95 = latencies[ceil(0.95 * total) - 1]
return total, good, bad, allowed, remaining, p95
def main():
total, good, bad, allowed, remaining, p95 = summarize(REQUESTS, TARGET)
print(f"窗口: {total} / 好请求: {good} / 坏请求: {bad}")
print(f"SLI: {Decimal(good) / total * 100:.2f}% / SLO: {TARGET * 100:.2f}%")
print(f"允许坏请求: {allowed:.0f} / 剩余预算: {remaining:.0f}")
print(f"p95: {p95}毫秒")
print("发布策略:", "冻结非修复发布" if remaining < 0 else "允许受控发布")
if __name__ == "__main__":
main()测试文件 test_error_budget.py:
"""检验窗口、成功判据、最近秩和预算耗尽的边界。"""
from decimal import Decimal as D
import unittest
from error_budget import REQUESTS, summarize
class BudgetTests(unittest.TestCase):
def test_baseline(self):
self.assertEqual(summarize(REQUESTS, D("0.99")),
(1000, 980, 20, D(10), D(-10), 400))
def test_revised_target(self):
self.assertEqual(summarize(REQUESTS, D("0.97"))[4], D(10))
def test_budget_exactly_zero(self):
self.assertEqual(summarize([(True, 1)] * 99 + [(False, 1)], D("0.99"))[4], D(0))
def test_latency_and_business_success(self):
self.assertEqual(summarize([(True, 2000), (True, 2001), (False, 10)], D("0.9"))[1:3],
(1, 2))
def test_empty_and_invalid(self):
with self.assertRaises(ValueError):
summarize([], D("0.99"))
for target in (D(0), D("1.1")):
with self.assertRaises(ValueError):
summarize(REQUESTS, target)
if __name__ == "__main__":
unittest.main()文件保存后,在同一窗口核对文件名并运行:
ls
python -X utf8 error_budget.py
python -X utf8 -m unittest -v test_error_budget.pydir应显示这两个文件。运行程序后得到下面输出;测试末尾应显示 OK。
程序输出:
窗口: 1000 / 好请求: 980 / 坏请求: 20
SLI: 98.00% / SLO: 99.00%
允许坏请求: 10 / 剩余预算: -10
p95: 400毫秒
发布策略: 冻结非修复发布改变目标会改变哪一个数字
在 error_budget.py 把 TARGET = Decimal("0.99") 改成 TARGET = Decimal("0.97"),保存后运行:
python -X utf8 error_budget.pySLI仍为98.00%,p95仍为400毫秒;SLO变为97.00%,允许坏请求30,剩余预算10,发布策略变为“允许受控发布”。恢复 TARGET = Decimal("0.99") 并重新运行,回到冻结策略。
这个动作帮助区分测量与目标:数据未改变,目标降低并没有改善用户体验。实际调整SLO应基于业务需求与服务成本,经约定后作用于明确窗口;不能用临时放宽目标掩盖当前事故。
预算如何进入值班和发布
生产统计需要固定窗口,例如滚动30天;滚动表示每天移除最早一天、加入最新一天。一次1000请求样本的计算不能直接代表整月预算。对于按请求比例计算的目标,允许失败次数随有效请求数量变化;按时间可用性计算的目标,则用总时长乘允许失败比例,两种分母应明确选择。
消耗速率也有用。若目标允许1%坏请求,而最近10分钟出现5%坏请求,预算燃烧率为 5% ÷ 1% = 5:以长期允许速率的5倍消耗。短窗口帮助发现快速故障,较长窗口帮助过滤噪声;低流量时一两个请求就可能产生大幅比例变化,需要同时观察样本量。
| 现象 | 判断 | 动作 |
|---|---|---|
| p95达标但好请求比例不足 | 尾部失败影响用户 | 查超时和下游错误 |
| 剩余预算恰好为0 | 当前窗口刚好用完 | 按策略限制下一步风险 |
| 预算为负且故障仍增长 | 继续消耗,目标已失守 | 先止损,再定位 |
| 没有有效请求 | 指标缺少数据 | 返回无数据,不能记100% |
Agent还可设置质量SLI,如“回答有可验证来源的比例”,但需要稳定的判定规则和样本。把可用性、延迟、质量及成本分开定义,发布时检查它们的组合,才不会因一个状态码成功而忽视业务失败。
课后练习展开习题收起习题
正在读取本地记录…
不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。
选择题 · 先判断边界
关于“SLO、SLA 与错误预算”,哪种做法更稳妥?
对应知识点:L8-slo
简答题 · 解释失败
写出一个失败输入并说明记录字段。
对应知识点:L8-slo
代码题 · 边界测试
补充正常、边界、失败三组输入和预期结果。
对应知识点:L8-slo
场景题 · 结果未知
证据不足时如何设计状态和人工接管?
对应知识点:L8-slo
下一篇灰度、Feature Flag与回滚用观测结果决定发布方向。
描述会发送给本站维护者,用于修订文章,保存90天。请只填写文章问题,省略个人信息、密钥和内部资料。