系统学习 学习路径总入口:先选领域,再建立模型,最后用故障演练验证

后端 on-call 学习路径:从 5xx 与超时止血,到日志、数据库、缓存、消息队列和发布回滚

使用方式

后端值班面对的从来不是单一组件,而是一条请求链路:入口、应用、连接池、数据库、缓存、消息队列和发布系统。这条路径按“先止血、再定位、后修复”的值班顺序组织,不按语言或框架分类。

四个阶段建议在一次完整值班周期内走完,每个阶段都用自己的服务或测试环境练习:

每次处理完都留下三样东西:请求 ID 或时间窗口、验证命令、结论。没有记录的“已恢复”无法复盘。

阶段一:接警后的 10 分钟,判断 5xx 与超时

目标:能区分 4xx、5xx、连接超时、网关超时和上游重置,判断故障发生在入口、应用还是依赖,并优先执行回滚、切流、扩容或降级。

阅读顺序:

  1. on-call — 告警分级、备份值班和升级时限。
  2. sre-oncall-checklist — 从确认影响到止血和复盘的固定检查项。
  3. incident-response-playbook — 事故分级、角色分工和沟通节奏。
  4. http-status-cheatsheet — 状态码与网关、上游、限流的对应关系。
  5. 502-bad-gateway — 网关收到上游无效响应时的排查顺序。
  6. 504-gateway-timeout — 已连上上游但等待响应超时的根因分类。
  7. connection-timeout — SYN 无响应、路由黑洞和中间设备丢包。
  8. scenario-service-502 — 从入口、网关到上游的分层排查场景卡。
  9. curl-cheatsheet — 分段测量建连、首字节和总耗时。
  10. 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

过关标准:

阶段二:日志、超时链路与运行时异常

目标:能用请求 ID 把一次失败串联到具体日志和代码路径,区分应用自身超时、下游 deadline、连接中断和运行时阻塞。

阅读顺序:

  1. logql-cheatsheet — 按标签、行过滤和解析提取错误字段。
  2. loki — 日志聚合、标签设计和保留策略。
  3. journalctl — 按服务、时间和优先级过滤 systemd 日志。
  4. jq — 从结构化日志和 API 响应中提取关键字段。
  5. context-deadline-exceeded — Go context 超时与下游预算耗尽。
  6. grpc-deadline-exceeded — gRPC DEADLINE_EXCEEDED 的客户端与服务端差异。
  7. unexpected-eof — 响应未完整读取就断开的定位方法。
  8. connection-reset-by-peer — 对端重置、keepalive 和中间代理行为。
  9. event-loop-blocked — Node.js 事件循环被同步任务阻塞。
  10. 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

过关标准:

阶段三:数据库、缓存与消息队列

目标:看到慢查询、锁等待、连接耗尽、缓存热 Key、消费积压时,能判断瓶颈在数据库、连接池、缓存还是消费者,并避免用扩容掩盖问题。

阅读顺序:

  1. mysql-slow-query — 执行计划、索引选择和慢查询日志。
  2. mysql-deadlock — 死锁等待图与事务加锁顺序。
  3. postgres-connection-exhausted — 连接池、空闲事务和 max_connections。
  4. postgres-lock-wait — 锁等待链、长事务和 DDL 阻塞。
  5. pgbouncer — session、transaction、statement 三种池模式的边界。
  6. redis-memory-full — maxmemory、淘汰策略和内存碎片。
  7. redis-hotkey — 单分片过热、大 Key 和缓存击穿。
  8. redis-slowlog — 慢命令、延迟尖刺和阻塞操作。
  9. kafka-consumer-lag — 分区积压、消费速率和 rebalance。
  10. rabbitmq-queue-backlog — 队列堆积、消费者和预取参数。
  11. kafka-cheatsheet — 查看 Topic、消费组和 lag 的常用命令。
  12. 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

过关标准:

阶段四:发布、回滚与复盘

目标:发布前能评估兼容性和爆炸半径,发布中能按指标自动或手动停止,发布后能回滚并确认数据与消息没有留下不可逆后果。

阅读顺序:

  1. migration-readiness-checklist — 依赖、数据、回滚和观察窗口的上线前检查。
  2. progressive-delivery — 金丝雀、蓝绿、流量比例和自动分析的取舍。
  3. argo-rollouts — Rollout、暂停步骤和 AnalysisTemplate。
  4. deployment — 滚动更新、可用副本和 rollout undo 的行为。
  5. poddisruptionbudget — 发布和节点维护时的最小可用副本。
  6. kubectl-cheatsheet — 查看发布状态、历史和回滚。
  7. runbook — 把回滚、切流和验证步骤写成可执行手册。
  8. postmortem — 无责复盘、时间线和改进项闭环。
  9. incident-db-conn-pool — 一次发布引入连接泄漏,被误判为数据库变慢。
  10. 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

过关标准:

常见误区

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. 502、504 和连接超时分别说明请求走到了哪一步?第一检查点有什么不同?
  2. 数据库连接耗尽时,为什么不能只调大 max_connections?应该先看什么?
  3. 发布后错误率升高,什么情况下应该立即回滚,什么情况下应该先切流或降级?
答案
  1. 502 表示网关已经连上上游,但收到了无效响应,常见于上游进程崩溃、端口错误或协议不匹配;504 表示网关连上了上游,但在超时时间内没有拿到完整响应,通常是后端慢、排队或超时配置不合理;连接超时表示 SYN 没有得到响应,链路可能不可达、被安全组丢弃或目标过载。三者分别先查上游健康与响应、后端耗时与超时配置、路由与网络可达性。
  2. 只调大 max_connections 会把压力转给数据库内存、CPU 和锁,可能让问题更糟。应先看连接池使用率、空闲事务、长事务、慢查询和应用侧连接是否泄漏,再决定修连接池、优化查询、限制入口流量还是扩容数据库。
  3. 如果错误率快速上升、核心链路受影响且回滚成本可控,应立即回滚;如果问题只影响新版本的部分流量,可以先切流或降级争取时间;如果涉及数据库 schema 或消息格式,必须先确认旧版本能否兼容新数据,不能盲目回滚代码。

相关条目

微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令