介绍
有时,人们正在寻找能够带来高吞吐量和低延迟的sysctl 货物崇拜(cargo cult)值,而无需进行权衡,并且这种值在任何情况下都能工作。这是不现实的,尽管我们可以说新的内核版本在默认情况下已经进行了很好的调优。事实上,如果乱用默认值,可能会影响性能。
这个简短的教程展示了一些最常用和引用最多的sysctl/网络参数在Linux网络流中的位置,它深受Linux网络堆栈的插图指南和Marek Majkowski的许多帖子的启发。
请随意发送更正和建议!:)
Linux网络队列概述
将sysctl变量装入Linux网络流中
进来了,数据来了
- 数据包到达网卡(NIC)
- NIC将验证 MAC (如果不是在混杂模式)和 FCS,并决定放弃或继续
- NIC将DMA数据包到RAM中,在一个由驱动程序预先准备(映射)的区域内
- NIC将在接收环形缓冲(ring buffer)队列
rx
对数据包的引用排队,直到rx-usecs
超时或达到rx-frames
个数 - NIC将提出一个硬中断 (hard IRQ)
- CPU将运行中断处理程序(IRQ handler), 即运行驱动程序代码
- 驱动程序将安排一次NAPI调用 (schedule a NAPI),清除硬中断并返回
- 驱动程序引发一个软中断 (soft IRQ) (具体讲是 NET_RX_SOFTIRQ)
- NAPI将从接收环缓冲区轮询数据,直到
netdev_budget_usecs
超时或达到netdev_budget
和dev_weight
个包 - Linux也将分配内存给 sk_buff
- Linux填充元数据:协议,接口,setmacheader (设置 MAC 头),移除以太网头
- Linux将把skb传递给内核堆栈 (netif_receive_skb)
- 它将设置网络报头,克隆 skb 窃听点(taps 即 tcpdump),并将其传递给tc入口
- 数据包通过 default_qdisc 定义的算法处理到 qdisc 大小的
netdev_max_backlog
- 它调用 ip_rcv,数据包被传递到 IP 层
- 它调用 netfilter (PREROUTING)
- 它查看路由表,是转发的 (forwarding ) 还是本地的 (local)
- 如果是本地的,则调用 netfilter (LOCAL_IN)
- 它调用第4层 (L4) 协议(例如 tcp_v4_rcv)
- 它找到了正确的socket
- 它进入tcp有限状态机
- 将包放入接收缓冲区并按
tcp_rmem
规则设置大小 - 如果启用了
tcp_moderate_rcvbuf
,内核将自动调优接收缓冲区 - 内核会通知有数据可用到应用程序( epoll 或任何轮询系统)
- 应用程序唤醒并读取数据
出口,数据出发了
- 应用程序发送消息(send或其他)
- TCP发送消息到分配的skb_buff
- 它将skb排到
tcp_wmem
大小的套接字(socket)写缓冲区 - 构建TCP报头(src和dst端口,校验和)
- 调用第3层(L3)处理程序(在本例中是ipv4的tcp_write_xmit和tcp_transmit_skb)
- L3 (ip_queue_xmit)完成它的工作: 构建ip头并调用 netfilter (LOCAL_OUT)
- 调用输出路由动作
- 调用 netfilter (POST_ROUTING)
- 将数据包分片(ip_output)
- 调用第2层(L2)发送函数
- 将txqueuelen长度的输出(QDisc)队列输入其算法default_qdisc
- 驱动程序代码在环形缓冲区 (ring buffer) tx 处使数据包排队
- 在
tx-usecs
超时或tx-frames
个帧之后,驱动程序将执行一个软中断 soft IRQ (NET_TX_SOFTIRQ) - 重新启用硬中断 (hard IRQ) 到NIC
- 驱动程序将所有的包(要发送)映射到一些DMA区域
- NIC从RAM中(通过DMA)获取数据包进行传输
- 在传输NIC之后,会发出一个硬中断来表示传输完成
- 驱动程序将处理这个硬中断并关闭它
- 并对NAPI poll 系统进行调度(发出软中断)
- NAPI将处理数据包的信号并释放RAM
是什么,为什么和如何做 - 网络和sysctl参数
Ring Buffer - rx,tx
是什么 - 驱动接收/发送队列。一个或多个固定大小的队列,通常实现为FIFO,它位于RAM
为什么 - 缓冲来平稳地接受突发的连接而不丢弃它们,当你看到丢弃(drop)或溢出(overrun)时,你可能需要增加这些队列,也就是说,有更多的包来超过内核能够消耗它们,副作用可能是延迟增加。
怎样做:
检查命令: ethtool -g ethX
修改命令: ethtool -G ethX rx 新值 tx 新值
如何监控: ethtool -S ethX | grep -e "err" -e "drop" -e "over" -e "miss" -e "timeout" -e "reset" -e "restar" -e "collis" -e "over" | grep -v "\: 0"
中断合并(IC) - rx-usecs, tx-usecs, rx-frames, tx-frames(硬件IRQ)
是什么——在发起一个硬中断之前需要等待多少微秒/帧,从NIC的角度来看,它将DMA数据包直到这个超时或达到帧数
为什么——减少cpu的使用,硬IRQ,可能会以延迟为代价增加吞吐量。
怎样做:
检查命令: ethtool -c ethX
修改命令: ethtool -C ethX rx-usecs 新值 tx-usecs 新值
如何监视: cat /proc/interrupts
中断合并(软 IRQ)和入口 QDisc
是什么——一个 NAPI 轮询周期中的最大微秒数。当轮询周期netdev_budget_usecs
超时或处理的数据包数量达到 netdev_budget
时,轮询将退出。
为什么——驱动程序没有对大量的软中断做出反应,而是不断地轮询数据;密切关注dropped
(因为超过 netdev_max_backlog
而丢弃的数据包数)和squeezed
(ksoftirq 用完 netdev_budget
或剩余工作的时间片的次数)。
如何做:
检查命令:sysctl net.core.netdev_budget_usecs
更改命令:sysctl -w net.core.netdev_budget_usecs 新值
如何监控:cat /proc/net/softnet_stat
;或者更好的工具
是什么 - netdev_budget
是在一个轮询周期(NAPI 轮询)中从所有接口获取的最大数据包数。在一个轮询周期中,注册到轮询的接口以循环方式进行探测。此外,轮询周期可能不会超过 netdev_budget_usecs
微秒,即使 netdev_budget
尚未用尽。
如何做:
检查命令:sysctl net.core.netdev_budget
更改命令:sysctl -w net.core.netdev_budget 新值
如何监控:cat /proc/net/softnet_stat
;或者更好的工具
是什么 - dev_weight
是内核可以在 NAPI 中断上处理的最大数据包数,它是关联到每个 CPU 变量(per-CPU variable)。对于支持 LRO 或 GRO_HW 的驱动程序,硬件聚合数据包在此计为一个数据包。
如何做:
检查命令:sysctl net.core.dev_weight
更改命令:sysctl -w net.core.dev_weight 新值
如何监控:cat /proc/net/softnet_stat
;或者更好的工具
是什么 - netdev_max_backlog
是在 INPUT 端(入口 qdisc)排队的最大数据包数,当接口接收数据包的速度超过内核处理它们的速度时。
如何做:
检查命令:sysctl net.core.netdev_max_backlog
更改命令:sysctl -w net.core.netdev_max_backlog 新值
如何监控:cat /proc/net/softnet_stat
;或者更好的工具
出口 QDisc - txqueuelen 和 default_qdisc
是什么 - txqueuelen
是在 OUTPUT 端排队的最大数据包数。
为什么 - 一个缓冲区/队列面对连接突发并应用 tc(流量控制)。
如何做:
检查命令:ifconfig ethX
更改命令:ifconfig ethX txqueuelen 新值
如何监控:ip -s link
是什么 - default_qdisc
是用于网络设备的默认排队规则。
为什么 - 每个应用程序都有不同的负载和需要流量控制,它也用于对抗缓冲膨胀
如何做:
检查命令:sysctl net.core.default_qdisc
更改命令:sysctl -w net.core.default_qdisc 新值
如何监控:tc -s qdisc ls dev ethX
TCP 读写缓冲区/队列
定义什么是内存压力的策略在
tcp_mem
和tcp_moderate_rcvbuf
中指定。
是什么 - tcp_rmem
- min(在内存压力下使用的大小),default(初始大小),max(最大大小) - TCP 套接字使用的接收缓冲区大小。
为什么 - 应用程序缓冲区/队列来写入/发送数据,了解其后果会有很大帮助。
如何做:
检查命令:sysctl net.ipv4.tcp_rmem
更改命令:sysctl -w net.ipv4.tcp_rmem="min default max"
;更改默认值时,请记住重新启动您的用户空间应用程序(即您的 Web 服务器、nginx 等)
如何监控:cat /proc/net/sockstat
是什么 - tcp_wmem
- min(在内存压力下使用的大小),default(初始大小),max(最大大小) - TCP 套接字使用的发送缓冲区大小。
如何做:
检查命令:sysctl net.ipv4.tcp_wmem
更改命令:sysctl -w net.ipv4.tcp_wmem="min default max"
;更改默认值时,请记住重新启动您的用户空间应用程序(即您的 Web 服务器、nginx 等)
如何监控:cat /proc/net/sockstat
是什么 - tcp_moderate_rcvbuf
- 如果设置,TCP 执行接收缓冲区自动调整,尝试自动调整缓冲区大小。
如何做:
检查命令:sysctl net.ipv4.tcp_moderate_rcvbuf
更改命令:sysctl -w net.ipv4.tcp_moderate_rcvbuf 新值
如何监控:cat /proc/net/sockstat
荣誉奖 - TCP FSM 和拥塞算法
Accept 和 SYN 队列由
net.core.somaxconn
和net.ipv4.tcp_max_syn_backlog
管理。现在net.core.somaxconn
限制了两个队列大小。
sysctl net.core.somaxconn
- 为传递给listen()
函数的 backlog 参数的值提供上限,在用户空间中称为 SOMAXCONN。如果您更改此值,您还应该将您的应用程序更改为兼容的值(即 nginx backlog)。cat /proc/sys/net/ipv4/tcp_fin_timeout
- 这指定在强制关闭套接字之前等待最终 FIN 数据包的秒数。这严格违反了 TCP 规范,但需要防止拒绝服务攻击。cat /proc/sys/net/ipv4/tcp_available_congestion_control
- 显示已注册的可用拥塞控制选项。cat /proc/sys/net/ipv4/tcp_congestion_control
- 设置用于新连接的拥塞控制算法。cat /proc/sys/net/ipv4/tcp_max_syn_backlog
- 设置尚未从连接客户端收到确认的排队连接请求的最大数量;如果超过这个数字,内核将开始丢弃请求。cat /proc/sys/net/ipv4/tcp_syncookies
- 启用/禁用同步 cookie (SYN cookies) ,用于防止同步洪水攻击 (SYN flood attacks)。cat /proc/sys/net/ipv4/tcp_slow_start_after_idle
- 启用/禁用 tcp 慢启动。
如何监控:
netstat -atn | awk '/tcp/ {print $6}' | sort | uniq -c
- 按状态汇总ss -neopt state time-wait | wc -l
- 按特定状态计数:established, syn-sent, syn-recv, fin-wait-1, fin-wait-2, time-wait, closed, close-wait, last-ack, listening, closing
netstat -st
- tcp 统计摘要nstat -a
- 人性化的 tcp 统计摘要cat /proc/net/sockstat
- 汇总的socket统计信息cat /proc/net/tcp
- 详细统计信息,请参阅内核文档中的每个字段含义cat /proc/net/netstat
-ListenOverflows
和ListenDrops
是需要关注的重要字段cat /proc/net/netstat | awk '(f==0) { i=1; while ( i<=NF) {n[i] = $i; i++ }; f=1; next} \ (f==1){ i=2; while ( i<=NF){ printf "%s = %d\n", n[i], $i; i++}; f=0} ' | grep -v "= 0
是人类可读的/proc/net/netstat
图片来源:https://commons.wikimedia.org/wiki/File:Tcp_state_diagram_fixed_new.svg
用于测试和监控的网络工具
iperf3 - 网络吞吐量
vegeta - HTTP 负载测试工具
netdata - 分布式实时性能和健康监控系统