TCP代理内存占用过高主因是缓冲区配置与流量不匹配,需按BDP估算合理设tcp_rmem/wmem上限(如8MB),同步收紧应用层缓冲、关闭tcp_moderate_rcvbuf,并监控skbuff缓存与丢包指标。

TCP代理过程中内存占用过高,核心原因往往是缓冲区配置与实际流量不匹配——系统为每个连接预分配了过大的内核缓冲区,而大量连接长期空闲或低速传输时,这些缓冲区持续驻留内存,导致整体内存水位飙升。关键不是盲目增大,而是让缓冲区“够用且及时释放”。
识别真实瓶颈:先看是哪个缓冲区在吃内存
代理类服务(如3proxy、Envoy、Higress)的内存压力通常来自三类缓冲区:
-
内核TCP缓冲区:由
tcp_rmem/tcp_wmem控制,每个连接最多占用其最大值; -
应用层写缓冲区:如Netty的
pulsarChannelWriteBuffer或Envoy的per_connection_buffer_limit_bytes,数据在用户态暂存; - 连接元数据开销:每个socket需约64KB–128KB内核缓冲区内存 + 文件描述符 + socket结构体。
执行 ss -i 查看各连接的 rcv_ssthresh、wscale 和当前 rcv_space/snd_space,比对是否普遍接近 tcp_rmem 最大值;再用 cat /proc/net/sockstat 看 sockets: used 和 TCP: inuse 是否远高于活跃连接数——若“inuse”高但“mem”不高,说明是连接堆积而非缓冲区过大。
调优 TCP 内核缓冲区:设合理上限,禁用过度自动扩缩
默认 tcp_rmem = "4096 87380 4194304"(4MB上限)在万级并发代理中极易引发OOM。应按带宽延迟积(BDP)估算后保守设定:
- 计算公式:
BDP = 带宽(bps) × RTT(s);例如 1Gbps × 50ms = 6.25MB → 缓冲区上限建议 ≤ 8MB; - 生产推荐值(10G网卡+中等延迟):
net.ipv4.tcp_rmem = 4096 131072 8388608(8MB),net.ipv4.tcp_wmem = 4096 65536 8388608; - 必须同步调整硬限制:
net.core.rmem_max = 8388608、net.core.wmem_max = 8388608,否则应用层setsockopt(SO_RCVBUF)会被截断; - 关闭激进自动调优:
net.ipv4.tcp_moderate_rcvbuf = 0,防止内核在突发流量后长时间维持高缓冲区不释放。
收紧应用层缓冲与连接生命周期
代理软件自身缓冲和连接管理不当,会放大内核层问题:
-
3proxy:在配置中显式限制单连接资源,例如
proxy -p8080 -o -s0 -t153060180(-s0禁用 splice 减少零拷贝内存驻留,-t缩短超时链); -
Higress/Envoy:设置
per_connection_buffer_limit_bytes: 65536(64KB),并启用tcp_backlog_size: 4096防止连接排队过长; -
Pulsar Broker:降低
pulsarChannelWriteBufferHighWaterMark至 262144(256KB),避免Netty因水位触发大块内存预分配; - 所有代理统一动作:将
net.core.somaxconn和net.ipv4.tcp_max_syn_backlog设为 4096–8192,避免SYN队列堆积拖慢连接释放。
验证与持续监控要点
调优后不验证等于没调。重点关注三项指标:
- 内存:用
slabtop -o | grep skbuff观察skbuff_head_cache和skbuff_fclone_cache占用是否下降; - 丢包:检查
netstat -s | grep "pruned\|Ofo",确认 “socket buffer overrun” 计数归零; - 连接健康:通过
ss -s中memory: used与sockets: used比值,理想应
记住:代理场景下,小而快的缓冲区 + 短连接生命周期 + 明确的超时控制,比大缓冲区更能压低内存峰值。调参不是一步到位,而是根据 ss -i 和 /proc/net/sockstat 的反馈反复微调。

















