应急预案:故障分级、止损与恢复演练
应急预案规定故障发生时由谁组织处理、哪些操作可以执行,以及怎样判断业务已经恢复。它需要包含服务的真实入口、部署位置、依赖、访问方式和恢复步骤。告警出现后,值班人员应能据此定位目标并采取已知动作,而不必临时寻找账号、镜像和联系人。
预案有两层:团队共用的响应流程,以及每个服务自己的操作手册。前者解决定级、分工、升级和沟通;后者保存特定服务的命令、风险与恢复条件。产品安装步骤可从 Nginx、Spring Boot 部署、Kubernetes等专题查阅,故障期间优先使用已经在目标环境验证过的手册。
根据业务影响启动响应
先确认发生了什么
告警可能来自用户入口、应用指标、主机或依赖。收到通知后,先记录告警对象与观察窗口,再用另一条相关路径确认影响:入口 5xx 增多可结合真实请求和上游日志;消费者异常可结合队列年龄与业务状态;主机 CPU 高则要看请求延迟或任务进度是否受影响。
初始记录应包含服务、环境、受影响接口或任务、开始时间、影响比例,以及最近发生的变更。尚未查明的信息单独标注,不要把怀疑的原因当成事实传播。时钟和时区应统一,命令与变更记录保留精度,便于之后还原先后顺序。
“最近发布过”值得优先调查,但仅有时间接近还不足以决定回滚。需要比较新旧实例、版本分组或配置差异,确认回滚是否能解除故障、旧版本是否仍能处理当前数据。
等级与升级条件
等级名称可以沿用团队约定,判断主要取决于业务损失和处理紧迫性:
| 影响 | 响应方式 | 需要补充的信息 |
|---|---|---|
| 大范围核心功能中断,或持续写错数据 | 启动集中指挥,召集相关负责人,尽快限制影响 | 受影响用户、持续写入、可用止损方案 |
| 局部功能不可用或性能明显下降 | 由服务负责人组织处理,准备扩大影响时升级 | 影响分组、替代路径、容量趋势 |
| 尚无业务影响,但副本、备份或容量保护减弱 | 安排明确处理时限并跟踪,避免保护继续失效 | 剩余副本、恢复点、预计耗尽时间 |
| 疑似入侵、凭据泄漏或数据外泄 | 同时启动安全响应,限制访问并保留调查材料 | 可疑身份、资产、网络连接与访问记录 |
具体响应时限应由业务目标、值班覆盖和风险要求决定。不要用一套“十分钟响应、半小时恢复”套所有服务。影响持续扩大、处置失败、接近可接受中断时长、存在数据损失或缺少必要权限时,都应升级协调。
安全事件需要考虑受影响身份和备份的可信程度。恢复服务前还要排除攻击入口、轮换受影响凭据,并确认恢复副本没有带回恶意配置。组织级准备、检测、响应与恢复的关系可查 NIST SP 800-61 Rev. 3。
分工与信息同步
集中处理时可以分成四项职责。指挥者维护当前目标、分配任务并决定是否扩大止损;操作者执行具体变更;记录者维护时间线与结果;沟通者向业务方、客服或相关团队更新影响和进展。小团队可以兼任,但应知道谁正在承担哪一项职责。Google SRE 故障响应提供了这类组织方式的详细说明。
诊断可以并行,例如分别检查入口和数据库。修改同一个资源时则需要协调,避免两个人同时改流量权重、重启服务或切换主库。每次变更都先说明目标、范围、预期结果与撤销方式,执行后返回实际结果。
状态更新可以保持简短:
受影响业务:订单查询在部分实例返回 502
已确认:网关进程可用,异常集中在一个 upstream 配置
当前动作:限制该入口流量,准备恢复上一份已验证配置
数据影响:查询故障;写入影响仍在检查
下一次更新:由沟通负责人按约定窗口发布对外说明以已经确认的信息为准。恢复时间尚不能估计时,说明下一项动作和下一次更新时间。内部消息不粘贴密码、访问令牌、完整用户数据或未经脱敏的请求头。
选择能限制影响的操作
先收集哪些信息
通常先暂停与故障相关的自动发布、自动扩散配置和重复修复任务,让系统变化可追踪。已批准的止损操作仍可以继续。若正在持续写错数据,应优先限制相关写入,不能为了收集完整日志而延长损失。
Linux 上可以先做短窗口、只读检查。以下变量由服务手册填写,命令需要能够读取服务状态与日志的身份;如需保存输出,应使用受限目录:
UNIT=orders.service
systemctl show "$UNIT" \
-p ActiveState -p SubState -p MainPID -p ExecMainStatus
journalctl -u "$UNIT" --since '-10 min' --no-pager -n 200
df -hT
df -i服务状态异常时结合退出原因和对应日志继续检查。df -hT 看块空间,df -i 看 inode;两者都正常而应用无法写入,还可能涉及只读挂载、配额或权限。命令权限不足、日志未持久化或目标服务不使用 systemd 时,记录检查未完成,转到实际运行平台,不将空输出写成正常。
同一组故障还应保存实际部署版本、相关配置差异和告警曲线。完整进程转储、堆转储或大范围日志打包会占用磁盘、暂停进程或暴露敏感数据,应评估剩余资源后再做。资源读数与诊断细节见生产巡检。
回滚、降级、隔离与扩容
| 选择 | 适合的条件 | 执行前检查 |
|---|---|---|
| 回滚代码或配置 | 故障与变更相关,旧版本仍可运行 | 旧制品可取得,配置与 schema 兼容,回退不会再次触发副作用 |
| 关闭功能或降级 | 故障集中于可选功能,核心流程可继续 | 返回含义明确,开关确实生效,有恢复开关的负责人 |
| 限流或暂停相关写入 | 过载、持续错误写入或重复执行扩大损失 | 限制对象与影响范围、在途请求和后台任务如何处理 |
| 隔离异常实例 | 异常局限于部分实例且其余容量足够 | 连接是否排空、剩余容量、会话与任务所有权 |
| 扩容 | 瓶颈可并行扩展,依赖仍有余量 | 数据库连接、队列分区、下游配额与扩容生效时间 |
| 恢复数据 | 现有数据损坏或丢失 | 恢复点、完整备份链、独立目标和业务对账方法 |
这些动作可以组合,但要按结果逐步推进。数据库已饱和时增加应用实例,可能带来更多连接与重试;暂停入口也未必停止调度器、消费者和已经接收的任务。要围绕真正产生负载或写入的执行者处理。
代码回滚通常只改变运行程序。数据库已经删除的字段、发出的消息或完成的第三方支付不会跟着撤销。遇到这类问题,先停止相关副作用,再选择兼容旧结构、向前修复或业务补偿。数据恢复步骤见备份与恢复。
按故障类型缩小处置范围
入口 502、504 应结合 upstream 地址、连接错误、响应时间和后端状态检查。Nginx 配置语法通过后,目标端口仍可能写错;代理层的重试还可能放大后端压力。特别是非幂等写请求,要确认失败发生在发送前、处理中还是返回途中,再决定能否重试。Nginx 上游重试规则规定了可尝试其他上游的条件。
数据库连接与锁等待异常,要区分连接泄漏、慢事务和等待链。结束查询不一定结束整个事务,也不一定立即释放锁;长事务回滚本身可能持续较久。先识别所属应用、事务年龄和业务操作,由数据库负责人决定具体处理,不按截图里的连接编号直接执行 KILL。
消息积压需要看持续到达速率、有效完成速率和最老消息年龄。只有有效完成速率高于新消息到达速率,积压才会缩小。把消费位点直接跳到最新可能丢弃尚未完成的业务;清空队列也会失去补偿来源。先恢复消费者或降低生产速率,再根据幂等记录安排重放与死信处理。
磁盘紧张时先确定增长目录和写入者。删除正在打开的文件可能暂时不释放空间;截断数据库文件、清空 Docker 数据目录或泛用 prune 会破坏业务与恢复材料。可以按已验证保留策略处理明确可删除的日志归档,必要时扩容或降低写入,操作前保留故障分析所需片段。
外部支付、短信或对象存储超时,既可能尚未执行,也可能已经成功但响应丢失。支付类请求应通过业务单号查询结果,依靠幂等键处理重试;临时关闭非必要通知时,要保存待处理记录与恢复顺序。把所有失败请求立即重试,常会延长依赖故障。
用隔离入口演练错误配置与恢复
环境、身份与访问路径
下载 Nginx 应急实验包,解压到 Linux 普通用户自己的测试目录。需要 Bash、curl 7.76 或更新版本、Docker Engine 与 Compose 插件。Docker 操作权限具有较高控制能力,只在专用测试机器执行。
实验使用 nginx:1.30.4-alpine,应用与网关进程均为 UID/GID 101:101,根文件系统只读,可写临时文件放在 /tmp。宿主只发布 127.0.0.1:18680。后端返回固定订单 JSON,不调用真实数据库、支付或消息服务。
宿主 curl
→ 127.0.0.1:18680
→ gateway:8080
├─ /health 直接返回 gateway-alive
└─ /orders/1001 转发到 app:8080准备一个与主机路由和现有 Docker 网络均不冲突的专用子网。示例使用以下值;如被占用,改成所在环境批准的测试网段,并在后续命令中保持一致:
ip route
docker network ls
# 对已有自定义网络检查 IPAM,例如:docker network inspect NETWORK_NAME
export LAB_SUBNET=10.232.0.0/24
bash lab.sh setup预期输出 HTTP 200,并检查到业务版本 lab-1。端口冲突时不要停止未知服务;换用空闲端口后同步修改 Compose 和探测地址。网络重叠时先修正 LAB_SUBNET。已有本实验容器或 runtime 目录时脚本拒绝初始化,避免覆盖前一次结果。
错误语法与错误目标是两种失败
bash lab.sh invalid脚本把含无效指令的文件放入配置目录,执行 nginx -t,确认非零退出,随即恢复磁盘上的正确文件;它不发送 reload。再次请求业务仍为 200。预期输出包含 REJECTED,详细错误保存在 runtime/invalid-test.txt。
这一步说明运行中的 worker 使用已加载配置。编辑磁盘文件不会自动改变请求处理;同样,磁盘恢复正确也不意味着之前已加载的错误配置自动失效。Nginx 收到 reload 后会检查并尝试应用新配置,失败时继续使用旧配置,成功时启动新 worker 并逐步退出旧 worker,详见官方进程控制说明。
接着引入语法正确、目标错误的配置:
bash lab.sh fault新配置把代理地址改为没有服务监听的 app:18081。nginx -t 通过,reload 后业务请求返回 502,而 /health 仍返回 gateway-alive。前者暴露上游连接失败,后者只检查网关自身。
可以直接保留状态码与响应体:
code=$(curl -q --noproxy '*' -sS \
--connect-timeout 2 --max-time 5 \
-D runtime/probe.headers -o runtime/probe.body \
-w '%{http_code}' http://127.0.0.1:18680/orders/1001)
test "$code" = 502
docker compose logs --tail=20 gateway这是预期失败分支,所以显式检查 502;正常路径使用 --fail-with-body 让 HTTP 错误产生非零退出。-q 放在第一个选项以忽略 curl 配置文件,--noproxy '*' 隔离本地代理影响,连接和总时限避免探测挂起。这些选项见 curl 手册。
维护响应限制影响,恢复配置重新提供业务
bash lab.sh mitigate网关把业务路径改为返回 503 和 Retry-After: 60,不再访问错误上游。脚本核对响应码与响应头,输出 MAINTENANCE。这是一种主动拒绝请求的临时措施,业务仍不可用。客户端是否以及何时重试,要遵循自己的重试策略;该响应头不保证所有客户端等待。
恢复正确上游后再验证:
bash lab.sh recover预期看到:
HTTP 200
{"id":1001,"status":"CREATED","version":"lab-1"}脚本每次应用配置都先测试,再 reload,并在有限时间内等待目标状态。HTTP 200 之外,还核对订单标识和版本,避免把网关健康响应当成业务恢复。真实系统应继续验证鉴权、必要读写、异步进度与外部结果,检查范围由该服务承担的业务决定。
如果语法测试失败,先检查配置错误,不发送 reload;reload 后仍未恢复,则检查运行日志、实际 upstream 和后端状态。不要在结果不明时继续叠加配置变更。
最后停止实验:
bash lab.sh stop容器、专用网络和本地结果会保留。此实验验证的是入口切换行为,不涉及真实数据库回滚、集群故障转移或外部通知。
恢复观察、交接与预案维护
怎样宣布恢复
恢复状态可以逐步说明:影响已受控、核心功能恢复、积压正在处理、系统进入稳定观察。这样业务方能区分“暂时没有继续扩大损失”和“所有功能已经正常”。
观察对象需要包含曾经失败的路径。接口错误率下降时,还要检查是否因为请求量降为零;队列长度下降时,要确认消费者真实完成业务,而非丢弃或跳过消息。使用相同口径比较故障前后数据,低流量服务可增加受控探测,但不能把没有样本解释成没有错误。
观察时间应覆盖故障机制相关的周期。例如连接池问题要经过连接更新,缓存问题要跨过相应过期过程,定时任务要观察下一次执行。高峰容量问题还需要在代表性负载下复验,统一等待固定分钟数并不能覆盖所有情况。
把临时状态交给下一班
交接时明确当前指挥和接收人,保留正在执行的命令、未完成操作以及禁止再次执行的步骤。暂停过的消费者、关闭的功能、临时限流、告警静默和应急权限,都要说明恢复条件与负责人。
| 交接对象 | 应记录的内容 |
|---|---|
| 业务状态 | 已恢复与仍受限的功能、影响数据范围 |
| 当前部署 | 镜像/制品、配置、数据库状态及流量去向 |
| 临时措施 | 开关、限流、暂停任务、静默到期和撤销条件 |
| 数据处理 | 待补偿订单、消息进度、恢复点与对账负责人 |
| 下一步 | 待验证问题、计划动作、操作权限和升级联系人 |
对已解除的临时权限及时收回,对仍需保留的措施设置到期检查。应急修改如果没有同步回配置仓库或自动化系统,下次发布可能再次覆盖正确状态。
演练与复盘分别解决什么
桌面推演适合检查人员分工、联系路径和决策条件;隔离环境演练验证命令和系统行为;限定范围的目标环境演练验证真实账号、网络和容量。三者可以互补。涉及生产写入、外部通知、云资源或真实故障注入时,必须有单独授权与停止条件。
一次演练可以选择一个明确问题:某实例失效后是否仍可访问、配置错误是否被拒绝、备份损坏时是否找到另一副本、主联系人无法响应时怎样升级。预先定义影响范围和退出步骤,保留正向与失败分支结果。
复盘需要还原触发条件、故障传播和恢复过程,区分事实与尚未证实的推测。除了直接原因,还应检查哪些保护没有发挥作用:发布为什么扩大到全部实例,告警为什么晚到,回滚为什么缺少旧配置。行动项应有负责人和验证方式,例如“补充业务路径探测,并在隔离环境让上游不可达以核对告警”,比“加强监控”更容易落实。Google SRE 复盘文化强调从系统和过程改进中减少重复故障。
服务入口、发布方式、值班人员或数据恢复方案改变后,应同步更新预案并重验相关步骤。日常接管与发布前检查可使用部署运维总清单。
