10G(82599EB) 网卡测试优化(kernel)

kernel 方面的优化,这里面大部分都会涉及到 tcp stack。
首先需要了解一个概念,BDP(bandwidth delay product),即两端的带宽跟 RTT 的乘积,比如,我们的 10G 网络,正常情况在 9.4G 到 9.9G 浮动,按照最差的 9.4 来算,RTT 正常的在 0.2ms 左右,他们的 BDP=9.4×10^6kbit/sx0.2×10^-3s=1.88×10^3kbit=235kByte
下面两张图截取自《TCP Implementation in Linux: A Brief Tutorial》,大致的描绘了包从进到出涉及到的几个层面(Device driver, kernel space, User space) 

对于一个包来说,从 IP 层到 TCP 层,经过状态机,最终进入到 TCP recv buffer 通过 read() 转入到 User space(app)。如果这个 buffer(net.ipv4.tcp_rmem) 比 BDP 小的话,其 throughput 会降低。对应的,对于发包来说,从 user space 的 app 通过 write() 调用到 kernel space 进入 TCP send buffer(net.ipv4.tcp_wmem, per socket)。

net.core.netdev_max_backlog 这个决定了一个设备里面等待 cpu 处理(rx)的的最大 queue 数量,如果新接受到的包超过该值,则会被 discarded,这个发生在 ip layer 到 tcp layer 过程中。

注意: core.rmem_max 会覆盖 ipv4.tcp_rmem,core.wmem_max 会覆盖 ipv4.tcp_wmem,上面的几个的单位都是 bytes。ipv4.tcp_mem 是以 pages 为单位而非 bytes。net.core.rmem_default,rmem_default 不应该大于 rmem_max。

上面的四个都是发生在 socket 层面,只对 end-to-end 有效,如果是 bridge/router 则无效。而 netdev_max_backlog 会同时影响端到端以及路由交换的机器。

对于整个网络而言,在接受方向有两个主要的 queue: NIC 的 rx buffer 以及 socket queue。前者在《10G(82599EB) 测试优化(ethtool)》提到过,后者则是上面提到的。两者都需要经过实践,才能得到一个比较满意的效果。

还有个就是 tcp_congestion_control/tcp_available_congestion_control。目前主流的 OS 会提供 cubic reno 这两个,一致偏向使用 CUBIC,2.6.19 之后使用该算法,包括目前的 3.0.0 等,也就是目前主流的稳定的内核(2.6.18, 2.6.32)使用的都是该算法。这个没得说,目前综合性能最好的。当然,如果你是想访问国外的,比如科学上网之类的, 当然使用 hybla,加载,开启:
# modprobe tcp_hybla
# echo hybla > /proc/sys/net/ipv4/tcp_congestion_control

除了上面几个重要的之外,还有几个需要注意的。

1. tcp_timstamps 会在 TCP header 额外的增加 12bytes,10G 网络可以关闭。
2. 对于 tcp_sack 来说,对于 WAN 的效果可能会比较好,但是会增加 CPU util,开不开对 LAN 影响不是很大,都 10G 的 LAN 了,可以肯定的说不会出现丢包这种网络很糟糕的情况
3. tcp_low_latency higher throughput > low latency,这个目前主流的系统默认都是 0。
4. tcp_mtu_probing 对于开启了 jumbo frames 的机器来说,需要开启,默认是 0。这个主要是为了弥补使用 PMTUD 调整 MTU 出现的一些问题。如果置为 2,则会牵扯到 tcp_base_mss,默认为 512,即使用 tcp_base_mss 作为起始的 MSS 值。与之相关的还有 ip_no_pmtu_disc 这个参数,默认为 0,即依然会优先使用传统的 PMTUD,只有当遇到 blackhole 的时候才会使用 PLPMTUD(Packetization Layer Path MTU Discovery),也就是上面提到的技术。 另外,像 fs.file-max, net.ipv4.ip_local_port_range 这类通用性的就不在这里说了,记得修改。

下面是一个范例:
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 600000
net.core.wmem_default = 600000
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_mem = 10000000 10000000 10000000
net.core.netdev_max_backlog = 600000
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_sack = 0
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_base_mss = 512
net.ipv4.ip_no_pmtu_disc = 0
net.ipv4.tcp_congestion_control = cubic