主题
第 8 章 · 常见踩坑
生活类比:大堂经理也会犯错——把所有人都引到刚晕倒的柜台、一个窗口倒了大家挤爆另一个、重复给顾客结账两次……
这一章是 避坑手册,生产事故多半出在「以为 LB 万能」的细节里。
8.1 坑 1:重试导致重复操作(最危险)
场景
用户 POST /orders(下单)
→ LB 转发到 A
→ A 处理慢,LB 超时
→ LB 认为失败,重试到 B
→ B 又下一单
→ 用户账户扣了两次钱Nginx 配置:
nginx
proxy_next_upstream error timeout http_502 http_503 http_504;默认对 idempotent 方法(GET/HEAD)重试;POST 等 默认不重试——但前端、网关、客户端 SDK 可能各自重试。
对策
| 层级 | 做法 |
|---|---|
| 业务 | 幂等键 Idempotency-Key: uuid |
| 数据库 | 唯一约束 (user_id, order_no) |
| LB | 谨慎开启 POST 重试;调大 proxy_read_timeout |
| 前端 | 防重复提交按钮 |
生活例子:顾客刷卡没听到「滴」,又刷一次——POS 机要能识别「同一笔别扣两次」。
8.2 坑 2:健康检查误杀
症状
节点一会儿 healthy 一会儿 unhealthy(flapping),流量抖动。
常见原因
- 探针
timeout太短,GC 时偶尔超时 /healthz走了鉴权,返回 401/healthz查了慢 SQL,探针本身太重- 网络抖动,threshold 设太小
对策
yaml
# 示例:连续 3 次失败才摘,连续 2 次成功才恢复
unhealthy_threshold: 3
healthy_threshold: 2
timeout: 3s探针接口要 极轻:ping DB 连接池,别 SELECT COUNT(*) 大表。
8.3 坑 3:会话丢失(IP Hash 依赖症)
见第 5 章。症状:用户随机掉登录。
根因:扩缩容、NAT、移动网络 IP 变化。
解法:Redis Session 或 JWT,放弃 IP Hash。
8.4 坑 4:慢启动(Slow Start)缺失
场景
新 Pod 刚启动,JVM 还在预热,立刻被打满流量 → 大量超时 → 又被健康检查杀掉 → 发布失败。
对策
- K8s
readinessProbe加initialDelaySeconds - 网关 渐进加权:新节点 weight 从 1 渐增到 100
- 应用层 warmup:启动后先预热缓存
生活例子:新实习生第一天,先让他旁观 2 小时,再慢慢接简单业务。
8.5 坑 5:热点机器(Hot Spot)
原因
- IP Hash + 大客户 NAT IP
- 一致性哈希虚拟节点不足
- 某个「超级用户」请求量极大
现象
A: CPU 95%
B: CPU 20%
C: CPU 15%对策
- 换算法(轮询 / least_conn)
- 一致性哈希加虚拟节点
- 热点 key 拆分、本地缓存
8.6 坑 6:LB 自身成为单点
[单台 Nginx] ← 挂了全站下线
/ | \
[A] [B] [C]对策
- 主备:Keepalived + VIP 漂移
- 多实例:云 LB 天然多 AZ
- DNS 多 A 记录 + 健康检查(次选)
8.7 坑 7:长连接未开启
每次请求新建 TCP → TLS 握手 → 后端延迟 +1~30ms。
三件套(Nginx):
nginx
upstream backend { keepalive 64; }
proxy_http_version 1.1;
proxy_set_header Connection "";8.8 坑 8:超时配置不合理
| 配置过短 | 配置过长 |
|---|---|
| 正常慢请求被断开 | 僵死连接占满 worker |
| 触发无谓重试 | 用户等太久 |
按 P99 延迟 + 业务容忍度 设 proxy_read_timeout,别拍脑袋。
8.9 坑 9:雪崩(Cascade Failure)
后端 A 变慢
→ LB 重试增多
→ 更多请求堆积
→ A 更慢
→ 健康检查超时
→ 流量涌向 B、C
→ B、C 也扛不住
→ 全挂对策组合拳
- 熔断:错误率超阈值暂停调用
- 限流:入口控制 QPS
- 超时:别无限等
- 舱壁隔离:核心接口独立线程池
- 降级:非核心功能先关
生活例子:一个收银台慢了,大家全挤过去,结果全堵死——应该暂时关闭该通道并限流。
8.10 坑 10:忽略 X-Forwarded-For 伪造
客户端可伪造 X-Forwarded-For。只有 可信的 LB 应追加该头,应用取 最左还是最右 要统一规范。
nginx
# LB 追加真实 IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;应用侧应信任 来自 LB 网段 的请求,解析时取 $remote_addr 或规范化的最后一跳。
8.11 踩坑速查表
| 症状 | 可能原因 | 第一反应 |
|---|---|---|
| 随机 502 | 后端挂了 / 健康检查未摘流 | 查后端池状态 |
| 重复下单 | 重试 + 非幂等 | 查幂等键、重试配置 |
| 发布后全 502 | readiness 未就绪 | 查探针、预热 |
| 某台 CPU 100% | 热点 / ip_hash | 查算法与 key 分布 |
| 登录老掉 | Session 不共享 | 上 Redis / JWT |
| 延迟突然升高 | 长连接未开 / 后端满 | 查 keepalive、连接数 |
8.12 一句话总结
LB 不是魔法:重试要幂等、探针要轻、会话要共享、发布要预热、入口要限流——否则大堂经理会把店带沟里。
下一章 → 09 · 综合实战