Linux网络相关参数
Contents
SACK / ACK
# 是否允许 TCP 发送 "duplicate" SACKs
net.ipv4.tcp_dsack = 1
net.ipv4.tcp_sack = 1
# 限制每秒发送 Challenge ACK 个数.
net.ipv4.tcp_challenge_ack_limit = 1000
# 限制响应现有传入 TCP 数据包但由于以下原因而无效的重复 ACK 的最大速率
# - out-of-window sequence numbe
# - out-of-window acknowledgment number
# - PAWS (Protection Against Wrapped Sequence numbers) check failure
# 单位为 ms. 换句话说, 这限制了发送重复 ack 的最小时间间隔.
net.ipv4.tcp_invalid_ratelimit = 500
window/buffer
# socket 读写缓冲区相关配置. 这个是所有协议中 每个 socket 的默认以及最大大小. 单位字节.
# 注意, 只有 default 值可以被覆盖, max 的值是硬性的.
net.core.rmem_default = 212992
net.core.rmem_max = 16777216
net.core.wmem_default = 212992
net.core.wmem_max = 16777216
# 是否开启自动调优接收缓冲区大小
net.ipv4.tcp_moderate_rcvbuf = 1
# [low, pressure, high] 系统总 TCP 分配内存. 当内存超过 pressure 水位时, 就是触发自动调优.
# pressure 在内存降到 low 的时候就会退出
# 注意, 这些单位是 system page (通常是 4KB/页)
net.ipv4.tcp_mem = 384462 512617 768924
# 这些是用于每一个 TCP 连接的. 这个单位是 字节.
# 注意, min 并不是用于 SO_RCVBUF 参数绑定声明的.
# 这里的 default 的值, 会覆盖 net.core.rmem_default / net.core.wmem_default 的值. 如果想增大 receive buffer 的大小, 可以增加 tcp_rmem 的 default 的值大小. 注意, 为了开启大的 TCP windows, net.ipv4.tcp_window_scaling 必须要开启(默认是开启的)
# 注意, max 这个值并不会覆盖 net.core.rmem_max / net.core.wmem_max 的值.
# 自动调优时使用的值, 分别为 min, default, max
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 是否开启 window 缩放
net.ipv4.tcp_window_scaling = 1
# man tcp , 然后搜索 adv
# 参考 https://unix.stackexchange.com/questions/94770/what-does-net-ipv4-tcp-app-win-do
net.ipv4.tcp_adv_win_scale = 2
# 保留多少字节 tcp window 用于缓冲开销.
# 保留 window 中的 max(window/2^tcp_app_win, mss) 字节用于应用程序 buffer. 0 表示不保留.
net.ipv4.tcp_app_win = 31
# 每个 TCP Socket 的 TCP Small Queue 的限制.
## 它限制了在 qdisc 或 device 中的字节数, 以减少人为 RTT/cwnd 和 减少 bufferbloat
## qdisc 是一个调度器. 每个输出设备都需要一种调度, 默认的调度器是 FIFO.
## bufferbloat : buffer 溢出, 从而导致高延时.
net.ipv4.tcp_limit_output_bytes = 262144
# 跟踪最小 RTT 的最小窗口过虑器中的窗口长度
net.ipv4.tcp_min_rtt_wlen = 300
# 由于这个选项, TCP socket 可以控制 write queue 中的总未发送字节数.
net.ipv4.tcp_notsent_lowat = -1
# 如果设置, 假设没有收到 window 缩放选项意味着远程 TCP 已损坏, 并将 window 缩放视为 signed 的数量
# 如果没有设置, 即使我们没有收到 window 缩放选项, 也假设远程 TCP 没损坏
net.ipv4.tcp_workaround_signed_windows = 0
如果 tcp_adv_win_scale > 0
, 则公式为 bytes / (2^tcp_adv_win_scale)
. 如果 tcp_adv_win_scale <=0
,则公式为 bytes - bytes/2^(-tcp_adv_win_scale)
Socket 的 receive buffer 是由应用程序与内核共享的. TCP 维护部分缓冲区作为 TCP window
, 这是作为通告另一端的 window 大小. 剩下的部分用于应用程序的缓冲区, 用于隔离调度与应用程序延时. tcp_adv_win_scale
默认为 2, 表示用于应用程序的缓冲区是总数的 1⁄4.
那理论上, 通告的 win 大小为 (tcp_adv_win_scale > 0
)
$$
通告 win = bytes * (1-\frac{1}{2^{tcp_adv_win_scale}})
$$
我的理解是
| A | (A 是 receive buffer 总大小)
| adv win | application | (由 `tcp_adv_win_scale` 控制比例)
| adv win | application |`tcp_app_win` | (由 `tcp_app_win` 控制app的保留大小)
https://ubuntuplace.info/questions/336323/what-does-net-ipv4-tcp-app-win-do
一个比较合理的设置 rcv buffer 的大小为 =
带宽 * RTT
keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
TIME WAIT
# 系统允许的最大的 TIME_WAIT 状态的 socket 数量
net.ipv4.tcp_max_tw_buckets = 5000
# 是否快速回收 TIME WAIT socket. 通常不要启用.
net.ipv4.tcp_tw_recycle = 0
# 是否重用 TIME WAIT socket. 这只是对一条新的 outgoing 的连接才考虑复用. 对于 incoming 的连接没效果.
net.ipv4.tcp_tw_reuse = 0
# TIME WAIT 等待多久后就完全关闭. 单位秒
net.ipv4.tcp_fin_timeout = 60
# 当禁用时, 如果在 TIME_WAIT 状态时收到一个 RST, 则立即关闭这个 socket, 而不用等 TIME_WAIT 结束.
net.ipv4.tcp_rfc1337 = 0
SYN
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_syn_retries = 6
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syncookies = 1
RST
# 当系统处理不过来时, 返回给客户端 RST. (没特殊情况的话, 不要开启)
# 因为返回 RST, 客户端可能认为服务器不可达, 导致不会重试. 而不是认为服务器繁忙.
net.ipv4.tcp_abort_on_overflow = 0
PMTU
net.ipv4.tcp_mtu_probing = 0
# 如果上面 MTU probing 的参数开启, 则这个值就是初始的 MSS 值
net.ipv4.tcp_base_mss = 1024
# 控制多久开始重新探测 TCP Packetization-Layer Path MTU Discovery. 单位秒
net.ipv4.tcp_probe_interval = 600
# 控制当进行 TCP Packetization-Layer Path MTU Discovery 停止条件. 即搜索范围的宽度. 以字节为单位.
##
net.ipv4.tcp_probe_threshold = 8
TCP metrics
# 是否关闭 tcp 指标收集. 0: 表示收集. 1: 不收集.
# 默认为 0, 收集.
net.ipv4.tcp_no_metrics_save = 0
拥塞相关
拥塞窗口 cwnd 衡量的是发送方的速率大小
通告窗口(接收窗口) rwnd 衡量的是接收方处理数据的能力大小.
net.ipv4.tcp_allowed_congestion_control = cubic reno
net.ipv4.tcp_available_congestion_control = cubic reno
net.ipv4.tcp_congestion_control = cubic
# 一种拥塞算法. 它是基于 SACK 的. 只有在 SACK 开启的前提下才行.
net.ipv4.tcp_fack = 1
# ECN : Explicit Congestion Notification . 显式拥塞通知. 只有两端都支持才起作用.
# 0 为禁用. 1 当接收ECN 时开启, 并且尝试也发送一个 ECN 出去. 2: 与 1 相似, 但不发送一个 ECN 出去.
net.ipv4.tcp_ecn = 2
# 当内核检测到一个错误有 ECN 行为, 则返回到非 ECN. 当上面的 tcp_ecn 开启的时候才起作用.
net.ipv4.tcp_ecn_fallback = 1
# 当前速率为 (current_rate = cwnd * mss / srtt).
## 当 TCP 处于拥塞避免阶段是, tcp_pacing_ca_ratio 用于保守探测更大的吞吐量
net.ipv4.tcp_pacing_ca_ratio = 120
## 当 TCP 处于慢启动, tcp_pacing_ss_ratio 用于探测更大的速率, 假设 cwnd 可以每隔一个 RTT 加倍.
net.ipv4.tcp_pacing_ss_ratio = 200
# 当开启, 则提供 RFC 2861 的行为以及在一个 idle 时间(即一个 RTO, 重传超时)后拥塞窗口超时.
## 当禁用时, 拥塞窗口在一个 idle 时间后不会超时
net.ipv4.tcp_slow_start_after_idle = 1
timestamp
# tcp 选项中的 timestamp 是否开启.(通常建议开启)
net.ipv4.tcp_timestamps = 1
CORK/NODELAY
# 内核自动尝试尽可能地合并 small write, 以减少发送包的总数.
# 也可以在应用程序中, 显式设置 TCP_CORK
net.ipv4.tcp_autocorking = 1
# TCP_NODELAY 会被 TCP_CORK 覆盖.
# 设置 TCP_NODELAY 会显式地 flush write 的数据, 尽管 TCP_CORK 已设置.
超时/重传/恢复
net.ipv4.tcp_early_retrans = 3
# Forward RTO-Recovery (F-RTO)
# 它是一个加强版的 TCP 重传超时的 recovery 算法. 0 表示禁用. 非 0 表示开启. 它是 sender only, 不要求对方也支持.
net.ipv4.tcp_frto = 2
# 实验性的丢失恢复特性.
## RACK: 0x1 enables the RACK loss detection for fast detection of lost
## retransmissions and tail drops. It also subsumes and disables
## RFC6675 recovery for SACK connections.
## RACK: 0x2 makes RACK's reordering window static (min_rtt/4).
## RACK: 0x4 disables RACK's DUPACK threshold heuristic
net.ipv4.tcp_recovery = 1
# TCP 在一个已正常建立的连接中尝试重传的次数. 参考 https://emacsist.github.io/2019/07/11/tcp-ip协议笔记/
## TCP 拥有两个阈值来决定如何重传同一个报文段.
## R1 表示 TCP 在向 IP 传递消极建议(如重新评估当前 IP 路径)前, 愿意尝试重传的次烽(或等待时间).
## R2 (大于 R1)指示 TCP 应放弃当前连接的时机.
## R1 和 R2 应分别至少设为 3 次重传和 100 秒.
## 对数据段, 分别对应系统配置变量 net.ipv4.tcp_retries1 (默认为 3), 以及 net.ipv4.tcp_retries2(默认为 15, 对应约 13 ~ 30 分钟, 根据具体连接的 RTO 而定) . 值为重传次数, 而不是时间.
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
# 在重传中, 尝试发送完整大小的数据包
net.ipv4.tcp_retrans_collapse = 1
TSO
# 每个 TSO frame 的最小 segment 数.
## TSO(TCP Segment Offload)是一种利用网卡的少量处理能力,降低CPU发送数据包负载的技术,需要网卡硬件及驱动的支持
## 可以用命令 ethtool -k eth0 来查看是否支持 TSO 功能.
net.ipv4.tcp_min_tso_segs = 2
# 允许控制 拥塞窗口的百分比可以被一个 TSO frame 消费
net.ipv4.tcp_tso_win_divisor = 3
fast open
# 是否在 SYN 包中开启 TCP Fast Open(RFC 7413) 来发送和接收数据.
# The values (bitmap) are
# 0x1: (client) enables sending data in the opening SYN on the client.
# 0x2: (server) enables the server support, i.e., allowing data in
# a SYN packet to be accepted and passed to the
# application before 3-way handshake finishes.
# 0x4: (client) send data in the opening SYN regardless of cookie
# availability and without a cookie option.
# 0x200: (server) accept data-in-SYN w/o any cookie option present.
# 0x400: (server) enable all listeners to support Fast Open by
# default without explicit TCP_FASTOPEN socket option.
net.ipv4.tcp_fastopen = 1
net.ipv4.tcp_fastopen_key = e3fb03ef-c56d92c4-01a94033-6ca6fd72
未分类
net.ipv4.tcp_fwmark_accept = 0
net.ipv4.tcp_thin_dupack = 0
net.ipv4.tcp_thin_linear_timeouts = 0
orphan
# 没附加到任何用户的文件句柄(即孤儿 socket), 只被系统持有的最大 TCP socket 数
## 只是为了防止简单的 Dos 攻击. 不要依赖它或人为地调低这个值.
## 注意, 每个 orphan 会吃掉约 64K 的物理内存.
net.ipv4.tcp_max_orphans = 65536
# 尝试探测一条连接的另一端是否已关闭的最大尝试次数.
net.ipv4.tcp_orphan_retries = 0
reorder 重排序
# 初始化一条 TCP stream 的重排序级别. 即无序包的容错率.
net.ipv4.tcp_reordering = 3
# 最大重排序级别
net.ipv4.tcp_max_reordering = 300
latency
# 内核 TCP 栈决策倾向. 默认是吞吐优先. 如果开启这个, 则表示低延时优先.
# 注, 最新版的这个选项已经被移除(2017 Jul 30). https://github.com/torvalds/linux/commit/b6690b14386698ce2c19309abad3f17656bdfaea?diff=split
net.ipv4.tcp_low_latency = 0
urgent pinter 紧急指针
# 极少使用遇到, 还不是很理解~
net.ipv4.tcp_stdurg = 0
Linux 中的 Socket 相关参数
TCP_CONGESTION
string 类型. 指定socket 的拥塞控制算法.
非特权进程, 只允许在 tcp_allowed_congestion_control
中允许的算法.
特权进程, 则可以在 tcp_available_congestion_control
中任一选择.
TCP_CORK
如果设置, 则不发送部分帧.(即小于 MSS 的帧). 对于调用 sendfile
或吞吐量优化用处比较大.
如果设置的话, 则达到以下两个条件之一才会发送帧:
- 达到一个 MSS 大小的帧
- 200 ms
在 2.5.71
及之后, 才可以与 TCP_NODELAY
结合一起使用.
TCP_DEFER_ACCEPT
允许一个监听器只在数据到达的时候才唤醒.
TCP_INFO
用于收集该 socket 的信息.内核会返回一个 tcp_info
的结构体
TCP_KEEPCNT
在销毁该连接之前允许的最大 keepalive 探测数.
TCP_KEEPIDLE
单位秒. 在发送 keepalive 探测之前空闲的时间.
TCP_KEEPINTVL
单位秒. 每次发送 keepalive 探测间隔时间
TCP_LINGER2
orphaned
的 FIN_WAIT2
状态的存活时间. 用于覆盖系统级别设置的 tcp_fin_timeout
TCP_MAXSEG
设置发送数据的 MSS. 如果超出 MTU 的话, 是则是无效的.
TCP_NODELAY
如果为 true 的话, 则禁用 Nagle 算法. 这意味着 segment 会尽快发送, 即使它只有一点数据.
如果为 false 的话, 则缓存一些数据, 以减少发送小数据的频率(会导致网络的使用率低).
它会被 TCP_CORK
覆盖. 但是, 显式设置该参数, 会刷新发送的数据, 即使 TCP_CORK
有设置.
TCP_QUICKACK
是否开启快速 ACK. 快速 ACK 模式中, ack 会被立即发送, 而不是延迟.
TCP_SYNCNT
设置 SNC
重传次数. 不能超过 255.
TCP_USER_TIMEOUT
>=0
的值. 当大于 0 时, 指定连接中已发送但还没 ack 的最大的时间(单位 ms
) , 超过的话则关闭连接.
为 0 时, 则使用系统默认.
TCP_WINDOW_CLAMP
绑定通告的 window
大小为该值. 内核会在它与 SOCK_MIN_RCVBUF/2
之间选一个最大值.
SOCK_MIN_RCVBUF
是 256 字节
if ((val * 2) < SOCK_MIN_RCVBUF)
sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
网络命令
ss
http://man7.org/linux/man-pages/man8/ss.8.html
Recv-Q : Established 状态的表示用户应用还没有复制的数据
Listening 状态的表示当前 syn backlog
Send-Q : Established 状态的表示还没有被对方 ACK 的字节数
Listening 状态的表示最大的 syn backlog 数.(例如 nginx 中的 listen backlog=65535). 这里就会显示 65535
常用参数
-a
: 列出所有监听和非监听(对于 TCP 则是 ESTABLISHED 状态) 的所有 socket-l
: 只列出监听状态的 socket(默认情况下不显示这种状态)-o
: 表示 timer 信息. 格式为timer:(<timer_name>,<expire_time>,<retrans>)
timer_name
- on : means one of these timers: TCP retrans timer, TCP early retrans timer and tail loss probe timer
- keepalive
- timewait
- persist : zero window probe timer
- unknown
expire_time
: 还有久过期retrans
: 重传次数
-e
: 显示详细socket信息. 格式为uid:<uid_number> ino:<inode_number> sk:<cookie>
- uid : 表示该 socket 属于哪个用户. 可以通过命令, 根据 uid 显示用户名
id -nu 用户ID
- inode : socket 的 inode 数
- cookie : socket 的 uuid
- uid : 表示该 socket 属于哪个用户. 可以通过命令, 根据 uid 显示用户名
-m
: 显示 socket 内存使用. 输出的格式为skmem:(r<rmem_alloc>,rb<rcv_buf>,t<wmem_alloc>,tb<snd_buf>,f<fwd_alloc>,w<wmem_queued>,o<opt_mem>,bl<back_log>)
rmem_alloc
: 已分配的 receive 内存rcv_buf
: 总可的分配 receive 内存wmem_alloc
: 已分配的 send 内存 (已发送数据到 layer 3)snd_buf
: 总的可分配 send 内存fwd_alloc
: socket 用于内存分配的 cache, 但还未用于 receive 或 send . 如果需要内存, 则优先从这里分配.wmem_queued
: 已分配的用于 send 的内存队列大小(还没有发送到 layer 3)ropt_mem
: 用于存储 socket 选项的内存.back_log
: 用于 socket backlog 队列内存.
-p
: 显示进程使用中的 socket-i
: 显示 TCP 内部信息. 格式例子:cubic wscale:7,9 rto:220 rtt:16.331/16.891 ato:68 mss:1448 cwnd:10 ssthresh:7 bytes_acked:7419 bytes_received:67286 segs_out:75 segs_in:125 send 7.1Mbps lastsnd:3636 lastrcv:3640 lastack:3636 pacing_rate 8.5Mbps rcv_rtt:36 rcv_space:28960
- cubic : 表示拥塞算法
- wscale : 绽放窗口因子. 分别是
snd_wscale,rcv_wscale
- rto : 重传超时值, 单位 ms
- rtt : 单位 ms
- ato : ack time out
- mss : 最大 segment 大小, 字节
- cwnd : 拥塞窗口大小
- ssthresh : 慢启动阈值
- lastsnd : 最后一次发送 packet 以来的时间, 单位 ms
- lastrcv : 最后一次接收 packet 以来的时间, 单位 ms
- lastack : 最后一次 ack 以来的时间, 单位 ms
- pacing_rate : 发送速率
- rcv_rtt : the time to receive one full window . https://www.spinics.net/lists/netdev/msg295886.html
- rcv_space : 一个用于帮助系统自动调优 rec buf 的变量值
-s
: 显示统计信息-4
: 只显示 ipv4-t
: 显示 TCP socket