服务器日常系统开发与维护 SOP
发布/回滚 · 配置变更 · 日常巡检 · 值班响应 · 故障演练 · 变更评审 · 告警闭环——把发布策略、可观测性、容器运行时三块能力落到一张值班表里。
一句话结论
日常运维 = 把"发布策略 / 可观测性 / 容器运行时"三块单一事实源,装进一张七件套 SOP(发布/回滚 / 配置变更 / 日常巡检 / 值班响应 / 故障演练 / 变更评审 / 告警闭环)。每件套都要有入口条件 / 动作清单 / 成功指标 / 失败动作四段,靠 SOP 拉平人差,而不是靠个人英雄。
本篇的红线:不重复展开
- 发布策略六模式与 K8s 五关键字段详见 release-strategy,本篇只讲"日常发布的动作清单"。
- 可观测性三支柱与 P99 直方图/分位数陷阱详见 observability,本篇只讲"告警怎么落到值班"。
- 容器运行时排障(containerd/CRI/OCI)详见 container-runtime,本篇只讲"排障入口"。
场景问题
游戏区服要 7×24 稳定跑,"日常维护"不是"没事就好",而是一整套值班动作:
- 发版永远不空档:赛季更新、活动上线、hotfix 全挤在一起。上一次滚更是 3 小时前,下一次可能就在 20 分钟后。发出去、发不回、发一半都是常态。
- 配置比代码变得更勤:新活动的开关、限流阈值、副本 buff 系数一天调好几次。配置变更没走灰度出事,回滚要比代码回滚更难(老版本不认新字段)。
- 告警不是"看红点":凌晨三点手机响,你要 5 分钟内判定"这是重大故障还是抖动",10 分钟内决定"止损还是继续排查",30 分钟内出稳定结论。
- 演练是必须:从来没演练过的恢复流程,真出事时几乎必然踩坑(详见 stateful-recovery 的"必须定期演练"警告)。
三个真实的日常事故
- 发布回滚拖尾:新版本推 25% 后 5xx 拉升,
kubectl rollout undo立即执行,但 Endpoints 摘除滞后 30s,客户端持续打到"僵尸 Pod"上——回滚动作做了 ≠ 流量真回滚了。 - 配置改错导致雪崩:把某活动的限流阈值从 5000 QPS 手动改到 500,忘了走灰度,全服瞬间打回 429,玩家投诉冲上话题榜——配置比代码更需要灰度。
- 告警疲劳:白天几百条告警没人看,凌晨一条真事故被淹没在"P99 抖动"和"磁盘 85%"里——告警设计不是加,是减。
发布、变更、告警不是彼此独立的操作,它们共同组成"日常 SOP"。这份 SOP 决定值班的人在事故来临前先做过多少次演练、事故来临时能不能按流程动作、事故过后能不能沉淀经验。
实现方案
七件套 SOP 全景
每件套按同一张卡片写清:入口条件 / 动作清单 / 成功指标 / 失败动作。
① 发布 / 回滚
| 段 | 内容 |
|---|---|
| 入口条件 | 变更单已过评审、灰度方案已定、回滚点已备份、值班已交接 |
| 动作清单 | 1) 冒烟环境验一次;2) 按 release-strategy 的灰度 SOP 八步逐级放量;3) 每级观察 5–15 分钟指标;4) 达标自动进下一级,异常触发一键回滚 |
| 成功指标 | 全量后 30 分钟内:错误率 < 基线 × 1.2、P99 < 基线 × 1.5、无 P0/P1 告警 |
| 失败动作 | 立刻 rollout undo + 摘流量 + 拉 war-room + 通知值班群;回滚只算做完到"Endpoints 已摘",不算做到"命令返回成功" |
回滚的两个反直觉
kubectl rollout undo不等于流量已切回旧版:Endpoints 更新与 kube-proxy 生效有秒级延迟;对长连接服务,还要主动关连接触发客户端重连。- 有状态服务不能直接
undo:PVC 数据兼容性、消息 schema 兼容性都要提前双向兼容(详见 release-strategy 的 "DB Schema 双向兼容")。
② 配置变更
| 段 | 内容 |
|---|---|
| 入口条件 | 配置版本已在配置中心写好、灰度批次已划分、老配置作为回滚点保留 |
| 动作清单 | 1) 单节点试灰度、观察 5 分钟;2) 单区试灰度、观察 15 分钟;3) 全服放量;4) 每步都在告警群 @ 值班 |
| 成功指标 | 目标行为生效 + 无关指标不动 |
| 失败动作 | 配置中心一键回滚到上一个版本号;若配置触发副作用(如 buff 系数已发放奖励)需走补偿而非"改回来" |
配置变更三板斧:评审 / 灰度 / 回滚点——三样缺一,事故必到。
③ 日常巡检
分三级:每日 / 每周 / 每月。清单不长,但必须每次都走完:
| 级别 | 清单项 | 落到工具 |
|---|---|---|
| 每日 | 错误率 & P99 与基线对比、容量水位(CPU/Mem/磁盘/连接数)、依赖健康(DB/Redis/MQ)、昨日告警复盘 | Grafana 首页 + 告警平台 |
| 每周 | 慢查询 Top 20 & 治理进度、证书 30 天内到期、Pod 重启次数异常、备份可恢复性演练一次 | 慢查询报表 + 证书扫描 + 备份 chaos |
| 每月 | 依赖升级评估、容量趋势外推 3 个月、故障演练 1 次、变更成功率复盘 | 变更平台 + Chaos 平台 |
备份 ≠ 可恢复
"备份存在"和"备份能还原到可用状态"是两件事。每周至少做一次备份还原演练(详见 stateful-recovery 的"必须演练"警告)。没演练过的备份,故障时等于没备份。
④ 值班响应
告警 → 值班 → 处置的四段式:
| 段 | 目标 | 关键动作 |
|---|---|---|
| Ack 认领 | 让告警不飘 | 告警群 @ 认领,避免无人响应 |
| Mitigate 止损 | 先止血再查因 | 摘流量、限流、降级、切副本、回滚——先做能止损的,不追求先找到根因 |
| Root Cause 定位 | 找到唯一因果链 | 顺着 observability 三支柱:Metrics 发现 → Trace 定位 → Log 抠细节 |
| Post-Mortem 复盘 | 沉淀经验 | 事故报告 + 时间线 + 5 Why + 行动项到人;行动项进变更平台跟踪 |
告警分级(对齐值班响应时限):
| 级别 | 定义 | 响应时限 | 处置权限 |
|---|---|---|---|
| P0 | 全服/大区不可用、核心业务停摆 | 5 分钟 ack、10 分钟 mitigate | 值班直接决定摘流量/回滚 |
| P1 | 部分玩家受影响、SLO 破线 | 15 分钟 ack、30 分钟 mitigate | 值班 + 二线 |
| P2 | 单点异常、指标波动 | 1 小时 ack | 值班次日复盘 |
| P3 | 只需知晓、无需处置 | 无 | 每周批处理 |
跨团队协同:谁是主责
出事时会有 5 个人同时 @:客户端、运维、DBA、网络、你。每次事故必须先指定"值班总协调"(通常是发现方或最先受影响方),其他角色以"支线"参与。没有总协调 = 三个小时后大家还在各自群里对齐。
⑤ 故障演练
Chaos 演练类型清单,按爆炸半径从小到大:
| 类型 | 演练动作 | 期望恢复表现 |
|---|---|---|
| 进程 Kill | kill -9 一个 Pod | K8s 重启 + 长连接客户端自动重连 |
| 网络分区 | tc netem 加 100ms 抖动 / 20% 丢包 | 限流不误伤、Retry 不雪崩 |
| 磁盘满 | 提前灌满 /var/log | 日志切换到备用盘 / 熔断保护主进程 |
| DNS 抖动 | 屏蔽 DNS 服务器 | 走本地缓存 / 长连接不受影响 |
| 依赖降级 | 停掉某个下游 | 熔断触发 / 回退到本地兜底 |
| 节点下线 | Cordon + Drain | Pod 迁走、有状态走 k8s-stateful-ops 的 NonGracefulShutdown 路径 |
演练前签发 + 止损策略:每次演练要有 announce → kick-off → observe → abort-condition → close-out 五步;abort-condition 命中立刻结束演练,不硬扛。
演练与真实事故的边界
- 演练时的止损是预定义的、可控的;真实事故的止损是当场判断的。
- 演练不能变成真实事故的替代品——只有真实事故的复盘才能让 SOP 长牙。
- 演练不能只在测试环境做;关键的、可控的必须在生产做一次,否则等于没做(真实环境的量级和依赖没法在测试环境复刻)。
⑥ 变更评审
每一次变更(代码、配置、依赖、拓扑)走 CAB(Change Advisory Board)三步:
- 发起方自评:变更范围、影响面、回滚方案、灰度批次
- 同侪评审:架构点 / SRE / 值班三方 review
- 值班确认:值班日历不冲突(避免与大版本、赛季、大活动同期)
免审白名单要极窄:紧急 hotfix(P0/P1 事故下)+ 已模板化的配置项(比如某类活动的开关)。其余一律入审。
⑦ 告警闭环
告警设计三原则(对齐 observability):
- 可行动:每条告警必须对应一个明确动作。"P99 > 200ms" 不可行动;"P99 > 200ms 持续 5 分钟" + "预案:先看下游依赖,再看容量" 才可行动。
- 可分类:每条告警必须打
severity标签(P0/P1/P2/P3),落到告警平台分级路由;P2/P3不 wake 人。 - 不淹没:静默 / 去重 / 升级三件套——同类告警 15 分钟内静默、重复告警合并为一条、超时未 ack 自动升级到二线。
告警设计不是加,是减
告警平均每周新增 5 条却从不清理,一年后就是"告警垃圾场"。每季度做一次告警治理:命中率 < 10% 的告警必须要么调整阈值、要么下线。
为什么这么做
- 为什么是"SOP"而不是"文档":日常运维的核心是拉平人差——不同人在同样场景下的动作差异必须收敛到几步内,否则事故只会发生在经验最少的那次值班上。SOP 不是给"看着办"留空间,是给"照着做"留台阶。
- 为什么"发布 + 配置 + 变更"要合并成一条日常线:三者本质是同一件事的三种粒度(大版本 / 配置项 / 单参数),日常工作里它们互相耦合(配置依赖代码新字段、变更依赖发布节奏)。分开写就会出现"配置变了但代码没跟上"、"发布回了但配置没回"的对齐事故。
- 为什么值班响应用四段式:
Ack → Mitigate → RCA → Post-Mortem是把"人的注意力"分配到最需要的阶段。先止血、后查因:查因是慢工,止血是分钟级动作,混淆两者 = 事故规模持续放大。 - 为什么告警设计比告警本身重要:告警噪音本身就是事故——它让真事故没人看。所以告警设计的目标不是"告警越全越好",而是"告警到达时能被行动"。
为什么别的选择不行
- "临时手工执行、不建 SOP":靠个人英雄主义撑值班表,一次交接、一次离职、一次深夜情绪化决策就把知识清空。
- "发布就用
kubectl apply、不走灰度":单点回滚极慢、爆炸半径极大、无法量化验收。RollingUpdate 六模式对比与灰度八步存在的意义就是把"直接生效"这种最危险的动作从默认路径删掉。 - "配置变更等同于代码变更、走一样的流程":配置变更的发生频率比代码高 10 倍,若走同样重的评审,运营节奏立刻卡死;若走同样轻的评审,事故立刻爆发。所以配置需要独立的三板斧(评审 / 灰度 / 回滚点)而不是共用代码 CI/CD。
- "告警越多越安全":告警的边际效用递减——第 100 条告警的价值可能是负的(它让第 1 条告警被淹没)。减告警比加告警更工程化。
- "演练只在测试环境做":测试环境的负载、依赖、数据量都与生产不同,测试环境的演练验证不出生产的失败模式。关键流程必须在生产做一次,且提前签发、随时可 abort。
三个绝对不做的动作
- 在没有回滚点的情况下变更:无论多小的变更。
- 不走灰度直接全量:无论多"简单"的配置。
- 发布 / 变更后立刻下班:至少留观察窗(15 分钟到 1 小时),把"我做完了" 变成 "指标验证了"。
沉淀结论
- 日常运维 = 一份七件套 SOP(发布/回滚 / 配置变更 / 日常巡检 / 值班响应 / 故障演练 / 变更评审 / 告警闭环),每件套按"入口条件 / 动作清单 / 成功指标 / 失败动作"四段固化。
- 发布策略、可观测性、容器运行时是三块能力,日常 SOP 是把它们装到值班表里的用法——本篇不讲原理,讲流程。
- 三板斧铁律:评审 / 灰度 / 回滚点——变更任何东西都缺一不可。
- 值班四段式:Ack → Mitigate → RCA → Post-Mortem——先止血、后查因,混淆两者事故就放大。
- 告警设计三原则:可行动 / 可分类 / 不淹没——减告警比加告警更工程化。
- 备份、演练、恢复三者都必须"做一次就是零、每周一次才叫有"——没演练过的能力不存在。
记忆口诀
七件套:发布/回滚 · 配置变更 · 日常巡检 · 值班响应 · 故障演练 · 变更评审 · 告警闭环
每件套四段:入口条件 / 动作清单 / 成功指标 / 失败动作
变更三板斧:评审 / 灰度 / 回滚点——缺一必炸
值班四段式:Ack 5m / Mitigate 10m / RCA 30m / Post-Mortem 3 天
告警三原则:可行动 / 可分类 / 不淹没——减告警而非加
巡检三级:日 = 指标水位依赖 / 周 = 慢查证书备份 / 月 = 依赖趋势演练
演练五步:announce / kick-off / observe / abort-condition / close-out
三不做:无回滚点变更 / 不灰度直接全量 / 变更后立刻下班
内容来源
综合整理。参考方向:Google SRE Book(值班、演练、告警设计章节)、Netflix Chaos Engineering、腾讯游戏后台运维实践、ITIL 变更管理框架、以及站内 release-strategy / observability / container-runtime / stateful-recovery 的日常应用视角。
自测:合上资料能说清楚吗?
Q1: "日常 SOP" 与 "发布策略" 是什么关系?为什么不合并到一篇?
发布策略讲的是六种模式的选型与技术细节(Recreate / RollingUpdate / BlueGreen / Canary / A-B / Shadow,五关键字段,Argo Rollouts / Flagger),是能力篇;日常 SOP 讲的是把能力装到值班表——什么时候用哪种模式、灰度批次怎么划、回滚窗口留多久、观察指标是哪些、失败动作是什么。两者的粒度和读者场景完全不同:一个是架构选型时读,一个是深夜值班时读。合并会让两个都读不下去。
Q2: 一条 P0 告警凌晨触发,你的前 15 分钟按什么顺序动?
- 0–1 min:Ack 认领(避免飘)+ 快速判定告警真伪(看关联指标是否同步异常)。
- 1–5 min:先做止损动作——最快的:摘流量 / 限流 / 降级 / 切副本 / 回滚。不追求先找到根因。
- 5–10 min:拉 war-room + 通知值班群 + 指定"值班总协调"。
- 10–15 min:顺 observability 三支柱开始 RCA:Metrics 报警面 → Trace 定位慢 span → Log 抠细节。
- 全程别忘:先做能止损的、再追求解释原因。
Q3: 一次赛季更新前的"变更评审"要卡哪几点?
- 变更范围与影响面(哪些模块、哪些区服、多少玩家);
- 灰度批次与放量节奏;
- 回滚方案(回滚窗口、回滚点、回滚不可逆点);
- DB Schema / 消息 schema 是否双向兼容;
- 值班日历不冲突(不与大活动、其他大版本同期);
- 依赖服务是否已被通知;
- 告警是否已按新版本调整阈值。
Q4: 为什么"配置变更"不能走"和代码变更一样的流程"?
配置变更的频率是代码的 10 倍以上。若走一样重的评审 → 运营节奏卡死;走一样轻的评审 → 事故爆发。所以配置需要独立三板斧:评审(快速但必须走)、灰度(分批放量、观察窗)、回滚点(老配置版本号保留)。此外配置往往有副作用(比如已发放奖励),回滚不等于行为撤销,需要走补偿而不是"改回来"。
Q5: 告警"疲劳治理"具体做什么?
- 每季度盘点:命中率 < 10% 的告警要么调整阈值、要么下线;
- 告警必须有 severity 标签,P2/P3 不 wake 人;
- 同类告警 15 分钟内静默、重复告警合并为一条、超时未 ack 自动升级;
- 每条告警必须能对应一个明确动作(可行动原则);
- 每条 P0/P1 告警必须有 runbook 链接指向操作手册。