错误预算(error budget)是站点可靠性工程里连接服务等级目标(SLO)和日常运维的关键概念。简单来说,如果约定接口月度成功率为 99.9%,那么剩下的 0.1% 就是这段时间内允许出错的请求配额,也就是错误预算。用 Python 做消耗追踪,核心是把分散在日志、监控系统中的错误事件聚合成可量化的预算消耗曲线,让团队能看清“钱”还剩多少。

一、错误预算的基础模型
假设某接口设定了月度 SLO:成功率不低于 99.9%,统计窗口为 30 天。若这 30 天总请求量为一千万次,则允许失败次数为 1000 万 × 0.1% = 10000 次。这就是初始错误预算。随着真实流量进来,每次 5xx 或超时都算一次消耗。很多团队只盯成功率曲线,但成功率在流量低时即使错几笔也会骤降,流量高时反而显得平稳,所以必须回归到“预算余数”这一绝对指标。
在 Python 中,可先定义预算类,把总量、已用、窗口起止时间封装起来。这样后续无论是离线批处理还是实时累加,都只需调用同一套方法。下面给出一个最简模型,实际生产可加上时间滑动与多 SLO 支持。
class ErrorBudget:
def __init__(self, total_requests, slo_target):
# slo_target 为成功率,例如 0.999
self.budget_total = total_requests * (1 - slo_target)
self.budget_used = 0.0
def consume(self, errors):
# errors 为本次统计周期内的错误请求数
self.budget_used += errors
def remaining(self):
return self.budget_total - self.budget_used
def burn_rate(self, errors, window_seconds):
# 返回消耗速率:每单位时间消耗预算占总量比例
if window_seconds <= 0:
return 0.0
return (errors / self.budget_total) / (window_seconds / (30 * 86400))
budget = ErrorBudget(total_requests=10_000_000, slo_target=0.999)
budget.consume(errors=120)
print("剩余预算:", budget.remaining())
print("消耗速率:", budget.burn_rate(errors=120, window_seconds=86400))
二、基于日志的离线追踪
多数中小团队没有完备的 metrics 管道,访问日志就是最真实的错误来源。我们可以用 Python 读取 Nginx 或应用日志,按小时聚合错误状态码,再汇入 pandas 做趋势分析。这种方式的优势是无需改动线上系统,缺点是时效差,通常隔天才能出报表。
下面的脚本演示如何从 CSV 格式日志中统计每日错误数,并画出预算消耗表。注意日志里 status 列若为 500 及以上或显式标记 timeout 都计入错误。我们用 pandas 的 resample 做日级别重采样,逻辑直观且易扩展。
import pandas as pd
# 假设日志已转为 csv,含 timestamp 与 status 两列
df = pd.read_csv("access_log.csv", parse_dates=["timestamp"])
df["is_error"] = df["status"] >= 500
daily_errors = df.set_index("timestamp")["is_error"].resample("D").sum()
budget_total = 10000
used = daily_errors.cumsum()
remaining = budget_total - used
report = pd.DataFrame({
"date": daily_errors.index.date,
"errors": daily_errors.values,
"used": used.values,
"remaining": remaining.values
})
print(report)
拿到上表后,如果某天 remaining 跌破总预算的 20%,就说明消耗已过半偏快,需要复盘那天的发布或依赖故障。相比单纯看成功率,这种绝对余数视角能避免流量低谷时虚惊一场。
三、实时消耗与告警
当系统规模变大,离线报表不够用,可用 Python 起一个定时任务,每隔一分钟向 Prometheus 拉取错误计数与总请求数,计算最近窗口的 burn rate。Google SRE 书里建议:若 1 小时 burn rate 超过 14.4,意味着 30 天预算会在 2 天内烧光,必须立刻告警。
下面示例用 prometheus_http 风格伪代码展示抓取与判断。实际可换官方 client 或 requests 直接查 query API。核心是把“预算消耗速率”转为可行动的阈值,而不是等预算没了才被发现。
import requests
PROM_URL = "http://127.0.0.1:9090/api/v1/query"
def query_prom(q):
r = requests.get(PROM_URL, params={"query": q})
return float(r.json()["data"]["result"][0]["value"][1])
errors_1h = query_prom("sum(increase(http_requests_total{code=~'5..'}[1h]))")
total_1h = query_prom("sum(increase(http_requests_total[1h]))")
budget_total = 10000 # 月度预算,简化示例
if total_1h > 0:
burn_rate = (errors_1h / budget_total) / (3600 / (30 * 86400))
if burn_rate > 14.4:
print("高危:错误预算将在2天内耗尽,请立即介入")
elif burn_rate > 3:
print("警告:预算消耗偏快")
这种追踪方式把 SLO 从文档落到工程实践。配合企业微信或邮件钩子,Python 脚本就能成为预算守卫。需要注意的是,多服务共用一个 SLO 时,预算应按权重拆分,否则容易扯皮谁烧得多。
四、常见误区与改进
第一个误区是用平均成功率代替预算。比如某天流量极小,十次请求错一次,成功率 90%,但绝对错误数仅 1,对月度万次预算几乎无影响。若按成功率告警就会误报。第二个误区是窗口固定不动,不考虑已过去的时间比例。正确做法是用时间加权:月初烧得快和月末烧得快性质不同。
改进方案是在 ErrorBudget 类里加入 elapsed_ratio,用已流逝天数除总天数,得到“时间进度”。将预算消耗进度与时间进度画在一起,若消耗进度线明显高于时间线,就是早期危险信号。Python 里用 matplotlib 或简单打印对比均可,关键是建立这种相对视角。
from datetime import datetime
class TimeAwareBudget:
def __init__(self, total, slo, start_day, end_day):
self.total = total * (1 - slo)
self.used = 0
self.start = start_day
self.end = end_day
def used_ratio(self):
return self.used / self.total
def time_ratio(self, now):
span = (self.end - self.start).days
elapsed = (now - self.start).days
return elapsed / span
b = TimeAwareBudget(10_000_000, 0.999, datetime(2023, 1, 1), datetime(2023, 1, 31))
b.used = 3000
now = datetime(2023, 1, 10)
print("消耗进度:", b.used_ratio(), "时间进度:", b.time_ratio(now))
通过上述四类方法,Python 能覆盖从日志回放、实时拉取到带时间感知的预算模型。团队可依基础设施成熟度逐步演进,不必一步到位。错误预算追踪的价值不在于精确小数点后几位,而在于把可靠性目标变成每天都能看见、能对话的数字。
error_budgetPythonSLO修改时间:2026-08-03 18:36:36