Files
Bruno GaoandQwen-Coder 2fd1eb59ab docs: Complete production-grade documentation set
- Create SECURITY.md with vulnerability disclosure policy
- Create docs/README.md as documentation index page
- Create docs/observability.md with metrics/logs/traces/alerting/SLO specs
- Create docs/runbook.md with troubleshooting scenarios (RB-01 to RB-05)
- Create docs/security.md with security design and compliance
- Create docs/release.md with versioning and rollback strategies
- Create docs/database.md with database design and migration strategy
- Create docs/adr/0005-cache-error-handler.md for cache error handling ADR
- Update README.md with documentation index section
- Update docs/architecture.md to update B-7 rule and add trust boundary section
- Create docs/api-guide.md with API specifications
- Fix method names in OrderDao.java to match OrderMapper interface
- Add Spring Boot Actuator dependency to tmpl-infrastructure
- Fix Redis ping method in RedisHealthContributor.java
- Fix syntax errors and method names in OrderAppService.java

Co-authored-by: Qwen-Coder <[email protected]>
2026-02-12 21:47:33 +08:00

8.9 KiB
Raw Permalink Blame History

运维排查手册 (Runbook)

本文档覆盖 tmpl-api 服务最常见的故障场景。每个场景包含:触发条件、排查步骤、 恢复操作和事后改进建议。

适用角色:SRE、运维工程师、值班开发人员。 前置条件:拥有 Kubernetes 集群 kubectl 权限、Grafana/Prometheus 访问权限、 数据库与 Redis CLI 访问权限。


RB-01 数据库连接池耗尽

触发条件

告警 DatabaseConnectionExhaustion 触发(hikaricp_connections_pending > 5 持续 1 分钟) 或应用日志出现 HikariPool-1 - Connection is not available, request timed out after 30000ms。

排查步骤

Step 1 — 确认连接池状态

curl -s http://<pod-ip>:9090/actuator/metrics/hikaricp.connections.active | jq .
curl -s http://<pod-ip>:9090/actuator/metrics/hikaricp.connections.pending | jq .

若 active 接近 max(默认 10)且 pending 持续增长,确认连接池耗尽。

Step 2 — 检查数据库慢查询

SELECT pid, now() - pg_stat_activity.query_start AS duration, query, state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 seconds'
  AND state != 'idle'
ORDER BY duration DESC;

Step 3 — 检查是否存在长事务

SELECT pid, age(clock_timestamp(), xact_start) AS xact_age, query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_age DESC
LIMIT 10;

Step 4 — 确认数据库最大连接数

SHOW max_connections;
SELECT count(*) FROM pg_stat_activity;

恢复操作

严重程度 操作
中等 终止长事务:SELECT pg_terminate_backend(<pid>);
严重 重启受影响的 Pod:kubectl rollout restart deployment/tmpl-api -n <ns>
持续 提升 HikariCP maximumPoolSize(配合数据库 max_connections 调整)

事后改进

检查是否有缺少索引的查询导致全表扫描;确认 @Transactional 范围是否过大;考虑引入连接池监控 Dashboard 面板和更低的超时阈值。


RB-02 Redis 连接抖动 / 缓存降级

触发条件

告警 RedisDown 触发,或日志中出现 GracefulCacheErrorHandler 的 WARN 级别条目 (Cache 'order' get failed),health 端点显示 redisPing: DOWN。

排查步骤

Step 1 — 确认 Redis 实例状态

redis-cli -h <redis-host> -p 6379 PING
redis-cli -h <redis-host> -p 6379 INFO server | grep uptime
redis-cli -h <redis-host> -p 6379 INFO clients | grep connected_clients

Step 2 — 检查网络连通性

kubectl exec -it <pod> -- nc -zv <redis-host> 6379

Step 3 — 检查 Redis 内存与驱逐

redis-cli INFO memory | grep -E "used_memory_human|maxmemory_human|evicted_keys"

Step 4 — 查看应用日志确认降级行为

kubectl logs <pod> --since=5m | grep -i "cache.*fail\|redis\|GracefulCacheErrorHandler"

恢复操作

场景 操作
Redis 实例宕机 重启 Redis Pod / 故障转移到从节点
网络问题 检查 NetworkPolicy、Service 配置
内存满 调整 maxmemory 或优化 key TTL
应用侧连接池满 调整 spring.data.redis.lettuce.pool.max-active

关键认知:当 app.cache.enabled=true 且 Redis 不可用时,GracefulCacheErrorHandler 会记录 WARN 并回退到数据库查询。服务不会宕机,但 DB 负载会上升。若 DB 也接近瓶颈, 应优先恢复 Redis。

事后改进

考虑引入 Redis Sentinel / Cluster 高可用方案;评估是否需要 Resilience4j CircuitBreaker 包裹缓存调用;确认缓存 key TTL 设置合理。


RB-03 Flyway 迁移失败

触发条件

应用启动失败,日志出现 FlywayMigrateException 或 Migration checksum mismatch。 Pod 处于 CrashLoopBackOff 状态。

排查步骤

Step 1 — 查看 Flyway 日志

kubectl logs <pod> | grep -i "flyway\|migration"

Step 2 — 检查迁移历史表

SELECT version, description, success, checksum, installed_on
FROM flyway_schema_history
ORDER BY installed_rank DESC
LIMIT 10;

Step 3 — 确认失败类型

类型 日志关键词 说明
Checksum 不匹配 checksum mismatch 已应用的迁移文件被修改
SQL 语法错误 ERROR: syntax error 迁移脚本有 SQL 错误
冲突版本号 Found more than one migration with version 版本号重复
手动修改了库 Detected resolved migration not applied 库结构被手动改动

恢复操作

场景 操作
SQL 语法错误 修复脚本,手动清理 flyway_schema_history 中失败记录:DELETE FROM flyway_schema_history WHERE success = false;
Checksum 不匹配 切勿修改已部署的迁移文件! 使用 flyway repair 仅在确认数据一致时更新 checksum
手动修改了库 创建补偿迁移脚本(新版本号),使 schema 回到预期状态

重要:Flyway 迁移本质上是不可逆的(forward-only)。每次修复后必须创建新的迁移脚本 而非修改历史脚本。回滚需通过编写反向 DDL 的新迁移实现。

事后改进

所有迁移脚本必须在 CI 中通过 Testcontainers 验证;禁止在 main 分支合并后修改迁移文件;命名规范参见 database.md。


RB-04 P95 延迟飙升

触发条件

告警 HighLatencyP95 触发(P95 > 500ms 持续 3 分钟),或 Grafana 延迟面板出现 突增尖峰。

排查步骤

Step 1 — 定位慢端点

在 Prometheus 中查询:

topk(5,
  histogram_quantile(0.95,
    sum(rate(http_server_requests_seconds_bucket[5m])) by (le, uri)
  )
)

Step 2 — 排除基础设施因素

检查 HikariCP 等待连接数(→ RB-01)、Redis 延迟(→ RB-02)、Pod CPU/内存使用率、 GC 暂停时间:

rate(jvm_gc_pause_seconds_sum[5m]) / rate(jvm_gc_pause_seconds_count[5m])

Step 3 — 检查上游依赖

若服务调用外部 API 或消息队列,检查对应 Timer 指标或日志中的耗时。

Step 4 — 检查缓存命中率

sum(rate(cache_gets_total{result="hit"}[5m]))
/
sum(rate(cache_gets_total[5m]))

命中率骤降可能导致大量 DB 查询,引发延迟升高。

恢复操作

根因 操作
DB 慢查询 添加索引、优化 SQL、终止长事务
GC 抖动 检查堆内存配置、排查内存泄漏
缓存击穿 恢复 Redis、预热缓存
流量突增 HPA 扩容、启用限流

事后改进

设置 P99 延迟告警;在慢查询日志中启用 log_min_duration_statement;考虑在 API 层引入超时和熔断。


RB-05 容器反复重启 (CrashLoopBackOff)

触发条件

kubectl get pods 显示 Pod 状态为 CrashLoopBackOff,Restart count 持续增加。

排查步骤

Step 1 — 查看 Pod 事件和日志

kubectl describe pod <pod-name> -n <ns>
kubectl logs <pod-name> -n <ns> --previous

Step 2 — 分类退出原因

Exit Code 含义 常见原因
0 正常退出 主线程结束(配置错误,未启动 Web 服务器)
1 应用异常 Bean 创建失败、数据库不可达、Flyway 失败
137 OOMKilled 容器内存超出 resources.limits.memory
143 SIGTERM 被 kubelet 杀死(探针超时)

Step 3 — 针对性检查

若 Exit Code = 137:检查 resources.limits.memory 是否过小,JVM -Xmx 是否超出容器限制,堆外内存(Metaspace、DirectBuffer)是否泄漏。

若 Exit Code = 1:检查 application.yml 配置是否正确,数据库/Redis 连接信息是否正确注入(Secret 挂载),Flyway 是否失败(→ RB-03)。

若 Exit Code = 143:检查 startup/liveness 探针配置,initialDelaySeconds 是否足够。

恢复操作

根因 操作
OOMKilled 提升 resources.limits.memory,调整 JVM 参数 -XX:MaxRAMPercentage=75
DB 不可达 确认 Secret 中连接 URL 正确,DB 实例正常,NetworkPolicy 允许流量
探针超时 延长 initialDelaySeconds、timeoutSeconds
Flyway 失败 参见 RB-03

事后改进

建立 Pod 资源 baseline(通过 VPA 推荐或历史监控数据);在 CI/CD 中验证配置文件完整性;为 startup 探针留足应用冷启动时间(至少 60s)。


通用排查工具速查

用途 命令
Pod 日志 kubectl logs <pod> -n <ns> -f --since=10m
前一次崩溃日志 kubectl logs <pod> -n <ns> --previous
进入 Pod kubectl exec -it <pod> -n <ns> -- /bin/sh
端口转发 kubectl port-forward <pod> 9090:9090 -n <ns>
健康检查 `curl http://localhost:9090/actuator/health
Prometheus 指标 curl http://localhost:9090/actuator/prometheus
Redis CLI redis-cli -h <host> -p 6379 INFO
PostgreSQL psql -h <host> -U <user> -d <db> -c "SELECT 1;"