linux-sre-handbook

05-经典案例库

案例 1:数据库连接池耗尽

现象:服务间歇性返回 500,监控显示有时请求正常有时全部失败。

排查

# 查看应用日志:Cannot get connection from pool
# Tomcat/HikariCP 连接池大小 10,但并发请求 200+

根因:慢查询导致连接占用时间长,连接池被耗尽。

解决:优化慢查询 + 增大连接池 + 设置获取连接超时。

案例 2:磁盘写满

现象:应用写入大量报错,功能异常。

排查

df -h                # 磁盘 100%
du -sh /*/           # 逐级找大目录
du -sh /var/log/*/   # 日志占据 80%
ls -lhS /var/log/nginx/ | head

根因:Nginx 日志未配置轮转,一个 access.log 达 200GB。

解决:配置 logrotate + 清理旧日志 + 监控磁盘使用率。

案例 3:DNS 解析延迟

现象:服务间偶发超时,间歇性,难以复现。

排查

strace -p <PID> -T -e trace=network 2>&1 | grep -v EAGAIN
# 发现 getaddrinfo 调用耗时 5-10s

根因:应用每次请求都做 DNS 解析(没用连接池),/etc/resolv.conf 配了 3 个 DNS 服务器,其中一个不可达,超时 5s。

解决:应用层加 DNS 缓存 + 检查 /etc/resolv.conf options timeout 配置。

案例 4:Cache 雪崩

现象:Redis key 集中过期,数据库瞬时负载飙升,API 大面积超时。

排查

redis-cli --bigkeys
redis-cli info keyspace
# 发现大量 key 在整点同时过期

根因:缓存预热脚本将所有 key 设了相同的 TTL。

解决:TTL 加随机偏移 (±30%) + 互斥锁防缓存击穿。

案例 5:文件句柄泄漏

现象:服务运行几天后开始报 “Too many open files”。

排查

lsof -p <PID> | wc -l       # 显示 65536 (上限)
lsof -p <PID> | awk '{print $NF}' | sort | uniq -c | sort -rn | head
# socket 数量异常高

根因:HTTP 客户端未正确关闭响应的 Body,连接未释放。

解决:修复代码 resp.Body.Close(),加 prometheus 监控 fd 数量。

经验总结

  1. 监控先行 — 没有监控的故障是瞎猜
  2. 变更即风险 — 80% 的故障与变更相关
  3. 假设驱动 — 先形成假设,再用数据验证
  4. 快速恢复 > 找根因 — 先止血,后解剖

延伸阅读