TCP连接被丢弃主因是系统tcp-backlog过小;需调大/proc/sys/net/core/somaxconn并同步配置Redis tcp-backlog;慢查询与大key导致性能瓶颈;连接池未复用引发重连风暴;分布式锁须用SET NX PX原子指令及Lua校验解锁。

tcp-backlog 不调,连接直接被系统丢弃
QPS冲到8万以上时,你可能突然发现大量客户端报 Connection refused,但Redis进程本身CPU和内存都正常——问题大概率出在操作系统层面的连接队列满了。Linux默认 tcp-backlog 是511,而Redis启动时只按这个值去调用 listen();如果内核参数 /proc/sys/net/core/somaxconn 也卡在512,那并发建连请求超过这个数就会被静默丢弃。
- 先查系统上限:
cat /proc/sys/net/core/somaxconn,若 ≤1024,执行echo 1024 > /proc/sys/net/core/somaxconn - 再改Redis配置:
tcp-backlog 1024(必须 ≤ somaxconn 值) - 重启Redis生效;不改的话,哪怕机器有16核、64GB内存,连接层就先跪了
慢查询+大key=雪崩前兆,不是Redis扛不住,是它在等你
单节点实测能跑3–4万QPS,但如果你的监控里出现大量 slowlog get 10 返回耗时 >10ms 的命令,或者 redis-cli --bigkeys 扫出几百MB的Hash/Set,那QPS上不去不是Redis不行,是你在拿它当数据库使。
- String类操作天然快,但一个
HGETALL big_user_profile拉10MB数据,网络+序列化+内存拷贝全压在单线程上,一秒钟只能处理几十次 - 用
SCAN替代KEYS *,用HSCAN分批读Hash,别让单次命令阻塞主线程超1ms - 大key必须拆:用户订单按月分片为
order:uid:202601、order:uid:202602,避免单key膨胀
连接池配错,10万QPS变成10万次重连
Java用Lettuce、Go用redis-go、Python用redis-py,都得自己管连接池。常见错误是每秒新建连接又销毁,而不是复用——这比命令慢更致命。
- 每个服务实例维持
50–100个长连接,不是“越多越好”;连接数翻倍但QPS不涨,说明网络或Redis已饱和,再加只会加剧争抢 - Lettuce要关自动重连:
ClientOptions.builder().autoReconnect(false),靠上层熔断兜底 - Python redis-py 必须设
max_connections=100和socket_keepalive=True,否则空闲连接被中间设备断开后,首次请求必超时
锁用SETNX+EXPIRE?原子性早没了
秒杀场景下,用 SETNX key 1 再 EXPIRE key 500 是经典反模式:两步非原子,网络抖动或进程崩溃会导致锁永远不释放。
- 必须用
SET key 1 NX PX 500,NX保证不存在才设,PX毫秒级过期,一步到位 - 解锁绝不能用
DEL,得用Lua脚本校验value是否匹配:if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end - 过期时间别拍脑袋设5秒,要略大于业务最大耗时(比如扣库存+写日志共320ms),设成500ms刚好,太短会误释放,太长卡住后续请求
真正卡住10万QPS的,往往不是Redis本身,而是连接队列、大key、连接池、锁实现这些外围环节。单线程模型的优势在于确定性,但确定性只对正确使用它的人有效。


















