首页
›
指南
›
学习路径
›
后端 on-call 学习路径
系统学习
学习路径总入口:先选领域,再建立模型,最后用故障演练验证
→
后端 on-call 学习路径:从 5xx 与超时止血,到日志、数据库、缓存、消息队列和发布回滚 本页目录 使用方式 阶段一:接警后的 10 分钟,判断 5xx 与超时 阶段二:日志、超时链路与运行时异常 阶段三:数据库、缓存与消息队列 阶段四:发布、回滚与复盘 常见误区 参考链接 读完自测 相关条目
使用方式
后端值班面对的从来不是单一组件,而是一条请求链路:入口、应用、连接池、数据库、缓存、消息队列和发布系统。这条路径按“先止血、再定位、后修复”的值班顺序组织,不按语言或框架分类。
四个阶段建议在一次完整值班周期内走完,每个阶段都用自己的服务或测试环境练习:
先读 :读每个故障页时,先记“典型现象”和“第一检查点”,再看修复步骤。
再做 :在测试环境复现一次故障,保留命令输出和时间线;不要在生产上制造问题。
后测 :合上页面,只给现象,能说出下一步查哪里、用什么命令验证、什么条件下回滚。
每次处理完都留下三样东西:请求 ID 或时间窗口、验证命令、结论。没有记录的“已恢复”无法复盘。
阶段一:接警后的 10 分钟,判断 5xx 与超时
目标 :能区分 4xx、5xx、连接超时、网关超时和上游重置,判断故障发生在入口、应用还是依赖,并优先执行回滚、切流、扩容或降级。
阅读顺序 :
on-call — 告警分级、备份值班和升级时限。
sre-oncall-checklist — 从确认影响到止血和复盘的固定检查项。
incident-response-playbook — 事故分级、角色分工和沟通节奏。
http-status-cheatsheet — 状态码与网关、上游、限流的对应关系。
502-bad-gateway — 网关收到上游无效响应时的排查顺序。
504-gateway-timeout — 已连上上游但等待响应超时的根因分类。
connection-timeout — SYN 无响应、路由黑洞和中间设备丢包。
scenario-service-502 — 从入口、网关到上游的分层排查场景卡。
curl-cheatsheet — 分段测量建连、首字节和总耗时。
network-troubleshooting-cheatsheet — DNS、TCP、TLS 到 HTTP 的逐层检查表。
动手任务 :在测试环境让上游分别返回 500、故意 sleep 超过网关超时、关闭端口,制造三类现象。对每一类记录 curl -w 的分段时间、网关错误日志、后端是否收到请求,并写出首选止血动作。
curl -sS -o /dev/null -w 'code=%{http_code} connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}\n' http://127.0.0.1:8080/healthz
ss -lntp | grep ':8080'
journalctl -u < backend> --since '10 min ago' -p warning --no-pager | tail -50
kubectl logs deploy/< app> --since = 10m --tail = 100
kubectl get events -n < namespace> --sort-by= .lastTimestamp | tail -20
过关标准 :
能区分 502、504、连接超时和连接被重置分别发生在链路的哪一层。
能在 10 分钟内回答:影响多少用户、开始时间、最近变更、当前首选止血动作。
回滚或切流后,用同一组指标确认错误率和延迟回到基线,而不是只看 Pod 是否 Running。
知道什么情况下继续排查比立即回滚风险更高。
阶段二:日志、超时链路与运行时异常
目标 :能用请求 ID 把一次失败串联到具体日志和代码路径,区分应用自身超时、下游 deadline、连接中断和运行时阻塞。
阅读顺序 :
logql-cheatsheet — 按标签、行过滤和解析提取错误字段。
loki — 日志聚合、标签设计和保留策略。
journalctl — 按服务、时间和优先级过滤 systemd 日志。
jq — 从结构化日志和 API 响应中提取关键字段。
context-deadline-exceeded — Go context 超时与下游预算耗尽。
grpc-deadline-exceeded — gRPC DEADLINE_EXCEEDED 的客户端与服务端差异。
unexpected-eof — 响应未完整读取就断开的定位方法。
connection-reset-by-peer — 对端重置、keepalive 和中间代理行为。
event-loop-blocked — Node.js 事件循环被同步任务阻塞。
goroutine-leak — Go goroutine 持续增长导致的延迟和内存问题。
动手任务 :给测试服务注入 300ms 下游延迟和 5% 随机断连,用请求 ID 查询一次完整链路:入口日志、应用日志、下游日志、超时错误。分别记录应用是“没收到请求”“收到但自己超时”还是“下游返回后连接已断”。
logcli query '{app="backend"} |= "request_id=<id>"' --since = 30m --limit = 200
journalctl -u < backend> --since '30 min ago' --no-pager | grep '<request_id>'
kubectl logs deploy/< app> --since = 30m | grep '<request_id>'
curl -s localhost:8080/debug/pprof/goroutine?debug= 1 | head -50
过关标准 :
能用请求 ID 还原一次请求经过的入口、应用和下游,而不是在多个日志系统里凭时间猜。
能解释 context deadline exceeded、i/o timeout 和 connection reset by peer 的触发位置差异。
知道日志里没有请求记录时,先查网关、路由、采样和日志管道,而不是直接怀疑业务代码。
发现 goroutine、事件循环或线程池异常时,能给出扩容、限流、降级或重启的取舍。
阶段三:数据库、缓存与消息队列
目标 :看到慢查询、锁等待、连接耗尽、缓存热 Key、消费积压时,能判断瓶颈在数据库、连接池、缓存还是消费者,并避免用扩容掩盖问题。
阅读顺序 :
mysql-slow-query — 执行计划、索引选择和慢查询日志。
mysql-deadlock — 死锁等待图与事务加锁顺序。
postgres-connection-exhausted — 连接池、空闲事务和 max_connections。
postgres-lock-wait — 锁等待链、长事务和 DDL 阻塞。
pgbouncer — session、transaction、statement 三种池模式的边界。
redis-memory-full — maxmemory、淘汰策略和内存碎片。
redis-hotkey — 单分片过热、大 Key 和缓存击穿。
redis-slowlog — 慢命令、延迟尖刺和阻塞操作。
kafka-consumer-lag — 分区积压、消费速率和 rebalance。
rabbitmq-queue-backlog — 队列堆积、消费者和预取参数。
kafka-cheatsheet — 查看 Topic、消费组和 lag 的常用命令。
redis-cheatsheet — 查看内存、慢日志、热 Key 和集群状态。
动手任务 :在一次性环境里制造一次慢查询、一次连接池耗尽和一次消费积压。对每个故障记录:应用侧表现、数据库或中间件侧指标、第一条区分根因的命令,以及“扩容是否真的有效”的判断。
mysql -e 'SHOW FULL PROCESSLIST; SHOW ENGINE INNODB STATUS\G'
psql -c "select pid, state, wait_event_type, wait_event, now()-query_start as age from pg_stat_activity order by age desc limit 20;"
redis-cli INFO memory
redis-cli --hotkeys
redis-cli SLOWLOG GET 20
kafka-consumer-groups --bootstrap-server < broker> :9092 --describe --group < group>
rabbitmqctl list_queues name messages consumers
过关标准 :
能区分“数据库真的慢”和“应用连接池泄漏或等待”,并说明各自看什么指标。
能按分区或 Key 判断是全局瓶颈还是单点倾斜,不盲目加副本。
知道 transaction 池模式下哪些会话状态不能跨事务保留,避免连接复用引入诡异问题。
消费积压时先看生产速率、消费速率、分区倾斜和 rebalance,再决定扩消费者还是优化消费逻辑。
每项修复都有回滚方式,尤其是改变连接池、淘汰策略和消费者并发时。
阶段四:发布、回滚与复盘
目标 :发布前能评估兼容性和爆炸半径,发布中能按指标自动或手动停止,发布后能回滚并确认数据与消息没有留下不可逆后果。
阅读顺序 :
migration-readiness-checklist — 依赖、数据、回滚和观察窗口的上线前检查。
progressive-delivery — 金丝雀、蓝绿、流量比例和自动分析的取舍。
argo-rollouts — Rollout、暂停步骤和 AnalysisTemplate。
deployment — 滚动更新、可用副本和 rollout undo 的行为。
poddisruptionbudget — 发布和节点维护时的最小可用副本。
kubectl-cheatsheet — 查看发布状态、历史和回滚。
runbook — 把回滚、切流和验证步骤写成可执行手册。
postmortem — 无责复盘、时间线和改进项闭环。
incident-db-conn-pool — 一次发布引入连接泄漏,被误判为数据库变慢。
incident-rollout-pdb — 资源配额与滚动策略叠加导致发布停滞。
动手任务 :给一个测试服务配置 1% → 5% → 25% 的金丝雀,分析指标设为错误率和 P99 延迟;注入一个新版本缺陷,验证自动回滚或手动 undo,并检查数据库写入和消息是否出现重复或丢失。
kubectl rollout history deployment/< app> -n < namespace>
kubectl rollout status deployment/< app> -n < namespace>
kubectl rollout undo deployment/< app> -n < namespace>
kubectl argo rollouts get rollout < app> -n < namespace> --watch
kubectl get pdb -A
kubectl get events -n < namespace> --sort-by= .lastTimestamp | tail -30
过关标准 :
发布单写清兼容性顺序:先 schema 后代码、先双写后切换、回滚时旧代码能读新数据。
金丝雀每一步都有通过条件、观察时长和停止条件,而不是“发完再看”。
回滚后确认错误率、延迟、连接数和消费 lag 回到基线,并检查重复写入或消息堆积。
复盘能区分触发因素、直接原因和系统性原因,改进项有 owner 和验收时间。
下一次同类发布前,runbook 或告警规则已经更新,而不是只写一份复盘文档。
常见误区
看到 5xx 就重启所有实例,破坏现场,也掩盖了真正的发布或依赖问题。
把所有超时都归因于“网络抖动”,不区分建连、等待响应头、读取响应体和下游 deadline。
只看应用日志,不看网关日志、下游日志和请求 ID,导致链路断在中间。
数据库慢就加索引或加连接,忽略锁等待、长事务和连接池泄漏。
Redis 内存高就清空缓存,造成缓存击穿和数据库雪崩。
Kafka 积压就加消费者,忽略分区数上限、消费逻辑慢和 rebalance。
回滚代码却不回滚数据库变更或消息格式,留下新旧版本不兼容的数据。
复盘只写“加强监控”,没有具体指标、阈值、owner 和完成时间。
参考链接
读完自测
合上页面,先回答,再展开对照。
502、504 和连接超时分别说明请求走到了哪一步?第一检查点有什么不同?
数据库连接耗尽时,为什么不能只调大 max_connections?应该先看什么?
发布后错误率升高,什么情况下应该立即回滚,什么情况下应该先切流或降级?
答案
502 表示网关已经连上上游,但收到了无效响应,常见于上游进程崩溃、端口错误或协议不匹配;504 表示网关连上了上游,但在超时时间内没有拿到完整响应,通常是后端慢、排队或超时配置不合理;连接超时表示 SYN 没有得到响应,链路可能不可达、被安全组丢弃或目标过载。三者分别先查上游健康与响应、后端耗时与超时配置、路由与网络可达性。
只调大 max_connections 会把压力转给数据库内存、CPU 和锁,可能让问题更糟。应先看连接池使用率、空闲事务、长事务、慢查询和应用侧连接是否泄漏,再决定修连接池、优化查询、限制入口流量还是扩容数据库。
如果错误率快速上升、核心链路受影响且回滚成本可控,应立即回滚;如果问题只影响新版本的部分流量,可以先切流或降级争取时间;如果涉及数据库 schema 或消息格式,必须先确认旧版本能否兼容新数据,不能盲目回滚代码。
相关条目
← role-ai-infra-oncall
role-data-platform →