必须改net.core.somaxconn,否则高并发下全连接队列溢出导致静默丢连接,客户端报connection refused或超时;默认值128/511远低于实际需求,需设为65535并同步调优redis的tcp-backlog和ulimit -n。

net.core.somaxconn 为什么必须改,不改就丢连接
Redis主线程调用 accept() 处理已完成三次握手的连接,但建连速度可能远超处理速度。这些待 accept 的连接排队进“全连接队列”,队列长度由 net.core.somaxconn 控制。默认值通常是 128 或 511,高并发下极易溢出——溢出后内核静默丢弃新连接,不发 RST、不重传 SYN-ACK,客户端只看到 Connection refused 或超时。
验证是否已溢出:netstat -s | grep "listen overflows" 输出非零(如 listen overflows: 42)就是铁证。临时生效:sudo sysctl -w net.core.somaxconn=65535;持久化需写入 /etc/sysctl.d/99-redis.conf 并执行 sudo sysctl --system。
注意:ss -lnt | grep :6379 中 Send-Q 列必须显示 65535(不是 128 或 511),否则说明没真正生效。
tcp-backlog 和 ulimit -n 必须跟 somaxconn 对齐
net.core.somaxconn 只是内核侧上限,Redis 自身也得配得上:6.2+ 版本在 redis.conf 中设 tcp-backlog 65535;老版本需确认 glibc 支持自动提升,否则仍卡在 511。同时,进程能打开的文件描述符数(即连接数上限)由 ulimit -n 控制,必须 ≥ tcp-backlog 值。
常见遗漏点:
- 只改了
sysctl没改redis.conf的tcp-backlog,Redis 启动时会 fallback 到系统默认值 - 改了
ulimit -n但没对 Redis 进程生效(比如用 systemd 启动,需在redis.service中加LimitNOFILE=65535) - 重启 Redis 前没 reload sysctl,导致新参数未加载
要不要碰 net.ipv4.tcp_max_syn_backlog
这个参数管的是“半连接队列”(SYN_RCVD 状态),只在遭遇 SYN Flood 攻击或极端短连接风暴时才可能成为瓶颈。正常 Redis 高并发场景下,它几乎不会溢出。
除非压测时看到 netstat -s | grep "SYNs to LISTEN sockets dropped" 非零,否则别动它。盲目调大反而增加内存开销,且对 Redis 无实际收益。生产环境真正该盯紧的只有 net.core.somaxconn、tcp-backlog、ulimit -n 三者的匹配关系。
其他关键配套参数不能漏
单调 somaxconn 不够,还得补全支撑链:
-
net.core.netdev_max_backlog = 100000:网卡接收队列,防止高吞吐下丢包 -
vm.overcommit_memory = 1:避免 fork() 时因内存检查失败导致 bgsave/RDB 失败 -
net.ipv4.tcp_tw_reuse = 1:允许复用 TIME_WAIT 状态 socket,缓解短连接压力(tcp_tw_recycle已废弃,禁用) -
echo never > /sys/kernel/mm/transparent_hugepage/enabled:禁用 THP,否则会导致延迟毛刺
所有参数改完必须执行 sysctl -p 或 sysctl --system 生效,且 Redis 必须重启才能读取新的 tcp-backlog 值——这点最容易被忽略,改完内核参数却忘了重启 Redis,等于白调。











