0x00 前言

在上篇学习笔记中我总结了 I/O 学习笔记,本篇会总结 Linux 网络的性能优化学习笔记。在上篇文章中我们提到了说磁盘 I/O 就是计算机的最终数据持久化的地方,如下图在冯诺依曼架构中也就是对应输入输出的设备,而存储器则就是内存。
冯诺依曼架构
在单台计算机的时候,可以说计算过程就是先从输入设备获取指令和数据,在经过运算器的处理后,最终将运算结果输出到输出设备上,而 I/O 的产生则是在和输入和输出设备打交道了。如果是多台计算机,计算机之间如何互相沟通呢?那么就需要通过网络来连接各个计算机了。

在计算机之间的沟通,无非也就是指令和数据就是这两种。比如我访问一个 Web 网站,本质上不就是从网站服务器上获取数据吗?又比如在分布式的计算集群中,master 节点向 slave 节点下发计算任务,这就输出指令呀。是不是感觉网络和磁盘 I/O 很相似?没错,他们在冯诺依曼结果中都是作为输入输出设备,所以他们有很多相似之处,比如在 Linux 系统中,网络 I/O 的操作和文件操作很相似,但网络的层次比文件系统 I/O 更多,所以会更加复杂,一篇文章无法概述,本笔记只是记录一些要点。

0x01 网络基础

0x0100 收发流程

网络和文件系统一样,为了解耦异构设备,都是分层的,分层在网络中主要分为 OSI 和 TCP/IP 模型。如下所示

而自然和磁盘一样,Linux 内核在处理网络包的时候对不同的层会进行不同的处理。

  • 应用层: 内核态系统调用,通过 socket 来发包
  • 传输层: 对应用层的包进行封装,是五元组的抽象
  • IP层: IP 报文发送,路由
  • 链路层: 封帧,mac 寻址
  • 网卡驱动: 收发包,网卡驱动收发包会通过硬中断和内核交互

0x0101 收包

  1. 网卡 DMA(可以理解为直接读 I/O 到内存,减少 cpu 的介入) 把收到的网络帧放到收包队列(在内存中),硬中断通知中断程序处理
  2. 中断程序分配一个叫 sk_buff 的 socket buffer数据结构,拷贝网络帧到这个结构,然后软中断通知内核来处理网络帧了
  3. 内核获得网络帧后,就跟剥洋葱一样,一层层的剥开
    1. 数据链路层:检查报文,去掉帧头帧尾,看 ip 层是什么报文,如果是 6 就交给上层 ipv6 对应的协议处理,如果是 4 就交给 4
    2. IP层: 判断网络包走向,是转发还是交给上层处理。比如 iptable 中的 forward 链就是转发链,如果要交给上层则确定上层协议是 tcp/udp 等,并去掉头尾
    3. 传输层:根据 tcp/udp 头,根据四元组找到对应的 socket,然后把数据拷贝到 socket 里
    4. 应用层:操作 socket 读取数据

0x0102 发包

  1. 应用层:通过系统调用,把数据包写到 socket 里
  2. 传输层:增加 tcp 头
  3. ip 层:增加 ip 头,路由寻址,找到下一跳,根据 MTU 分片
  4. 数据链路层:根据 mac 地址寻址,找到下一跳的 mac,增加头尾,放到发包队列,软中断通知中断程序驱动
  5. 物理层:驱动程序 DMA 读取网络帧,通过物理网卡通过脉冲信号或光信号发包

0x0110 性能指标

  1. 带宽: 最大传输速率
  2. 吞吐量: 单位时间内传输数据量
  3. 延时: 发出请求到收到响应的时间
  4. PPS: Packet Per Second,每秒发包量
  5. 网络可用性
  6. 并发数
  7. 丢包率
  8. 重传率

0x02 网络 I/O 原理

I/O通知方式:

  1. 水平触发: 应用程序 可以随时读fd
  2. 边缘触发: 只能在 fd 发生变化是才可以读

I/O 多路复用:

  1. 非阻塞 I/O 水平触发:
    • select: fd 数量有限制,轮询检查 fd。O(n)
    • poll: 无 fd 限制,轮询检查fd。O(n)
  2. 非阻塞 I/O边缘触发:
    • epoll: 内核红黑树管理 fd,事件驱动
  3. 异步 I/O:异步通知,通过信号或者回调

工作模型:

  • 主进程 + 多个 workder 子进程:nginx
    • 主 bind + listen 初始化 socket
    • 子 accept + epoll_wait 都绑定这个 socket
    • 有惊群问题,需要锁机制来确保只有一个 worker 节点唤醒
  • 多进程监听同个端口,需要开启端口重用,等于是内核将该端口的请求分发到不同的 worker 进程上

高性能网络模型:

  • DPDK:跳过内核网络协议栈,直接用户态轮询
  • XDP:在内核网络协议栈前处理网络包

0x03 网络优化方式

网络也是分层的,不同的层有不同的优化手段

  1. 应用层:
    • 优化 I/O 模型
    • 长连接
    • DNS 缓存
  2. socket: 调整内核参数
  3. 传输层: 优化传输层协议
  4. 网络层:路由等
  5. 链路层:收发包

基本上就是:

  1. 先查看一波网络性能指标: sar,ip,ss 等工具
  2. tcpdump,wireshark抓包,分析异常网络流量情况
  3. 调整对应内核参数,基本上可以解决 80% 的问题

0x04 总结

虽然我是计算机网络专业毕业,但是想一篇文章写完所有的优化点还是太难了,毕竟计算机网络是一门单独的学科,只能把简单地把网络原理和优化思路记录下,在实际使用的时候还是要根据具体的情况来排查问题,另外有很多细节我比较熟悉,觉得太简单了就不一一记录了。