SO_BACKLOG控制已完成三次握手但未accept的连接队列长度,调太小(如<100)会导致listen overflows、accept变慢、连接超时;生产建议设1024~4096并同步调高somaxconn。

SO_BACKLOG 是什么,为什么调小反而卡住连接
SO_BACKLOG 控制的是内核里「已完成三次握手但尚未被应用 accept() 的连接队列」长度。它不是 Netty 配置项,而是 ServerBootstrap.option(ChannelOption.SO_BACKLOG, ...) 设置的底层 socket 参数。Linux 内核实际生效值受 /proc/sys/net/core/somaxconn 限制——如果设成 1024,但 somaxconn 是 128,那真正起作用的还是 128。
常见错误现象:accept() 调用变慢、新连接大量超时、netstat -s | grep "listen overflows" 显示溢出计数上涨。
- 生产环境建议设为 1024~4096,同时确保
somaxconn ≥ 你设的值 - Netty 4.1+ 默认是 128,不够用;低于 100 会明显拖慢高并发建连
- 注意:这个值只影响 TCP 连接建立阶段,和后续 IO 吞吐无直接关系
TCP_NODELAY 关闭 Nagle 算法的真实代价
TCP_NODELAY 是一个 socket 选项,启用后禁用 Nagle 算法,让小包不等待 ACK 就立即发出。Netty 中通过 childOption(ChannelOption.TCP_NODELAY, true) 设置。它对延迟敏感型服务(如实时消息、RPC)几乎必开,但不是“开了就一定快”。
容易踩的坑:TCP_NODELAY = true 后,如果业务层频繁 write() 小数据(比如每次只发 20 字节),会导致大量 40~60 字节的 TCP 包,引发网卡中断风暴、CPU 软中断飙升、吞吐反而下降。
- 必须配合业务写法:攒批发送(用
CompositeByteBuf或writeAndFlush()批量落盘) - HTTP/2、gRPC 等协议栈内部已做帧合并,开
TCP_NODELAY是安全的;纯自定义二进制协议需确认序列化是否分块 - 某些云厂商网卡驱动对小包处理差,实测开启后吞吐降 15%~20%,建议压测对比
Netty 的 writeBufferHighWaterMark 和低水位联动机制
Netty 不靠系统参数,而是用 writeBufferHighWaterMark 和 writeBufferLowWaterMark 控制 ChannelOutboundBuffer 的缓冲水位。当写入缓冲区超过高水位,channel.isWritable() 变 false,且触发 channelWritabilityChanged 事件——这是防止 OOM 的关键防线,但很多人忽略它。
典型误用:业务线程无脑 channel.write(msg),不检查 isWritable(),导致缓冲区持续膨胀,GC 压力大、延迟毛刺频发。
- 默认高水位是 64 KB,低水位是 32 KB;突发流量下极易突破,建议根据单连接平均消息大小调整(比如平均 1KB 消息,可设为 128KB / 64KB)
- 必须在
channelWritabilityChanged里做节流:暂停投递、切到队列暂存、或丢弃非关键消息 - 注意:这个水位只管 Netty 自己的 outbound buffer,不管 OS 的 socket send buffer,后者由
SO_SNDBUF控制
SO_RCVBUF 和 SO_SNDBUF 在 Netty 里的实际意义很有限
SO_RCVBUF 和 SO_SNDBUF 分别控制内核接收/发送缓冲区大小。Netty 允许通过 option() 或 childOption() 设置,但现代 Linux(3.10+)默认开启 autotuning,手动设死反而可能降低吞吐。
真实影响场景极少:只有在极低延迟要求(微秒级)、且网络 RTT 极不稳定时,固定 SO_RCVBUF 才可能减少接收窗口震荡。其他情况基本白配。
- 设太小(如 64KB):TCP 窗口缩窄,长肥管道(BDP 大)下吞吐受限
- 设太大(如 16MB):内存浪费,且内核 autotune 会忽略该值,实际仍按算法动态调整
- Netty 官方文档也明确说:“通常不需要显式设置”,留默认即可
真正要调的,是 SO_BACKLOG 和 TCP_NODELAY,其余 socket 参数多数时候只是掩盖了业务层的问题。










