网络是Linux系统最核心的功能之一,网络是一种把不同计算机或网络设备连接到一起的技术,它本质上是一种进程间通信方式,特别是跨系统的进程间通信,必须要通过网络才能进行。随着高并发、分布式、云计算、微服务等技术的普及,网络的性能也变得越来越重要;
那么,Linux网络又是怎么工作的呢?又有哪些指标衡量网络的性能呢?
网络性能篇
Linux网络基础原理
网络模型
**网络模型:**7层网络模型(OSI 网络模型)与4层网络模型(TCP/IP 网络模型)
OSI是一个分层结构,共有7层,从下往上分别是:物理层、数据链路层(通常简称链路层)、网络层、传输层、会话层、表示层和应用层,如下图所示。其中各个功能层执行特定的、相对简单的任务。每一层都由上一层支配,并从上一层接收数据,为上一层提供服务。
第1层至第3层主要是完成数据交换和数据传输,称为网络低层,即通信子网;第5层至第7层主要是完成信息处理服务的功能,称为网络高层;低层与高层之间由第4层衔接。通常也将会话层、表示层和应用层统称为应用层,将传输层及以下各层统称为数据传输层。
但是OSI模型还是太复杂了,也没能提供一个可实现的方法。因此,在Linux中,我们实际上使用的是另一个更实用的四层模型,也就是TCP/IP模型;
- 网络接口层
网络接口层(Network Interface Layer)又称网络访问层(Network Access Layer),包括OSI的物理层和链路层,负责向网络物理介质发送数据包,从网络物理介质接收数据包。TCP/IP并没有对物理层和链路层进行定义,它只是支持现有的各种底层网络技术和标准。网络接口层涉及操作系统中的设备驱动程序和网络接口设备。
- 网络层
网络层又称为互联网层或IP层,负责处理IP数据包的传输、路由选择、流量控制和拥塞控制。
TCP/IP网络层的底部是负责Internet地址(IP地址)与底层物理网络地址之间进行转换的地址解析协议(Address Resolution Protocol, ARP)和反向地址解析协议(Reverse Address Resolution Protocol, RARP)。
ARP用于根据IP地址获取物理地址。RARP用于根据物理地址查找其IP地址。由于ARP和RARP用于完成网络层地址和链路层地址之间的转换,也有人将ARP和RARP作为链路层协议。
IP协议(Internet Protocol)既是网络层的核心协议,也是TCP/IP协议簇中的核心协议。网络互联的基本功能主要是由IP协议来完成的。Internet控制报文协议(Internet Control Message Protocol, ICMP)是主机和网关进行差错报告、控制和进行请求/应答的协议。Internet组管理协议(Internet Group Management Protocol, IGMP)用于实现组播中的组成员管理。
- 传输层
传输层为两台主机上的应用程序提供端到端的通信。
TCP/IP的传输层包含传输控制协议TCP (Transmission Control Protocol)和用户数据报协议UDP(User Datagram Protocol)。这两种协议对应两类不同性质的服务,TCP为主机提供可靠的面向连接的传输服务;UDP为应用层提供简单高效的无连接传输服务。上层的应用进程可以根据可靠性要求或效率要求决定是使用TCP还是UDP来提供服务。
- 应用层
这个层次包括OSI的会话层、表示层和应用层,直接为特定的应用提供服务。应用层为用户提供一些常用的应用程序。TCP/IP给出了应用层的一些常用协议规范,如文件传输协议FTP、简单邮件传输协议SMTP、超文本传输协议HTTP等。
同时上图也给出对应层的关系, 可以形象地理解TCP/IP和OSI模型的关系;
虽然说Linux实际按照TCP/IP模型, 实现了网络协议栈,但是在平时交流中还是习惯的用OSI七层模型来描述,例如,在说到七层和四层的负载均衡,对应的分别是OSI模型中的应用层个传输层(而它们对应到TCP/IP模型中,实际上是四层和三层);
Linux网络栈
有了TCP/IP模型后,在进行网络传输时,数据包就会按照协议栈,对上一层发来的数据进行逐层处理;然后封装上该层的协议头,再发送给下一层;
当然,网络包在每一层的处理逻辑,都取决于各层采用的网络协议。比如在应用层,一个提供REST API的应用,可以使用HTTP协议,把它需要传输的JSON数据封装到HTTP协议中,然后向下传递到下一层(也就是TCP层);
而封装做的事情就很简单了,只是在原来的负载前后,增加固定的格式的元数据,原始的负载数据并不会被修改;
比如,以通过TCP协议通信的网络包为例,以下面这个图,我们可以看到,应用程序数据在每个层的封装格式;
其中:
- 传输层在应用程序数据前面增加了TCP头;
- 网络层在TCP数据包前增加了IP头;
- 而网络接口层,又在IP数据包前后分别增加了帧头和帧尾。
这些新增的头部和尾部,都按照特定的协议格式填充;
这些新增的头部和尾部,增加了网络包的大小,但我们都知道,物理链路并不能传输任意大小的数据包。网络接口配置的最大传输单元(MTU),就规定了最大的IP包大小;
在我们最常见的以太网中,MTU默认值时1500(这也是Linux的默认值);
一旦网络包超过MTU的大小,就会在网络层分片,以保证分片后的IP包不大于MTU值。显然,MTU越大,需要的分包也就越少,自然,网络的吞吐能力就越好。
理解了TCP/IP网络模型和网络包的封装原理后,你就很容易想到,Linux内核中的网络栈,其实也类似于TCP/IP的四层结构。如下图所示,就是Linux通用网络栈的示意图;
从上到下来看这个网络栈,可以发现:
- 最上层的应用程序,需要通过系统调用,来和套接字接口进行交互;
- 套接字的下面,就是前面提到的传输层、网络层和网络接口层;
- 最底层,就是网卡驱动程序以及物理网卡设备;
网卡是发送和接收网络包的基本设备,在系统的启动过程中,网卡通过内核中的网卡驱动程序注册到系统中。而在网络收发过程中,内核通过中断跟网卡进行交互;
结合到前面提到的Linux网络栈,可以看出,网络包的处理非常复杂。所以网卡硬中断只处理最核心的网卡数据读取或者发送,而协议栈中的大部分逻辑,都会放到软中断中处理;
Linux网络收发流程
了解Linux网络栈后,再来看看,Linux到底是怎么收发网络包的?
网络包的接收流程
|
|
|
|
网络包的发送流程
https://segmentfault.com/a/1190000008926093
|
|
Linux网络性能
了解了Linux网络的基本原理和收发流程后,我们应该如何去观察网络的性能情况。具体而言,哪些指标又是可以用来衡量Linux的网络性能呢?
性能指标
性能指标:带宽、吞吐量、延时、PPS、网络的可用性(网络能否正常通信)、并发连接数(TCP 连接数量)、丢包率(丢包百分比)、重传率(重新传输的网络包比例)
- 带宽,表示链路的最大传输速率,单位通常为 b/s (比特 / 秒)。
- 吞吐量,表示单位时间内成功传输的数据量,单位通常为 b/s(比特 / 秒)或者 B/s(字节 / 秒)。吞吐量受带宽限制,而吞吐量 / 带宽,也就是该网络的使用率。
- 延时,表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。在不同场景中,这一指标可能会有不同含义。比如,它可以表示,建立连接需要的时间(比如 TCP 握手延时),或一个数据包往返所需的时间(比如 RTT)。
- PPS,是 Packet Per Second(包 / 秒)的缩写,表示以网络包为单位的传输速率。PPS 通常用来评估网络的转发能力,比如硬件交换机,通常可以达到线性转发(即 PPS 可以达到或者接近理论最大值)。而基于 Linux 服务器的转发,则容易受网络包大小的影响。
除了这些指标,网络的可用性(网络能否正常通信)、并发连接数(TCP 连接数量)、丢包率(丢包百分比)、重传率(重新传输的网络包比例)等也是常用的性能指标。
网络配置
分析网络问题的第一步,通常是查看网络接口的配置和状态。可以使用ifconfig或者ip命令,来查看网络的配置;个人更推荐使用ip工具,因为它提供了更丰富的功能和更易用的接口;
ifconfig eth0
ip -s addr show dev eth0
ifconfig
和ip
分别属于软件包net-tools和iproute2, iproute2是net-tools的下一代。通常情况下它们会在发行版中默认安装。如果你找不到ifconfig
或者ip
命令, 可以安装这两个软件包;
以网络接口eth0为例,可以运行下面的两个命令,查看它的配置和状态:
- 第一,网络接口的状态标志。ifconfig 输出中的 RUNNING ,或 ip 输出中的 LOWER_UP ,都表示物理网络是连通的,即网卡已经连接到了交换机或者路由器中。如果你看不到它们,通常表示网线被拔掉了。
- 第二,MTU 的大小。MTU 默认大小是 1500,根据网络架构的不同(比如是否使用了 VXLAN 等叠加网络),你可能需要调大或者调小 MTU 的数值。
- 第三,网络接口的 IP 地址、子网以及 MAC 地址。这些都是保障网络功能正常工作所必需的,你需要确保配置正确。
- 第四,网络收发的字节数、包数、错误数以及丢包情况,特别是 TX 和 RX 部分的 errors、dropped、overruns、carrier 以及 collisions 等指标不为 0 时,通常表示出现了网络 I/O 问题。其中:
- errors 表示发生错误的数据包数,比如校验错误、帧同步错误等;
- dropped 表示丢弃的数据包数,即数据包已经收到了 Ring Buffer,但因为内存不足等原因丢包;
- overruns 表示超限数据包数,即网络 I/O 速度过快,导致 Ring Buffer 中的数据包来不及处理(队列满)而导致的丢包;
- carrier 表示发生 carrirer 错误的数据包数,比如双工模式不匹配、物理电缆出现问题等;
- collisions 表示碰撞数据包数。
套接字信息
ifconfig和ip只显示了网络接口收发数据包的统计信息,但在实际的性能问题中,网络协议栈中的统计信息,我们也需要关注。可以用netstat或者ss, 来查看套接字、网络栈、网络接口以及路由表的信息;
个人更推荐,使用ss来查询网络的连接信息,因此它比netstat提供了更好的性能(速度更快);
套接字信息:netstat -nlp、ss -ltnp
;
-l 表示只显示前面3行
-n 表示显示数字地址和端口(而不是名字)
-p 表示显示进程信息
协议栈统计信息:netstat -s、ss -s
-l 表示只显示监听套接字
-t 表示只显示TCP套接字
-n 表示显示数字地址和端口(而不是名字)
-p 表示显示进程信息
netstat和ss的输出也是类似的,都显示了套接字的状态、接收队列、发送队列、本地地址、远端地址、进程PID和进程名称等。
其中,接收队列(Recv-Q)和发送队列(Send-Q)需要你特别关注,它们通常应该是 0。当你发现它们不是 0 时,说明有网络包的堆积发生。也要注意到在不同套接字状态下,它们的含义不同。
当套接字处于连接状态(Established)时,
- Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。
- 而 Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)。
当套接字处于监听状态(Listening)时,
- Recv-Q 表示syn backlog的当前值。
- 而 Send-Q 表示最大的syn backlog值。
而syn backlog是TCP协议栈中的半连接队列长度,相应的也有一个全连接队列(accept queue), 它们都是维护TCP状态的重要机制;
顾名思义,所谓半连接,就是还没有完成TCP三次握手的连接,连接只进行了一半,而服务器收到了客户端的SYN包后,就会把这个连接放到半连接队列中,然后再向客户端发送SYN+ACK包;
而全连接,则是服务器收到了客户端的ACK,完成了TCP三次握手,然后就会把这个连接挪到全连接队列中。这些全连接中的套接字,还需要被accept()系统调用取走,这样,服务器就可以真正处理客户端的请求了;
协议栈统计信息
类似地,使用netstat或ss, 也可以查看协议栈的信息;
|
|
这些协议栈的统计信息都很直观, ss
只显示已经连接、关闭、孤儿套接字等简要统计,而 netstat 则提供的是更详细的网络协议栈信息, 比如上面的netstat的输出示例, 就展示了TCP协议的主动连接、被动连接、失败重试、发送和接收的分段数量等各种信息。
套接字信息:netstat -nlp、ss -ltnp
;协议栈统计信息:netstat -s、ss -s
网络吞吐和PPS
接下来,我们来看看如何查看系统当前的网络吞吐量和PPS,在这里,使用之前使用过的sar。
给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 可以用 ethtool 来查询,它的单位通常是 Gb/s 或者 Mb/s,不过注意这里小写字母 b ,表示比特而不是字节。我们通常提到的千兆网卡、万兆网卡等,单位也都是比特。
连通性和延时
通常使用ping, 来测试远程主机的联通性和延时,而这是基于ICMP协议。比如,执行下面的命令,可以测试到本机到120.229.79.95这个IP地址的连通性和延时:
|
|
ping的输出,可以分为两部分;
- 第一部分,是每个ICMP请求的信息,包括ICMP序列号(icmp_seq)、TTL(生存时间,跳数)以及往返延时;
- 第二部分,则是三次ICMP请求的汇总;