监控、日志与故障处理
用最少的信号发现真正影响用户的问题,建立从告警到恢复的处理顺序。含可直接用的健康检查和日志查看命令。
没有监控的时候,最先告诉你服务坏了的人是用户——如果你运气好,他还愿意告诉你。运气不好的话,他只是走了。
但监控也不是图表越多越好。一个有用的监控系统只需要在异常出现时回答三个问题:哪里坏了、影响谁、现在该做什么。
快速版
- 先监控用户结果(能不能打开、能不能完成核心任务),不是 CPU。
- 给每次请求分配可追踪 ID,日志围绕请求组织。
- 日志绝不写密码、验证码、密钥、完整令牌。
- 每条告警必须带处理动作,否则它只是噪音。
- 故障时顺序固定:先恢复,再找根因。
- 复盘只产出少量有负责人的动作,不产出"以后更小心"。
先监控用户结果
基础设施在线不代表产品可用。服务器 CPU 5%、内存充足、容器 running——同时用户一个都登录不进来,这种情况非常常见。
第一版优先盯这几项:
| 监控什么 | 为什么它排在前面 |
|---|---|
| 首页和核心接口能否访问 | 最直接的"还活着吗" |
| 核心任务成功率和耗时 | 能打开不代表能用 |
| 登录、邮件、支付回调是否成功 | 这三条断一条就没有新用户或新收入 |
| 订单与权益是否一致 | 钱收了权益没发,是最贵的故障 |
| 第三方接口错误率和成本异常 | AI 调用尤其要盯成本突增 |
CPU 使用率可以帮你定位问题,但它不是用户结果。别把它放在第一屏。
最低成本的实现:一个定时 curl 打你的健康检查地址,非 200 就告警。
# 最小健康检查:状态码 + 响应时间
curl -s -o /dev/null -w '%{http_code} %{time_total}s\n' https://example.com
# 核心接口也要查,首页是静态的话它活着说明不了什么
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/api/health首页是静态页的话,它返回 200 几乎说明不了什么——数据库挂了首页照样能开。健康检查要打到真的会碰数据库的路径上。
日志围绕一次请求组织
给每次请求、任务、订单分配一个可追踪 ID,然后每条日志都带上它。这样排查时能把一次完整的流程串起来,而不是在几万行日志里猜哪几行是同一个人的。
日志里该有的:
- 时间、环境、版本(哪次部署)
- 请求或任务 ID
- 当前阶段和状态变化
- 外部服务返回的错误码
- 耗时和重试次数
日志里绝不能有:密码、验证码、支付密钥、完整令牌、用户的原始敏感内容。支付和登录日志经常需要贴给别人看——同事、平台客服、AI 助手。带着密钥的日志一旦流出,损失比原来那个 bug 大得多。需要排查输入时,记类型、大小、哈希或脱敏摘要。
自建部署的话,看日志的命令通常就这几条:
docker compose logs --tail=100 app # 最近 100 行
docker compose logs -f app # 跟踪
docker compose logs app | grep -i error # 筛错误
docker compose logs --since 30m app # 最近半小时--since 那条在排查"刚才那次故障"时最有用。
告警必须能行动
一条有效告警要说清五件事:
发生了什么:支付回调连续失败
影响范围:新付款可能暂未开通权益
从什么时候开始:v1.4.2 部署后 / 14:20 起
先做什么:检查回调日志与支付平台状态页
怎样止损:暂停购买入口,或切人工补单没有处理动作的告警只会制造噪音,而噪音的终点是你把通知静音,然后错过真正的故障。
触发条件也要克制:连续多次失败、持续一段时间、或影响关键交易时才通知。单次超时不值得半夜把你叫起来。
故障时先恢复,再找根因
顺序是固定的,不要凭直觉调整:
- 确认影响范围,以及是否还在扩大
- 暂停危险操作,保护数据和资金(比如关掉购买入口,避免继续收钱不发货)
- 回滚、降级或切人工
- 通知受影响用户,并给出下一次更新时间
- 服务恢复之后,再做根因分析
第 3 步的前提是你有回滚能力。没有回滚方案的上线,本质上是在赌。
第 4 步经常被跳过,但它成本最低收益最高:用户能接受故障,很难接受不知情。一句"我们知道了,正在处理,一小时内更新"就能挡掉大部分投诉。
不要在用户仍然无法使用时,执着于写出完美的解释。 恢复优先。
复盘只产出少量有效动作
故障复盘至少写五段:
| 写什么 | 常见的错误答案 |
|---|---|
| 触发条件 | "偶发" ← 那就是还没查清 |
| 为什么没有更早发现 | 通常答案是"没监控这一项" |
| 为什么影响扩大了 | 通常答案是"没有止损开关" |
| 恢复过程 | 照实写,包括绕的弯路 |
| 防止复发的动作 | "以后更加小心" ← 无效 |
每个动作必须有负责人和完成时间。优先补的是检测、止损、恢复三种能力——它们对下一次任何故障都有用,而修一个具体 bug 只对这一个有用。
常见卡点
| 卡在哪 | 可能原因 | 试试这样 |
|---|---|---|
| 用户比你先知道站挂了 | 没有外部健康检查 | 定时 curl + 非 200 告警,十分钟能配好 |
| 健康检查一直 200,但用户用不了 | 检查打在静态首页上 | 改成打会碰数据库的接口 |
| 日志翻不出有用信息 | 没有请求 ID,无法串联 | 每次请求生成 ID,全链路带上 |
| 告警太多,已经静音了 | 告警没有分级,也没有处理动作 | 只保留"影响用户结果"的告警 |
| 出故障时手忙脚乱 | 没有固定处理顺序 | 把上面五步贴在你能看到的地方 |
| 同一个故障反复发生 | 复盘只产出了"更小心" | 复盘动作必须有负责人和时间 |
| 想回滚但不敢 | 没演练过回滚 | 见数据库迁移、备份与恢复 |
验收标准
- 有一个从外部发起的健康检查,打在会碰数据库的路径上
- 登录、邮件、支付回调三项都有独立的成功率信号
- 日志有请求 ID,能串起一次完整流程
- 日志里没有密钥、令牌、验证码
- 每条告警都写了"先做什么"和"怎么止损"
- 故障处理五步顺序写下来了,不靠临场判断
- 有回滚方案,并且演练过
- 最近一次故障的复盘动作有负责人和完成时间
本章动作
主动制造一次无害故障:把测试环境的某个外部接口地址改错,或者把数据库容器停掉。
然后确认三件事:告警到没到、日志能不能串起整次请求、按文档能不能恢复。
三件里有任何一件不成立,你现在发现它的代价,是它在真实故障时暴露的代价的百分之一。
下一步
- 数据库迁移、备份与恢复——回滚和恢复能力
- 上线前验收——上线记录和回滚方式
- 每周复盘——把故障复盘变成固定动作