首页/系统/Linux 内核与性能调优速查/net.ipv4.tcp_notsent_lowat 发送缓冲水位
网络栈调优98 条

net.ipv4.tcp_notsent_lowat 发送缓冲水位

控制发送队列中未发送字节的阈值:低于阈值才通知应用可写,用于抑制缓冲区膨胀(bufferbloat)与控制内存占用。

参数是干什么的

net.ipv4.tcp_notsent_lowat 设定发送队列中未发送字节数的阈值:只有当未发送数据低于该值时,内核才向应用报告「可写」(select/poll/epoll 返回可写)。默认 -1 表示不限制。它的用途是抑制缓冲膨胀——限制内核里排队等待发送的数据量,让应用跟随网络的实际发送速度推进,从而降低延迟,代价是在大流量场景下可能限制吞吐。

基本信息

系统参数net.ipv4.tcp_notsent_lowat(默认 -1,不限制)
应用侧选项TCP_NOTSENT_LOWAT,可按单个连接设置
观测方式ss -ti 输出中的 notsent 字段
相关参数net.ipv4.tcp_wmem(发送缓冲的自动调优范围)
适用平台Linux(需要内核支持该 sysctl)
影响面改变的是「何时通知应用可写」,不改变拥塞控制

典型使用场景

  • 延迟敏感的代理、网关与推送服务:限制内核排队数据以压低响应时间
  • 排查「应用写很快、客户端收很慢」的缓冲膨胀问题
  • 与 SO_SNDBUF 配合控制进程的内存占用上限
  • 按连接精细控制:只对延迟敏感的业务连接设置该选项
  • 长尾延迟分析时观察 notsent 是否长期偏高,判断排队位置

查看与设置

查看与设置
sysctl net.ipv4.tcp_notsent_lowat  # 查看全局值,-1 表示不限制
ss -tin dst :8080  # 关注 notsent: 与 skmem 中的发送排队量
printf 'net.ipv4.tcp_notsent_lowat = 131072\n' > /etc/sysctl.d/90-notsent.conf  # 全局设为 128KB
sysctl --system  # 重新加载并复核
# 应用侧按连接设置(C 语言示意):
# int val = 65536; setsockopt(fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &val, sizeof(val));
sysctl net.ipv4.tcp_wmem  # 同时确认发送缓冲范围,两者需要配合

观测项读法

观测项含义判读要点
notsent该连接未发送的字节数长期偏高说明数据积在内核里
skmem 的 tb/rb发送与接收缓冲上限确认是否被系统上限截断
skmem 的 t/r当前收发排队字节数与 notsent 一起判断排队位置
cwnd / rtt拥塞窗口与往返时间用于判断发送受限是否来自网络
该参数只影响「应用何时被通知可写」,不能替代拥塞控制:如果对端读取慢或网络本身受限,未发送数据仍会积压,只是应用会更早被阻塞而不是把数据推进缓冲。
阈值设得过小会限制吞吐:发送方频繁被阻塞、带宽利用下降,在大文件传输或高吞吐代理上尤其明显。全局调整前先确认应用是否已按连接设置,并以压测数据为依据。

易错点

  • 阈值设得过小限制吞吐:大流量场景下带宽利用率下降,得不偿失
  • 直接做全局调整:会同时影响不敏感的业务,优先考虑按连接设置
  • 只看参数不看 notsent 实际值:无法确认改动是否产生了预期效果
  • 以为它能解决对端慢的问题:对端消费慢或网络受限时,限制排队只是把压力移回应用
  • 忽略与 tcp_wmem 的关系:发送缓冲上限本身的量级决定了该阈值的实际意义

数据来源与参考

  • Linux 内核 Documentation/networking/
  • man-pages tcp(7)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌