Linux 网络收发流程
Linux 网络栈
Linux 实际按照 TCP/IP 模型,实现了网络协议栈。在进行网络传输时,数据包就会按照协议栈,对上一层发来的数据进行逐层处理;然后封装上该层的协议头,再发送给下一层。
网络包的接收
当一个网络帧到达网卡后,网卡会通过 DMA 方式,把这个网络包放到收包队列中;然后通过硬中断,告诉中断处理程序已经收到了网络包。
网卡中断处理程序会为网络帧分配内核数据结sk_buff
,并将其拷贝到 sk_buff
缓冲区中;然后再通过软中断,通知内核收到了新的网络帧。
接下来,内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧
- 在链路层检查报文的合法性,找出上层协议的类型(比如 IPv4 还是 IPv6),再去掉帧头、帧尾,然后交给网络层。
- 网络层取出 IP 头,判断网络包下一步的走向,比如是交给上层处理还是转发。当网络层确认这个包是要发送到本机后,就会取出上层协议的类型(比如 TCP 还是 UDP),去掉 IP 头,再交给传输层处理。
- 传输层取出 TCP 头或者 UDP 头后,根据
源 IP、源端口、目的 IP、目的端口
四元组作为标识,找出对应的 Socket,并把数据拷贝到 Socket 的接收缓存中。
网络包的发送
应用程序调用 Socket API(比如 send)发送网络包。由于这是一个系统调用,所以会陷入到内核态的套接字层中。套接字层会把数据包放到 Socket 发送缓冲区中。
网络协议栈从 Socket 发送缓冲区中,取出数据包;再按照 TCP/IP 栈,从上到下逐层处理。比如,传输层和网络层,分别为其增加 TCP 头和 IP 头,执行路由查找确认下一跳的 IP,并按照 MTU 大小进行分片。
分片后的网络包,再送到网络接口层,进行物理地址寻址,以找到下一跳的 MAC 地址。然后添加帧头和帧尾,放到发包队列中。这一切完成后,会有软中断通知驱动程序:发包队列中有新的网络帧需要发送。
最后,驱动程序通过 DMA ,从发包队列中读出网络帧,并通过物理网卡把它发送出去。
处理线程
TODO
网络监控工具全景图
性能指标
带宽
表示链路的最大传输速率,单位是b/s(比特 / 秒)。
吞吐量
表示单位时间内成功传输的数据量,单位通常为 b/s(比特 / 秒)或者 B/s(字节 / 秒)。吞吐量受带宽限制
延时
表示从网络请求发出后,一直收到远端响应,所需要的时间延迟。在不同场景中,这一指标可能会有不同含义。比如,它可以表示,建立连接需要的时间(比如 TCP 握手延时),或一个数据包往返所需的时间(比如 RTT)。
PPS
Packet Per Second(包 / 秒) 的缩写,表示以网络包为单位的传输速率。PPS通常用来评估网络的转发能力。
网络基准测试
转发性能测试PPS
Linux 内核自带的高性能网络测试工具 pktgen。pktgen 支持丰富的自定义选项,方便你根据实际需要构造所需网络包,从而更准确地测试出目标服务器的性能。
不过,在 Linux 系统中,你并不能直接找到 pktgen 命令,因为 pktgen 作为一个内核线程来运行,需要你加载 pktgen 内核模块后,再通过 /proc 文件系统来交互。
# modprobe pktgen
# ls /proc/net/pktgen/
kpktgend_0 kpktgend_1 pgctrl
根据上面的结果,我们发现,PPS 为 12 万,吞吐量为 61 Mb/s,没有发生错误。那么,12 万的 PPS 好不好呢?
作为对比,你可以计算一下千兆交换机的 PPS。交换机可以达到线速(满负载时,无差错转发),它的 PPS 就是 1000Mbit 除以以太网帧的大小,即 1000Mbps / ((64+20)*8bit) = 1.5 Mpps(其中,20B 为以太网帧前导和帧间距的大小)。
即使是千兆交换机的 PPS,也可以达到 150 万 PPS,比我们测试得到的 12 万大多了。所以,看到这个数值你并不用担心,现在的多核服务器和万兆网卡已经很普遍了,稍做优化就可以达到数百万的 PPS。
而且,如果你用了DPDK 或 XDP ,还能达到千万数量级。
TDP/UDP 性能
iperf
和 netperf
都是最常用的网络性能测试工具,用来测试TCP 和 UDP的吞吐量。它们都以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。这里以iperf
命令为例。
-
常用命令
-
实践
在目标机器上启动iperf 服务端# iperf3 -s -i 1 -p 10000 -s 表示启动服务端 -i 表示汇报间隔 -p 表示监听端口
在另一台机器上运行客户端
# iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000 -c 表示启动客户端 -b 表示目标带宽 -t 表示测试时间 -P 表示并发数 -p 表示目标服务器的监听端口
无标题.png
从上面可以看出目标机器的吞吐量为866 Mb/s。
HTTP
测试HTTP的性能,也有大量工具可以使用,比如 ab,webbench等。这里以 ab 为例
-
安装
- ubuntu
apt-get install -y apache2-utils
- centos
yum install -y httpd-tools
- ubuntu
-
常用命令
-
实践
- 在目标机器上,使用 Docker 启动一个 Nginx 服务,然后用 ab 来测试它的性能。
docker run -p 80:80 -itd nginx
- 在另一台机器上,运行
ab
命令,测试nginx性能# ab -c 1000 -n 10000 http://192.168.0.30/ # -c 表示并发量100,10000表示总的
- 在目标机器上,使用 Docker 启动一个 Nginx 服务,然后用 ab 来测试它的性能。
应用负载性能
TODO
网络配置
root@VM-0-12-ubuntu:~# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.12 netmask 255.255.240.0 broadcast 172.17.15.255
inet6 fe80::5054:ff:fed7:21c8 prefixlen 64 scopeid 0x20<link>
ether 52:54:00:d7:21:c8 txqueuelen 1000 (Ethernet)
RX packets 160252 bytes 164031108 (164.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 64627 bytes 10431076 (10.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
网络接口的状态标志
输出的RUNNING
,都表示物理网络是连通的,即网卡已经连接到了交换机或者路由器中。MTU的大小
规定了最大的 IP 包大小,。MTU 默认大小是 1500。网络接口的IP地址,子网,以及MAC地址
-
网络收发的字节数,包数,错误数以及丢包的情况
- errors
表示发生错误的数据包数,比如校验错误,帧同步错误。 - dropped
表示丢弃的数据包数,即数据包已经收到了Ring Buffer
。 - overruns
表示超限数据包数,即网络 I/O 速度过快,导致Ring Buffer
中的数据包来不及处理(队列满)而导致的丢包; - carrier
表示发生 carrirer 错误的数据包数,比如双工模式不匹配、物理电缆出现问题等 - collisions
表示碰撞数据包数
- errors
查看网卡带宽
# ethtool eth0 | grep Speed
连通性和延时查看:ping hping3 telnet nc 命令
ping 命令
确定网络主机的连通状态
- 发指定个数ping包
- linux
ping -c 4 www.baidu.com
- windows
- linux
- 指定ping报文数据包大小
ping -s 512 www.baidu.com
hping3 命令
出于安全的考虑,很多网络服务会把ICMP禁止掉,这也就导致我们无法用 ping ,hping3是一个测试网络包处理能力的性能工具,也可以用来测试延时
# hping3 -c 3 -S -p 80 baidu.com # -c 表示3次 -S 表示Tcp SYN -p 表示端口
HPING baidu.com (eth0 39.156.69.79): S set, 40 headers + 0 data bytes
len=40 ip=39.156.69.79 ttl=249 id=6995 sport=80 flags=SA seq=0 win=8192 rtt=29.8 ms
len=40 ip=39.156.69.79 ttl=249 id=32254 sport=80 flags=SA seq=1 win=8192 rtt=36.0 ms
len=40 ip=39.156.69.79 ttl=249 id=20666 sport=80 flags=SA seq=2 win=8192 rtt=32.0 ms
telnet 命令
用于确定目标主机端口是否打开
# telnet www.baicu.com 80
nc 命令
- 连接服务器某端口
可用来测试对方端口是否打开nc -v 127.0.0.1 12345
套接字信息:netstat 命令
netstat
netstat -[atunlp]
-a:列出目前系统上所有的连接,监听,socket
-t:列出tcp网络数据包数据
-u:列出udp网络数据包数据
-n:不列出进程的服务名称,以端口号来显示
-l:列出目前正在监听的网络
-p:列出网络服务的PID
- 查看某个端口是否被占用
netstat -anp | grep 80
- 统计TCP套接字各状态信息
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}'
- netstat 中Recv-Q 和 Send-Q的意义
-
当套接字处于连接状态时
- Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)
- Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)
-
当套接字处于监听状态时
image.png- Recv-Q 表示全连接队列的长度。
- Send-Q 表示全连接队列的最大长度。
全连接,是指服务器收到了客户端的 ACK,完成了 TCP 三次握手,然后就会把这个连接挪到全连接队列中。这些全连接中的套接字,还需要被
accept
系统调用取走。与全连接队列相对应的,还有一个半连接队列。半连接是指还没有完成 TCP 三次握手的连接,连接只进行了一半。服务器收到了客户端的 SYN 包后,就会把这个连接放到半连接队列中,然后再向客户端发送 SYN+ACK 包。
-
网络吞吐和 PPS:sar 命令
给 sar 增加 -n 参数就可以查看网络的统计信息,比如网络接口(DEV)、网络接口错误(EDEV)、TCP、UDP、ICMP 等等
# sar -n DEV 1
Linux 4.15.0-118-generic (VM-0-12-ubuntu) 12/28/2020 _x86_64_ (1 CPU)
11:25:06 AM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
11:25:07 AM eth0 8.00 6.00 0.64 0.97 0.00 0.00 0.00 0.00
11:25:07 AM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
11:25:07 AM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
11:25:08 AM eth0 3.96 3.96 0.32 0.80 0.00 0.00 0.00 0.00
11:25:08 AM lo 7.92 7.92 0.64 0.64 0.00 0.00 0.00 0.00
rxpck/s txpck/s
每秒钟 接收/发送 PPS 的数据包,单位为包 / 秒rxKB/s txkB/s
每秒钟接受/发送的数据包大小,单位为KB / 秒rxcmp/s 和 txcmp/s
分别是接收和发送的压缩数据包数,单位是包 / 秒。%ifutil
网络接口的使用率,即半双工模式下为 (rxkB/s+txkB/s)/Bandwidth,而全双工模式下为 max(rxkB/s, txkB/s)/Bandwidth。
统计socket连接信息
sar -n SOCK 1 1
- totsck 当前被使用的socket总数
- tcpsck 当前正在被使用的TCP的socket总数
- udpsck 当前正在被使用的UDP的socket总数
- rawsck 当前正在被使用于RAW的skcket总数
- if-frag 当前的IP分片的数目
- tcp-tw TCP套接字中处于TIME-WAIT状态的连接数量
iftop 命令
iftop是类似于top的实时流量监控工具。
中间的<= =>这两个左右箭头,表示的是流量的方向。
TX:发送流量
RX:接收流量
TOTAL:总流量
Cumm:运行iftop到目前时间的总流量
peak:流量峰值
rates:分别表示过去 2s 10s 40s 的平均流量
常用命令
-
-i设定监测的网卡
iftop -i eth1
-
-B 以bytes为单位显示流量(默认是bits)
iftop -B
-
-n使host信息默认直接都显示IP
iftop -n
-
-N使端口信息默认直接都显示端口号
iftop -N
-P使host信息及端口信息默认就都显示
-F显示特定网段的进出流量,如# iftop -F 10.10.1.0/24或# iftop -F 10.10.1.0/255.255.255.0
-h(display this message),帮助,显示参数信息
进入iftop画面后的一些操作命令
按h切换是否显示帮助;
按n切换显示本机的IP或主机名;
按s切换是否显示本机的host信息;
按d切换是否显示远端目标主机的host信息;
按t切换显示格式为2行/1行/只显示发送流量/只显示接收流量;
按N切换显示端口号或端口服务名称;
按S切换是否显示本机的端口信息;
按D切换是否显示远端目标主机的端口信息;
按p切换是否显示端口信息;
按P切换暂停/继续显示;
按b切换是否显示平均流量图形条;
按B切换计算2秒或10秒或40秒内的平均流量;
按T切换是否显示每个连接的总流量;
按l打开屏幕过滤功能,输入要过滤的字符,比如ip,按回车后,屏幕就只显示这个IP相关的流量信息;
按L切换显示画面上边的刻度;刻度不同,流量图形条会有变化;
按j或按k可以向上或向下滚动屏幕显示的连接记录;
按1或2或3可以根据右侧显示的三列流量数据进行排序;
按<根据左边的本机名或IP排序;
按>根据远端目标主机的主机名或IP排序;
按o切换是否固定只显示当前的连接;
按f可以编辑过滤代码,这是翻译过来的说法,我还没用过这个!
按!可以使用shell命令,这个没用过!没搞明白啥命令在这好用呢!
按q退出监控。
延展阅读
- 文件描述符的数量
- syn 洪泛攻击
- 大量请求带来的中断处理中断不均
- dropped 上升
- 连接状态的跟踪(CONNTRACK)