一、网络通信
以下内容都以物理网卡为例。事实上,Linux还支持众多的虚拟网络设备,而它们的网络收发流程会有一些差别。
网络包的接收
1)网卡接收
当一个网络帧到达网卡后,网卡会通过DMA方式,把这个网络包放到收包队列中;然后通过硬中断,告诉中断处理程序已经收到了网络包。
接着,网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到sk_buff缓冲区中;然后再通过软中断,通知内核收到了新的网络帧。
接下来,内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧。比如,
2)在链路层
检查报文的合法性,找出上层协议的类型(比如IPv4还是IPv6),再去掉帧头、帧尾,然后交给网络层。
3)网络层
取出IP头,判断网络包下一步的走向,比如是交给上层处理还是转发。当网络层确认这个包是要发送到本机后,就会取出上层协议的类型(比如TCP还是UDP),去掉IP头,再交给传输层处理。
4)传输层
取出TCP头或者UDP头后,根据<源IP、源端口、目的IP、目的端口>四元组作为标识,找出对应的Socket,并把数据拷贝到Socket的接收缓存中。
5)应用层
最后,应用程序就可以使用Socket接口,读取到新接收到的数据了。
二、性能指标
用带宽、吞吐量、延时、PPS(PacketPerSecond)等指标衡量网络的性能。
带宽
表示链路的最大传输速率,单位通常为b/s(比特/秒)。1字节=8比特
1M带宽就是1Mbps(兆比特每秒),亦1x1024/8=128KB/sec,但这只是理论速度,实际上还要扣除12%的通信标识等各种控制讯号,故传输速度上限应为112KB/sec左右。
服务器双万兆网卡bond后为20000Mb/s传输速度上限计算后应为
20000➗1024➗8✖️(1-12%)≈2.15GB/sec左右。(除以1024转为Gbps千兆比特每秒)
[root@maxc81 ~]# ethtool bond0 | grep -A1 Speed Speed: 20000Mb/s Duplex: Full 全双工
吞吐量
表示单位时间内成功传输的数据量,单位通常为b/s(比特/秒)或者B/s(字节/秒)。吞吐量受带宽限制,而吞吐量/带宽,也就是该网络的使用率。
查看sar-n参数就可以查看网络的统计信息,比如网络接口(DEV)、网络接口错口(EDEV)、TCP、UDP、ICMP等等
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。
本机带宽Bandwidth为20000Mb/s,本机网络接口使用率
max(8018.14KB/s,7544.02KB/s)/(20000Mb/s✖️1024)≈0
[root@maxc81 ~]# sar -n DEV 1 Linux 3.10.0-514.el7.x86_64 (maxc81) 03/06/2022 _x86_64_ (40 CPU) 10:34:41 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s 10:34:42 PM enp94s0f1 7168.00 533.00 10503.15 749.27 0.00 0.00 0.00 10:34:42 PM bond0 7575.00 8021.00 10535.12 11272.95 0.00 0.00 0.00 10:34:42 PM enp94s0f0 407.00 7488.00 31.98 10523.68 0.00 0.00 0.00 10:34:42 PM lo 44.00 44.00 27.37 27.37 0.00 0.00 0.00 ^C 10:34:42 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s 10:34:43 PM enp94s0f1 17263.49 34.92 25442.32 10.24 0.00 0.00 0.00 10:34:43 PM bond0 18163.49 18130.16 25519.88 25484.61 0.00 0.00 0.00 10:34:43 PM enp94s0f0 900.00 18095.24 77.56 25474.37 0.00 0.00 0.00 10:34:43 PM lo 19.05 19.05 1.65 1.65 0.00 0.00 0.00 Average: IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s Average: enp94s0f1 5451.79 173.28 7983.42 212.05 0.00 0.00 0.00 Average: bond0 5752.89 5443.53 8018.14 7544.02 0.00 0.00 0.00 Average: enp94s0f0 301.10 5270.25 34.71 7331.97 0.00 0.00 0.00 Average: lo 30.03 30.03 9.07 9.07 0.00 0.00 0.00
延时
表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。在不同场景中,这一指标可能会有不同含义。比如,它可以表示,建立连接需要的时间(比如TCP握手延时),或一个数据包往返所需的时间(比如RTT)。
ping,来测试远程主机的连通性和延时,而这基于ICMP协议
ping的输出,可以分为两部分。
第一部分,是每个ICMP请求的信息,包括ICMP序列号(icmp_seq)、TTL(生存时间,或者跳数)以及往返延时。
第二部分,则是三次ICMP请求的汇总。
比如下面的示例显示,发送了3个网络包,并且接收到3个响应,没有丢包发生,这说明测试主机到8.8.8.8是连通的;平均往返延时(RTT)是44ms,也就是从发送ICMP开始,到接收到8.8.8.8回复的确认,总共经历44ms。偏离平均值mdev(MeanDeviation)是0.037ms,值越小网络越稳定。
[root@maxc81 ~]# ping -c3 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=2 ttl=113 time=44.3 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=113 time=44.4 ms --- 8.8.8.8 ping statistics --- 3 packets transmitted, 2 received, 33% packet loss, time 2000ms rtt min/avg/max/mdev = 44.355/44.392/44.429/0.037 ms
在遇到服务器禁用icmp时可以通过 traceroute或hping3的TCP和UDP模式,来获取网络延迟。traceroute会在路由的每一跳发送三个包,并在收到响应后,输出往返延时。如果无响应或者响应超时(默认5s),就会输出一个星号。
# -c 表示发送 3 次请求,-S 表示设置 TCP SYN,-p 表示端口号为 80 [root@k8smaster ~]# hping3 -c 3 -S -p 80 baidu.com HPING baidu.com (ens33 220.181.38.148): S set, 40 headers + 0 data bytes len=46 ip=220.181.38.148 ttl=128 id=34904 sport=80 flags=SA seq=0 win=64240 rtt=31.1 ms len=46 ip=220.181.38.148 ttl=128 id=34905 sport=80 flags=SA seq=1 win=64240 rtt=30.0 ms len=46 ip=220.181.38.148 ttl=128 id=34906 sport=80 flags=SA seq=2 win=64240 rtt=27.6 ms --- baidu.com hping statistic --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 27.6/29.5/31.1 ms
# --tcp 表示使用 TCP 协议,-p 表示端口号,-n 表示不对结果中的 IP 地址执行反向域名解析 [root@k8smaster ~]# traceroute --tcp -p 80 -n baidu.com traceroute to baidu.com (220.181.38.148), 30 hops max, 52 byte packets 1 172.17.1.2 0.150 ms 0.187 ms 0.111 ms 2 220.181.38.148 28.967 ms 30.303 ms 30.022 ms
使用hping3以及wrk等工具,确认单次请求和并发请求情况的网络延迟是否正常。
使用traceroute,确认路由是否正确,并查看路由中每一跳网关的延迟。
使用tcpdump和Wireshark,确认网络包的收发是否正常。
使用strace等,观察应用程序对网络套接字的调用情况是否正常。
PPS
是PacketPerSecond(包/秒)的缩写,表示以网络包为单位的传输速率。PPS通常用来评估网络的转发能力,比如硬件交换机,通常可以达到线性转发(即PPS可以达到或者接近理论最大值)。而基于Linux服务器的转发,则容易受网络包大小的影响。
其他
除了这些指标,网络的可用性(ping、telnet、nmap命令测试网络能否正常通信)、并发连接数(ss、netstat命令查询TCP连接数量)、丢包率(ifconfig、sar命令查看丢包百分比)、重传率(netstat-s命令查询重新传输的网络包比例)等也是常用的性能指标。
ifconfig和ip命令都包括了网络接口的状态标志、MTU大小、IP、子网、MAC地址以及网络包收发的统计信息。
网络接口状态标志
ifconfig输出中的RUNNING,或ip输出中的LOWER_UP,都表示物理网络是连通的,即网卡已经连接到了交换机或者路由器中。
MTU大小
MTU默认大小是1500,根据网络架构的不同(比如是否使用了VXLAN等叠加网络),可能需要调大或者调小MTU的数值。
网络接口的IP地址、子网以及MAC地址
这些都是保障网络功能正常工作所必需的,需要确保配置正确。
网络收发的字节数、包数、错误数以及丢包情况
特别是ifconfig输出TX(接收)和RX(发送)部分:
errors:发生错误的数据包数,比如校验错误、帧同步错误等
dropped:丢弃的数据包数,即数据包已经收到了RingBuffer,但因为内存不足等原因丢包
overruns:超限数据包数,即网络I/O速度过快,导致RingBuffer中的数据包来不及处理(队列满)而导致的丢包
carrier:发生carrirer错误的数据包数,比如双工模式不匹配、物理电缆出现问题等
collisions:碰撞数据包数
三、套接字socket
在实际的性能问题中,网络协议栈中的统计信息,也必须关注。用ss命令来查看套接字、网络栈、网络接口以及路由表的信息
ss统计信息
显示套接字的状态、接收队列、发送队列、本地地址、远端地址、进程PID和进程名称等,常用组合选项-ltnp
-l 显示监听套接字 -t 显示TCP套接字 -n 显示数字地址和端口(而不是名称) -p 显示进程信息
其中,接收队列(Recv-Q)和发送队列(Send-Q)需要特别关注,它们通常应该是0。
当套接字处于连接状态(Established)时,
Recv-Q表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。
Send-Q表示还没有被远端主机确认的字节数(即发送队列长度)。
当套接字处于监听状态(Listening)时,
Recv-Q表示synbacklog的当前值。
Send-Q表示最大的synbacklog值。
协议栈统计
ss-s和netstat-s命令
ss-s较为精简:只显示已经连接、关闭、等待套接字等简要统计
netstat-s丰富:展示TCP协议的主动/被动连接、失败重试、发送/接收的分段数量等信息
[root@maxc81 ~]# ss -s Total: 2029 (kernel 12321) TCP: 538 (estab 233, closed 222, orphaned 0, synrecv 0, timewait 190/0), ports 0 Transport Total IP IPv6 * 12321 - - RAW 0 0 0 UDP 18 11 7 TCP 316 50 266 INET 334 61 273 FRAG 0 0 0 [root@maxc81 ~]# netstat -s | grep -A10 ^Tcp: Tcp: 264430273 active connections openings 149305561 passive connection openings 174283425 failed connection attempts 2123749 connection resets received 236 connections established 30923492268 segments received 275155123109 segments send out 36717117 segments retransmited 168063 bad segments received. 12045490 resets sent
四、C10K和C1000K
介绍
首字母C是Client的缩写。C10K就是单机同时处理1万个请求(并发连接1万)的问题,而C1000K也就是单机支持处理100万个请求(并发连接100万)的问题。
从资源上来说,对2GB内存和千兆网卡的服务器来说,同时处理10000个请求,只要每个请求处理占用不到200KB(2GB/10000)的内存和100Kbit(1000Mbit/10000)的网络带宽就可以。
网络I/O
基于I/O多路复用和请求处理的优化,实现C10K从1万到10万,其实还是基于C10K的这些理论,epoll配合线程池,再加上CPU、内存和网络接口的性能和容量提升。大部分情况下,C100K很自然就可以达到。
实现C1000K,首先从物理资源使用上来说,100万个请求需要大量的系统资源。比如,
假设每个请求需要16KB内存的话,那么总共就需要大约15GB内存。
而从带宽上来说,假设只有20%活跃连接,即使每个连接只需要1KB/s的吞吐量,总共也需要1.6Gb/s的吞吐量。千兆网卡显然满足不了这么大的吞吐量,所以还需要配置万兆网卡,或者基于多网卡Bonding承载更大的吞吐量。
其次,从软件资源上来说,大量的连接也会占用大量的软件资源。
最后,大量请求带来的中断处理,也会带来非常高的处理成本,优化各种硬件和软件。
扩展
C10K问题的根源,一方面在于系统有限的资源;另一方面,也是更重要的因素,是同步阻塞的I/O模型以及轮询的套接字接口,限制了网络事件的处理效率。Linux2.6中引入的epoll,完美解决了C10K的问题,现在的高性能网络方案都基于epoll。
从C10K到C100K,可能只需要增加系统的物理资源就可以满足;但从C100K到C1000K,就不仅仅是增加物理资源就能解决的问题了。这时,就需要多方面的优化工作了,从硬件的中断处理和网络功能卸载、到网络协议栈的文件描述符数量、连接状态跟踪、缓存队列等内核的优化,再到应用程序的工作模型优化,都是考虑的重点。
再进一步,要实现C10M,就不只是增加物理资源,或者优化内核和应用程序可以解决的问题了。这时候,就需要用XDP的方式,在内核协议栈之前处理网络包;或者用DPDK直接跳过网络协议栈,在用户空间通过轮询的方式直接处理网络包。
五、抓包分析
抓包tcpdump
介绍
tcpdump也是最常用的一个网络分析工具。它基于libpcap,利用内核中的AF_PACKET套接字,抓取网络接口中传输的网络包;并提供了强大的过滤规则。
前两行,表示tcpdump的选项以及接口的基本信息;从第三行开始,就是抓取到的网络包的输出。这些输出的格式,都是时间戳协议源地址.源端口>目的地址.目的端口网络包详细信息(这是最基本的格式,可以通过选项增加其他字段)。
使用格式:
tcpdump【选项】【过滤表达式】
常用选项:
-i 指定网口,默认0号接口,any表示所有接口 -nn 不解析IP地址和端口号的名称 -c 限制抓包个数 -A 以ASCII格式显示网络包内容(默认只显示头部信息) -w 保存到文件中,默认.pcap为后缀文件名 -e 输出链路层头部信息
常用过滤表达式:
host、src host、dst host 主机过滤 net、src net、dst net 网络过滤 port、portrange、src port、dst port 端口过滤 ip、ip6、arp、tcp、udp、icmp 协议过滤 and、or、not 逻辑关系
常用案例:
抓取连接指定主机的包(不解析IP地址和端口号的名称)
tcpdump-nnhostexample.com-wweb.pcap
抓取eth0网卡上tcp协议80端口的包
tcpdump-ieth0-ntcpport80
分析wireshark
介绍
Wireshark也是最流行的一个网络分析工具,它最大的好处就是提供了跨平台的图形界面。跟tcpdump类似,Wireshark也提供了强大的过滤规则表达式,同时,还内置了一系列的汇总分析工具。以更规整的格式,展示了各个网络包的头部信息;还用了不同颜色,展示不同的协议。
使用方式:
安装客户端使用,规则参考tcpdump。