← All incidents

[Eval][v2][zh] Payment service connection pool exhaustion after batch job deploy

service: payment-svccreated: 6/2/2026, 11:49:21 PM

Raw incident context

Time: 14:02 UTC. payment-svc p99 latency jumped from 120ms to 4.8s within ~3 minutes.
Error rate climbed from 0.1% to 12% (mostly HTTP 500).
Application logs (last 5min): repeated "FATAL: sorry, too many clients already" and "connection refused"
from payment-svc → postgres-primary.

Postgres metrics:
- CPU: 35% (normal)
- active_connections: 500 / 500 (max_connections)
- waiting_queries: 87
- slow_query_log shows a new query running every 30s: SELECT * FROM ledger_entries WHERE status='pending'
  (no index on status; full table scan over ~12M rows, ~2.4s per execution)

Deploy history:
- 13:50 UTC — payment-svc v2.41 shipped. Changelog mentions "added nightly settlement batch (cron: */30 * * * *)"
- No infra/DB changes in past 7 days.

On-call notes (Slack):
- 14:03 — CS reports failed checkout volume rising
- 14:04 — Pager: PaymentSvcErrorRateHigh
- 14:06 — "DB looks healthy, CPU is fine" (initial mis-diagnosis)

Summary

SEV1

支付服务 payment-svc 在 14:02 UTC 出现 p99 延迟从 120ms 飙升到 4.8s,错误率从 0.1% 升至 12%(HTTP 500),客户报告结账失败。根因是 13:50 部署的新版本引入了每 30 秒执行的全表扫描查询,耗尽了 PostgreSQL 连接池(max_connections=500),导致新连接被拒绝。

Severity reasoning: 用户可见的结账失败(收入路径中断),错误率 >1% 超过 5 分钟,符合 SEV1 标准。

deepseek-chat·prompt v2·output: zh·11663ms·2150↑ / 1809↓ tok·$0.00257

Root cause hypotheses

  • high新部署的 payment-svc v2.41 引入的定时任务(每 30 秒)执行无索引查询 SELECT * FROM ledger_entries WHERE status='pending',导致全表扫描,长时间占用数据库连接,耗尽连接池。

    Evidence: 慢查询日志显示该查询每 30 秒执行一次,耗时约 2.4 秒;部署时间 13:50 与问题开始时间 14:02 吻合;应用日志报 'too many clients already'。

  • medium数据库连接池配置错误,max_connections 设置过低(500),无法应对正常流量波动。

    Evidence: active_connections 达到 500/500,但 CPU 仅 35%,表明瓶颈在连接数而非计算资源。

  • low外部流量突增导致数据库连接数超限。

    Evidence: 无流量突增迹象(错误率上升与部署时间强相关),且慢查询日志显示新查询模式。

Investigation checklist

  1. 确认连接池耗尽:查看当前活跃连接和等待查询数
    kubectl exec -n prod deployment/postgres-primary -- psql -U postgres -c "SELECT count(*) FROM pg_stat_activity WHERE state != 'idle'; SELECT count(*) FROM pg_stat_activity WHERE wait_event_type = 'Lock';"

    Expected: 活跃连接数接近 500,等待查询数 >0

  2. 定位慢查询:检查 pg_stat_activity 中运行时间最长的查询
    kubectl exec -n prod deployment/postgres-primary -- psql -U postgres -c "SELECT pid, now() - pg_stat_activity.query_start AS duration, query, state FROM pg_stat_activity WHERE state != 'idle' ORDER BY duration DESC LIMIT 10;"

    Expected: 看到 SELECT * FROM ledger_entries WHERE status='pending' 查询持续运行

  3. 验证新部署的定时任务:检查 payment-svc 的 cron 配置
    kubectl get configmap -n prod payment-svc-config -o jsonpath='{.data.cron}' 2>/dev/null || kubectl logs -n prod -l app=payment-svc --since=30m | grep -i 'settlement\|cron\|batch' | head -20

    Expected: 显示每 30 分钟执行一次的 settlement batch 任务

  4. 检查 ledger_entries 表索引情况
    kubectl exec -n prod deployment/postgres-primary -- psql -U postgres -c "\d ledger_entries" | grep -i 'index'

    Expected: status 列上没有索引

  5. 确认错误率来源:查看 payment-svc 日志中的 500 错误
    kubectl logs -n prod -l app=payment-svc --since=15m | grep 'HTTP 500\|500' | head -20

    Expected: 错误与数据库连接失败相关

Mitigation plan

  • 立即终止阻塞查询:杀掉正在执行全表扫描的查询,释放连接。

    Risk: 可能导致该批次数据未处理,但不会丢失数据;需确认查询来源。

    Rollback: 如果误杀,重新执行查询(但需先加索引)。

  • 临时增加 max_connections 到 1000 并重启数据库(或动态调整)。

    Risk: 增加数据库内存压力,可能引发 OOM;需监控内存使用。

    Rollback: 恢复 max_connections 为 500 并重启。

  • 回滚 payment-svc 到 v2.40 版本,移除有问题的定时任务。

    Risk: 回滚期间服务短暂不可用(滚动更新);需确认 v2.40 兼容性。

    Rollback: 重新部署 v2.41(但需先修复)。

Customer impact

部分用户无法完成结账,收到 500 错误。影响范围约为总用户的 12%(基于错误率)。预计在回滚和连接恢复后 5-10 分钟内恢复。

Postmortem draft

Summary

[FILL IN]

Timeline (UTC)

  • 13:50 - 部署 payment-svc v2.41,引入每 30 秒的 settlement batch 查询。
  • 14:02 - p99 延迟从 120ms 升至 4.8s,错误率开始上升。
  • 14:03 - CS 报告结账失败增加。
  • 14:04 - Pager 触发 PaymentSvcErrorRateHigh。
  • 14:06 - 初步误判数据库健康(CPU 正常)。
  • [FILL IN] - 发现慢查询并终止。
  • [FILL IN] - 回滚部署。
  • [FILL IN] - 服务恢复。

Impact

  • 错误率 12%,持续约 [FILL IN] 分钟。
  • 用户结账失败,收入损失 [FILL IN]。

Root Cause

新部署的定时任务执行无索引全表扫描,耗尽数据库连接池。

Detection

通过慢查询日志和连接数监控发现。

Response

  • 终止慢查询。
  • 增加 max_connections。
  • 回滚部署。

What Went Well

  • 监控告警及时。
  • 慢查询日志帮助快速定位。

What Went Poorly

  • 初始误判数据库健康。
  • 部署前未进行性能测试。

Action Items

  • [ ] 为 ledger_entries.status 添加索引。
  • [ ] 在 CI/CD 中增加慢查询检测。
  • [ ] 审查所有定时任务的性能影响。

Follow-ups

  • P0为 ledger_entries.status 列添加索引,防止全表扫描。数据库管理员
  • P1在 CI/CD 流水线中集成慢查询检测(如 pt-query-digest)。平台团队
  • P1审查 payment-svc 所有定时任务的 SQL 性能,添加 explain 分析。服务所有者
  • P1增加数据库连接池使用率告警(>80%)。可观测性团队
  • P2更新部署流程,要求变更前进行性能基准测试。SRE 团队