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 收包
网卡 DMA(可以理解为直接读 I/O 到内存,减少 cpu 的介入) 把收到的网络帧放到收包队列(在内存中),硬中断通知中断程序处理
中断程序分配一个叫 sk_buff 的 socket buffer数据结构,拷贝网络帧到这个结构,然后软中断通知内核来处理网络帧了
内核获得网络帧后,就跟剥洋葱一样,一层层的剥开
数据链路层:检查报文,去掉帧头帧尾,看 ip 层是什么报文,如果是 6 就交给上层 ipv6 对应的协议处理,如果是 4 就交给 4
IP层: 判断网络包走向,是转发还是交给上层处理。比如 iptable 中的 forward 链就是转发链,如果要交给上层则确定上层协议是 tcp/udp 等,并去掉头尾
传输层:根据 tcp/udp 头,根据四元组找到对应的 socket,然后把数据拷贝到 socket 里
应用层:操作 socket 读取数据
0x0102 发包
应用层:通过系统调用,把数据包写到 socket 里
传输层:增加 tcp 头
ip 层:增加 ip 头,路由寻址,找到下一跳,根据 MTU 分片
数据链路层:根据 mac 地址寻址,找到下一跳的 mac,增加头尾,放到发包队列,软中断通知中断程序驱动
物理层:驱动程序 DMA 读取网络帧,通过物理网卡通过脉冲信号或光信号发包
0x0110 性能指标
带宽: 最大传输速率
吞吐量: 单位时间内传输数据量
延时: 发出请求到收到响应的时间
PPS: Packet Per Second,每秒发包量
网络可用性
并发数
丢包率
重传率
0x02 网络 I/O 原理
I/O通知方式:
水平触发: 应用程序 可以随时读fd
边缘触发: 只能在 fd 发生变化是才可以读
I/O 多路复用:
非阻塞 I/O 水平触发:
select: fd 数量有限制,轮询检查 fd。O(n)
poll: 无 fd 限制,轮询检查fd。O(n)
非阻塞 I/O边缘触发:
epoll: 内核红黑树管理 fd,事件驱动
异步 I/O:异步通知,通过信号或者回调
工作模型:
主进程 + 多个 workder 子进程:nginx
主 bind + listen 初始化 socket
子 accept + epoll_wait 都绑定这个 socket
有惊群问题,需要锁机制来确保只有一个 worker 节点唤醒
多进程监听同个端口,需要开启端口重用,等于是内核将该端口的请求分发到不同的 worker 进程上
高性能网络模型:
DPDK:跳过内核网络协议栈,直接用户态轮询
XDP:在内核网络协议栈前处理网络包
0x03 网络优化方式
网络也是分层的,不同的层有不同的优化手段
应用层:
优化 I/O 模型
长连接
DNS 缓存
socket: 调整内核参数
传输层: 优化传输层协议
网络层:路由等
链路层:收发包
基本上就是:
先查看一波网络性能指标: sar,ip,ss 等工具
tcpdump,wireshark抓包,分析异常网络流量情况
调整对应内核参数,基本上可以解决 80% 的问题
0x04 总结
虽然我是计算机网络专业毕业,但是想一篇文章写完所有的优化点还是太难了,毕竟计算机网络是一门单独的学科,只能把简单地把网络原理和优化思路记录下,在实际使用的时候还是要根据具体的情况来排查问题,另外有很多细节我比较熟悉,觉得太简单了就不一一记录了。