软件项目开发全流程 · 第 27 课 · 运维与监控
1、上线不是终点,是起点
很多人以为"代码上线"就完事了。可系统的真正考验在上线之后:它要一天 24 小时运行、要面对真实流量、会悄悄退化、会半夜出故障。
运维不是"给服务器续命",而是"让系统持续健康地服务用户"。 本课讲运维的核心:可观测性(日志/指标/链路)、告警设计、以及SLO 与错误预算。
2、可观测性三大支柱
系统出问题时,你需要"看见内部发生了什么"。靠三样东西:
| 支柱 | 回答什么 | 例子 |
|---|---|---|
| 日志(Logs) | 发生了什么具体事件? | "用户 123 登录失败:密码错误" |
| 指标(Metrics) | 系统整体状态如何? | QPS、P95 延迟、错误率、CPU |
| 链路追踪(Traces) | 一个请求经过了哪些环节? | 请求 → 网关 → 订单服务 → 库存服务(各耗时) |
一次用户请求的"可观测"过程:
日志: [10:00:01] order=#88 created by user=123
指标: http_requests_total=1024, p95_latency=210ms, error_rate=0.3%
链路: gateway(5ms) → order-svc(180ms) → db(120ms) ← DB 是瓶颈!日志:结构化(JSON)比纯文本好检索;分级(DEBUG/INFO/WARN/ERROR);关键:别记敏感信息(密码、token、身份证)。
{"time":"2026-01-01T10:00:01Z","level":"ERROR","service":"order","user":123,"msg":"payment failed","code":"CARD_DECLINED","trace_id":"abc123"}指标:常见四类(USE 法 / RED 法):
RED(服务视角): Rate 请求率 / Errors 错误 / Duration 耗时
USE(资源视角): Utilization 利用率 / Saturation 饱和 / Errors 错误链路追踪:给每个请求一个 trace_id,串起跨服务调用,定位"到底哪一段慢"。
工具:Prometheus + Grafana(指标)、ELK/Loki(日志)、Jaeger/Tempo(追踪)。
3、告警:宁可少响,不可误响
告警疲劳(Alert Fatigue) 是运维的头号杀手:如果告警天天响、大多是误报,团队就会无视它,真出事时也麻木了。
好告警的原则:
| 原则 | 说明 |
|---|---|
| 可行动(Actionable) | 收到告警知道该做什么,不知道就是噪音 |
| 指向症状而非原因 | 告警"用户请求失败率高",而非"某个磁盘满了"(后者可能是原因,留给诊断) |
| 有阈值与持续时间 | "错误率 > 5% 持续 5 分钟",避免瞬时抖动误报 |
| 分级 | P0 打电话、P1 发消息、P2 邮件 |
| 去重与聚合 | 一次故障别发 500 条告警 |
| 有归属 | 每条告警知道找谁 |
# Prometheus 告警规则示例
groups:
- name: api
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 5m # 持续 5 分钟才告警
labels:
severity: P1
annotations:
summary: "API 5xx 错误率 >5%"
runbook: "https://wiki/runbook/high-error-rate""Runbook" 很重要:每个告警配有处置手册,值班的人照着做即可。
4、SLO 与错误预算:把"可靠性"量化
"要 100% 可用"是不现实的(也不可能,成本无限)。工程上的做法是把可靠性变成可管理的目标:
SLI(指标): 实际测量值,如"请求成功率 = 99.95%"
SLO(目标): 我们希望达到的水平,如"成功率 ≥ 99.9%"
SLA(协议): 对客户的承诺(往往带赔偿条款),通常比 SLO 宽松
错误预算(Error Budget)= 1 - SLO
若 SLO=99.9%,则每月允许约 43 分钟不可用错误预算的妙用:把"要不要发新功能"变成数据决策:
错误预算充足 → 可以大胆发版、做实验
错误预算耗尽 → 冻结发布,集中力量修稳定性这样开发(想快)和运维(想稳)就不再是对立面——用同一个数字说话。
5、值班(On-call)与响应
系统 24×7 运行,就得有人随时能响应故障:
- 轮值制度:轮班,避免一个人长期疲惫。
- 清晰升级路径:第一时间找不到人 → 多久升级给谁。
- 预案(Runbook):常见故障怎么处置、怎么回滚。
- 事后复盘:每次故障都复盘(第 28 课)。
- 健康文化:值班的人不是"背锅侠",是"守夜人"。
痛苦指标:如果一个人经常半夜被叫醒,说明系统或告警需要改进——从"人肉扛"转向"系统自愈"。
6、让系统更"自愈"
成熟的运维会尽量自动化响应:
- 自动重启:进程挂了,supervisor/systemd/k8s 自动拉起。
- 自动扩容:流量涨,自动加实例(HPA/Auto Scaling)。
- 自动降级:依赖挂了,返回缓存/默认值,而不是全挂。
- 自动熔断:下游持续失败,快速失败,别拖垮自己。
- 限流:保护自己不被流量冲垮。
# 简单降级示例:推荐服务挂了就返回热门列表
def get_recommendations(user):
try:
return recommend_service.query(user, timeout=0.5)
except (Timeout, ConnectionError):
return fallback.get_popular_items() # 降级,别让页面白屏7、常见误区
| 误区 | 问题 | 正解 |
|---|---|---|
| 无监控凭感觉 | 出问题不知道 | 日志/指标/追踪三支柱 |
| 告警太多 | 告警疲劳、真报警被忽略 | 可行动、分级、去重 |
| 追求 100% 可用 | 成本无限、不可行 | 用 SLO + 错误预算 |
| 日志带敏感信息 | 泄露隐私/合规风险 | 脱敏、禁记密码 token |
| 只监控机器不监控业务 | 机器正常但业务挂了 | 业务指标(下单成功率)也要监控 |
| 值班靠一个人硬扛 | 疲惫、易出错 | 轮值 + 自动化 |
8、动手实验 🎯
任务:给贯穿项目「团队任务清单」搭建可观测性。
- 结构化日志:把应用日志改成 JSON,包含
trace_id、level、关键字段,且不含敏感信息。 - 暴露指标:用 Prometheus 客户端暴露
/metrics,包含请求数、错误数、耗时直方图。 - 建看板:用 Grafana(或本地替代)画出 QPS、P95 延迟、错误率四张图。
- 配 3 条告警:错误率、延迟、实例宕机各一条,带
for持续时间与 runbook 链接。 - 定义 SLO:为"任务列表接口"写一个 SLO(如 P95 < 500ms、成功率 ≥ 99.9%),算出月度错误预算。
- 实现降级:给某个外部依赖调用加超时 + 降级逻辑,模拟依赖挂掉时服务仍可用。
- 反思:如果半夜收到告警,你希望告警里包含哪些信息,才能不慌?
下一课:事故响应与复盘。
9、今天你带走的三句话
- 可观测性三支柱:日志(发生了什么)/ 指标(整体状态)/ 链路(请求去了哪)。
- 告警要"可行动、指向症状、有持续时间",避免告警疲劳。
- 用 SLO + 错误预算把可靠性量化,让"快"和"稳"用同一把尺子。
下一课:事故响应与复盘。