深色模式
中间件超时排查
摘要:中间件超时的报错常常一模一样,但成因可能是网络抖动、下游慢、连接池太小或重试放大。本文按"客户端 → 网络 → 服务端"三段拆解,并给出超时时间必须逐层递减这一关键原则。
适用环境
bash
ss -V
which redis-cli mysql kafka-consumer-groups.sh rabbitmqctl 2>/dev/null
cat /proc/sys/net/ipv4/tcp_syn_retries1
2
3
2
3
排障步骤
第 1 步:先分清是哪种超时
- 连接超时:连不上(建连阶段),多为网络、端口、backlog、连接池获取超时
- 读写超时:连上了但没返回,多为下游慢或服务端线程打满
- 获取连接超时(pool timeout):连接池借不到连接,与网络无关
bash
# 建连是否通
timeout 3 bash -c 'cat < /dev/null > /dev/tcp/<中间件IP>/<端口>' && echo connect-ok
# 单次请求往返耗时
redis-cli -h <host> -p 6379 --latency-history -i 51
2
3
4
2
3
4
第 2 步:检查客户端连接池状态
bash
# 本机到中间件的连接数
ss -ant state established '( dport = :6379 )' | wc -l
ss -ant state established '( dport = :3306 )' | wc -l1
2
3
2
3
若连接数长期等于池上限,说明池被占满,新请求在排队等待获取连接。
"获取连接超时"不是"查询超时"
报错里出现 pool/timeout waiting for connection 时,加网络超时时间毫无作用,应扩大池容量或缩短单次占用时长。
第 3 步:确认服务端侧是否慢
Redis:
bash
redis-cli info stats | grep -E 'instantaneous_ops_per_sec|rejected_connections'
redis-cli slowlog get 201
2
2
关系型数据库参照慢查询排查思路,先看活跃会话。
第 4 步:核对超时配置是否倒挂
bash
grep -rE 'timeout|connectTimeout|socketTimeout|maxWait' /etc/app/*.yml 2>/dev/null1
超时时间倒挂会引发雪崩
上游 3 秒超时、下游 30 秒超时时,上游早早放弃但下游仍在计算,请求不断堆积最终压垮下游。必须保证:调用方超时 < 被调方超时 < 网关超时。
第 5 步:检查重试是否放大流量
bash
grep -rE 'retry|maxAttempts|retries' /etc/app/*.yml 2>/dev/null1
网关重试 × SDK 重试 × 业务重试,会把 1 倍流量放大到 8 倍以上,让下游从"慢"变成"死"。
第 6 步:网络层确认
bash
ss -antp state established '( dport = :6379 )' | head
tcpdump -i any -nn -c 20 host <中间件IP>1
2
2
验证
bash
redis-cli -h <host> -p 6379 ping
ss -ant state established '( dport = :6379 )' | wc -l
curl -sS -o /dev/null -w 'code=%{http_code} total=%{time_total}\n' http://127.0.0.1:8080/api1
2
3
2
3
常见坑
连接池越大越好是错的
过大的连接池会让数据库并发暴涨,反而拉高整体延迟。池大小应参考下游能承受的并发数。
网络抖动时重试无法解决
重试对已超时的请求通常是无效放大,应配合熔断与退避(backoff + jitter)。
客户端与服务端 keepalive 不一致
服务端主动断掉空闲连接,客户端认为连接仍有效,下一次请求必然失败一次,表现为偶发错误。
直接调大所有超时参数
会把短时抖动变成长时间资源占用,导致线程池被占满。应先定位慢在哪,再针对性调整。