linux协议栈优化方法,初识 Linux 网络栈及常用优化方法

原标题:初识 Linux 网络栈及常用优化方法

作者简介: 刘立超,靠 Linux 内核,驱动吃饭的工程师,喜欢探究事物本质,喜欢分享。

版权声明: 本文最先发表于 “泰晓科技” 微信公众号,欢迎转载,转载时请在文章的开头保留本声明。

文章简介

基于 ping 流程窥探 Linux 网络子系统,同时介绍各个模块的优化方法。

ping 基本原理

Client 端发送 ICMP ECHO_REQUEST 报文给 Server

Server 端回应 ICMP ECHO_REPLY 报文给 Client

这其中涉及基本的二三层转发原理,比如:直接路由、间接路由、ARP 等概念。

这部分不是本文重点,最基本的网络通信原理可以参考这篇文章:

👉 TCP/IP 入门指导

ping 报文发送流程

系统调用层

sendmsg 系统调用

根据目标地址获取路由信息,决定报文出口

ip_append_data 函数构建 skb(这时才将报文从用户态拷贝到内核态),将报文放入 socket buffer

调用 ip_push_pending_frames ,进入 IP 层处理

IP 层

填充 IP 头

根据 neighbour 信息,填充 MAC 头,调用 dev_queue_xmit 进入网络设备层

网络设备层

选择发送队列

__dev_xmit_skb 尝试直接发送报文,如果网卡繁忙就将报文放入目标发送队列的 qdisc 队列,并触发 NET_TX_SOFTIRQ 软中断,在后续软中断处理中发送 qdisc 队列中的报文

驱动层发包函数,将 skb 指向的报文地址填入 tx deor,网卡发送报文

发送完成后触发中断,回收 tx deor(实际实现中一般放在驱动 poll 函数中)

优化点

socket buffer

应用程序报文首先放入 socket buffer,socket buffer 空间受 wmem_default 限制,而 wmem_default 最大值受 wmem_max 限制。

调整方法:sysctl -w net.core.wmem_max=xxxxxx -- 限制最大值

sysctl -w net.core.wmem_default=yyyyyy

qdisc 队列长度

经过网络协议栈到达网络设备层的时候,报文从 socket buffer 转移至发送队列 qdisc。

调整方法:ifconfig eth0 txqueuelen 10000

qdisc 权重

即一次 NET_TX_SOFTIRQ 软中断最大发送报文数,默认64。

调整方法:sysctl -w net.core.dev_weight=600

tx deor 数量

即,多少个发送描述符。

调整方法:ethtool -G eth0 rx 1024 tx 1024

高级特性:TSO/GSO/XPS

TSO(TCP Segmentation Offload):超过 MTU 大小的报文不需要在协议栈分段,直接由网卡分段,降低 CPU 负载。

GSO(Generic Segmentation Offload):TSO 的软件实现,延迟大报文分段时机到 IP 层结束或者设备层发包前,不同版本内核实现不同。

开启方法:ethtool -K eth0 gso on

ethtool -K eth0 tso on

XPS(Transmit Packet Steering):对于有多队列的网卡,XPS 可以建立 CPU 与 tx queue 的对应关系,对于单队列网卡,XPS 没啥用。

开启方法:

内核配置CONFIG_XPS

建立cpu与发送队列映射:

echocpu_mask > /sys/class/net/eth0/queues/tx-/xps_cpus

ping 报文收取过程

驱动层

网卡驱动初始化,分配收包内存(ring buffer),初始化 rx deor

网卡收到报文,将报文 DMA 到 rx deor 指向的内存,并中断通知 CPU

CPU 中断处理函数:关闭网卡中断开关,触发 NET_RX_SOFTIRQ 软中断

软中断调用网卡驱动注册的 poll 函数,收取报文(著名的 NAPI 机制)

驱动 poll 函数退出前将已经收取的 rx deor 回填给网卡

协议栈层

驱动层调用 napi_gro_receive ,开始协议栈处理,对于 ICMP 报文,经过的处理函数: ip_rcv -> raw_local_deliver -> raw_rcv -> __sock_queue_rcv_skb

现在内核都使用 GRO 机制将驱动层 skb 上送协议栈,GRO 全称 Generic Receive Offload,是网卡硬件的 LRO 功能(Intel 手册使用 RSC 描述)的软件实现,可以将同一条流的报文聚合后再上送协议栈处理,降低 CPU 消耗,提高网络吞吐量。

送入 socket buffer

基于 poll/epoll 机制唤醒等待 socket 的进程

应用读取报文

从 socket buffer 的读取文,并拷贝到用户态

优化点

rx deor 长度

瞬时流量太大,软件收取太慢,rx deor 耗尽后肯定丢包。增大 rx deor 长度可以减少因为瞬时流量大造成的丢包。但是不能解决性能不足造成的丢包。

调整方法:查看 rx deor 长度:ethtool -g eth0

调整 rx deor 长度:ethtool -G eth0 rx 1024 tx 1024

中断

为了充分利用多核 CPU 性能,高性能(现代)网卡一般支持多队列。配合底层 RSS(Receive-Side Scaling)机制,将报文分流到不同的队列。每个队列对应不同的中断,进而可以通过中断亲和性将不同的队列绑定到不同的 CPU。

PS:只有 MSI-X 才支持多队列/多中断。

调整方法:中断亲和性设置:

echocpu_mask > /proc/irq//smp_affinity

查看队列数:ethtool -l eth0

调整队列数:ethtool -L eth0

进阶:队列分流算法设置

NAPI

网卡中断中触发 NET_RX_SOFTIRQ 软中断,软中断中调用驱动 poll 函数,进行轮询收包。NAPI 的好处在于避免了每个报文都触发中断,避免了无意义的上下文切换带来的 Cache/TLB miss 对性能的影响。

但是 Linux 毕竟是通用操作系统,NAPI 轮询收包也要有限制,不能长时间收包,不干其他活。所以 NET_RX_SOFTIRQ 软中断有收包 budget 概念。即,一次最大收取的报文数。

收包数超过 netdev_budget(默认300)或者收包时间超过2个 jiffies 后就退出,等待下次软中断执行时再继续收包。驱动层 poll 收包函数默认一次收64个报文。

netdev_budget 调整方法:sysctl -w net.core.netdev_budget=600

驱动层 poll 函数收包个数只能修改代码。一般不需要修改。

开启高级特性 GRO/RPS/RFS

GRO(Generic Receive Offload):驱动送协议栈时,实现同条流报文汇聚后再上送,提高吞吐量。对应 napi_gro_receive 函数。

开启方法:ethtool -K eth0 gro on

RPS(Receive Packet Steering):对于单队列网卡,RPS 特性可以根据报文 hash 值将报文推送到其它 CPU 处理(把报文压入其它 CPU 队列,然后给其它 CPU 发送 IPI 中断,使其进行收包处理),提高多核利用率,对于多队列网卡,建议使用网卡自带的 RSS 特性分流。

RPS 开启方法:

echocpu_mask > /sys/class/net/eth0/queues/rx-0/rps_cpus

RFS 设置方法:

sysctl -w net.core.rps_sock_flow_entries=32768

echo2048 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

PS:RFS 有些复杂,这里只说举例配置,不讲述原理(其实就是不会。。。)

socket buffer

__sock_queue_rcv_skb 中会将 skb 放入 socket buffer,其中会检查 socket buffer 是否溢出。所以要保证 socket buffer 足够大。

设置方法:sysctl -w net.core.rmem_max=xxxxxx -- 限制最大值

sysctl -w net.core.rmem_default=yyyyyy

参考文档

scaling:👉https://github.com/torvalds/linux/blob/v3.13/Documentation/networking/scaling.txt

monitoring-tuning-linux-networking-stack-receiving-data:👉https://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/

monitoring-tuning-linux-networking-stack-sending-data:👉https://blog.packagecloud.io/eng/2017/02/06/monitoring-tuning-linux-networking-stack-sending-data/

扫 码 关 注 我 们

再 + 好 友 tinylab

进 泰 晓 技 术 群

泰 晓 科 技

72d6cad06bf906852f0f689e80e0b7cf.png

关注“泰晓科技”!点“在看”返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值