Linux网络性能指标
性能指标
- 带宽,表示链路的最大传输速率,单位通常为 b/s(比特/秒)
- 吞吐量,表示单位时间内成功传输的数据量,单位通常为 b/s(比特/秒)或者 B/s(字节/秒)。吞吐量受带宽限制,而吞吐量/带宽,也就是该网络的使用率
- 延时,表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。在不同场景中,这一指标可能会有不同的涵义。比如,它可以表示,建立连接需要的时间(比如 TCP 握手延时),或一个数据包往返所需的时间(比如 RTT)
- PSS,是 Packet Per Second(包/秒)的缩写,表示以网络包为单位的传输速率。PSS 通常用来评估网络的转发能力,比如硬件交换机,通常可以达到线性转发(即 PPS 可以达到或者接近理论最大值)。而基于 Linux 服务器的转发,则容易受网络包大小的影响
另外,网络的可用性(网络能否正常通信)、并发连接数(TCP 连接数量)、丢包率(丢包百分比)、重传率(重新传输的网络包比例)等也是常用的性能指标。
网络配置
使用命令 ifconfig 或者 ip 查看
1 | $ ifconfig eth1 |
第一,网络接口的状态标志。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 表示碰撞数据包数
嵌套字信息
使用 netstat 或 ss 来表示嵌套字、网络栈、网络接口以及路由表的信息
1 | $ netstat -nlp | head -n 3 |
其中,接收队列(Recv-Q)和发送队列(Send-Q)需要关注,它们通常是 0。当你发现它们不是 0 时,说明有网络包的堆积发生
当嵌套字处于连接状态(Established)时,
- Recv-Q 表示嵌套字缓冲还没有被应用程序取走的字节数(即接收队列长度)
- Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)
当嵌套字处于监听状态(Listening)时,
- Recv-Q 表示当前全连接队列(accept 队列)长度
- Send-Q 表示全连接队列的最大长度
协议栈统计信息
使用 netstat 或 ss 命令
1 | $ netstat -s |
网络吞吐 和 PPS
使用 sar 命令,加上 -n 参数,可以查看网络的统计信息,比如网络接口(DEV)、网络接口错误(EDEV)、TCP、UDP、ICMP 等
1 | $ sar -n DEV 1 |
- rxpck/s 和 txpck/s 分别是接收和发送的 PPS,单位为包/秒
- rxkB/s 和 txkB/s 分别是接收和发送的吞吐量,单位是 KB/s
- rxcmp/s 和 txcmp/s 分别是接收和发送的压缩数据包数,单位是包/秒
带宽可以用 ethtool 来查询,它的单位通常是 Gb/s 或者 Mb/s(千兆网卡或者万兆网卡的单位都是 bit)
1 | $ ethtool enp4s0f0 | grep Speed |
连通性和延时
使用命令 ping,来测试远程主机的连通性和延时(基于 ICMP 协议)
如下,测试本机到 baidu.com 这个地址的连通性和延时
1 | $ ping -c3 baidu.com |
ping 的输出,可以分为两部分:
- 每个 ICMP 请求的信息,包括 ICMP 序列号(icmp_seq)、TTL(生存时间,或者跳数)以及往返延时
- 三次 ICMP 请求的汇总
C10K和C100K问题
C10K
C10K 代表同时处理 10000 个请求
从资源上来说,对 2GB 内存和千兆网卡的服务器来说,同时处理 10000 个请求,只要每个请求处理占用不到 200KB(2GB/10000)的内存和 100Kbit(1000Mbit/10000)的网络带宽就可以。
从软件上来看,主要是网络 I/O 模型的问题,在 C10K 之前,Linux 主要是同步阻塞的方式,每个请求都分配一个进程或者线程,而 10000 个进程或者线程的调度、上下文切换和内存,都可能成为瓶颈。
需要解决的问题:
- 怎样在一个线程内处理多个请求,也就是要在一个线程内响应多个网络 I/O?
I/O 模型优化
异步、非阻塞 I/O 的思路:I/O 多路复用
两种 I/O 时间通知的方式:水平触发和边缘触发
水平触发:只要文件描述符可以非阻塞地执行 I/O,就会触发通知。也就是说,应用程序可以随时检查文件描述符地状态,然后再根据状态,进行 I/O 操作。
边缘触发:只有在文件描述符的状态发生改变(也就是 I/O 请求达到)时,才会发送一次通知。这时候,应用程序需要尽可能多地执行 I/O,知道无法继续读写,才可以停止。如果 I/O 没执行完,或者因为某种原因没来得及处理,那么这次通知也就丢失了
- 第一种,使用非阻塞 I/O 和水平触发通知,比如使用 select 或者 poll
- 第二种,使用非阻塞 I/O 和边缘触发通知,比如 epoll(在 select 和 poll 基础上进行优化)
- 第三种,使用异步 I/O(Asynchronous I/O,简称为 AIO)
工作模型优化
I/O 多路复用有两种主要的工作模式:
第一种:主进程 + 多个 worker 子进程(比如 nginx),主要流程是:
- 主进程执行 bind() + listen() 后,创建多个子进程;
- 在每个子进程中,都通过 accept() 或 epoll_wait() ,来处理相同的套接字