- 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]>
8.9 KiB
运维排查手册 (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;" |