Linux性能优化
CPU
系统层面的一些优化手段:
- CPU 绑定:把进程绑定到一个或者多个 CPU 上,可以提高 CPU 缓存的命中率,减少跨 CPU 调度带来的上下文切换问题
- CPU 独占:跟 CPU 绑定类似,进一步将 CPU 分组,并通过 CPU 亲和性机制为其分配进程。这样,这些 CPU 就由指定的进程独占,换句话说,不允许其他进程再来使用这些 CPU
- 优先级调整:使用 nice 调整进程的优先级,正值调低优先级,负值调高优先级。,适当降低非核心应用的优先级,增高核心应用的优先级,可以确保核心应用得到优先处理
- 为进程设置资源限制:使用 Linux cgroups 来设置进程的 CPU 使用上限,可以防止由于某个应用自身的问题,而耗尽系统资源
- NUMA(Non-Uniform Memory Access)优化:支持 NUMA 的处理器会被划分为多个 node,每个 node 都有自己的本地内存空间。NUMA 优化,其实就是让 CPU 尽可能只访问本地内存
- 中断负载均衡:无论是软中断还是硬中断,它们的中断处理程序都可能会耗费大量的 CPU。开启 irqbalance 服务或者配置 smp_affinity,就可以把中断处理过程自动负载均衡到多个 CPU 上。
平均负载
平均负载统计了这两种情况的进程:
- Linux 进程调度器中可运行队列(Running Queue)一段时间(1 分钟,5 分钟,15 分钟)的进程平均数
- Linux 进程调度器中休眠队列(Sleeping Queue)里的一段时间的 TASK_UNINTERRUPTIBLE 状态下的进程平均数
从上面两点可知,平均负载跟CPU 使用率没有直接关系
Load Average = 可运行队列进程平均数 + 休眠队列中不可打断的进程平均数
处于 D 状态(主要集中在 disk I/O 的访问和信号量(Semaphore)锁的访问)的进程即休眠队列中不可打断的进程过多就会增加负载,这是性能下降的表现
在只有 2 个 CPU 的系统上,平均负载为 2 代表所有的 CPU 都刚好被完全占用,大量 IO 会导致平均负载变高,但 CPU 使用率却不一定高
top 命令展示的三个值,分别为 1 分钟、5 分钟、15 分钟内的平均负载
上下文切换
vmstat 可以查看系统整体上下文切换情况:
- cs(context switch)是每秒上下文切换的次数
- in(interrupt)则是每秒中断的次数
- r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数
- b(Blocked)则是处于不可中断睡眠状态的进程数
pidstat 则可以查看单个进程的上下文切换情况,cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数,另一个则是 nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数
- 自愿上下文切换:是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。
- 非自愿上下文切换:是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换
中断处理也需要上下文切换,可以通过 /proc/interrupts
查看中断最多的类型
CPU使用率
通过 top 可以查看 CPU 在不同场景下的运行时间:
- user(通常缩写为 us),代表用户态 CPU 时间。注它不包括下面的 nice 时间,但包括了 guest 时间
- nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低
- system(通常缩写为 sys),代表内核态 CPU 时间
- idle(通常缩写为 id),代表空闲时间。它不包括等待 I/O 的时间(iowait)
- iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间,iowait 升高并不能证明等待I/O的进程数量增多了,也不能证明等待I/O的总时间增加了,还需检查I/O量有没有明显增加,avserv/avwait/avque等指标有没有明显增大
- irq(通常缩写为 hi),代表处理硬中断的 CPU 时间
- softirq(通常缩写为 si),代表处理软中断的 CPU 时间
- steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间
- guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间
- guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间
为了在具体进程找到占用 CPU 时钟最多的函数或者指令,可以通过 perf top 查看函数名或函数地址
软中断
Linux 将中断处理过程分成了两个阶段,也就是上半部和下半部:
- 上半部用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作
- 下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行
网卡接收到数据包后,会通过硬件中断的方式通知内核有新的数据到了对上半部来说,既然是快速处理,其实就是要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态(表示数据已经读好了),最后再发送一个软中断信号,通知下半部做进一步的处理下半部被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序
上半部会打断 CPU 正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号”
- /proc/softirqs 提供了软中断的运行情况
- /proc/interrupts 提供了硬中断的运行情况
当软中断事件的频率过高时,内核线程也会因为 CPU 使用率过高而导致软中断处理不及时,进而引发网络收发延迟、调度缓慢等性能问题
内存
通过 free 可以查看整体内存使用情况:
- total 是总内存大小
- used 是已使用内存的大小,包含了共享内存
- free 是未使用内存的大小
- shared 是共享内存的大小
- buff/cache 是缓存和缓冲区的大小
- available 是新进程可用内存的大小,不仅包含未使用内存,还包括了可回收的缓存
通过 top 查看具体进程的内存情况:
- VIRT 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内
- RES 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存
- SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等
- %MEM 是进程使用物理内存占系统总内存的百分比
mindmap 内存性能指标 系统内存指标 已用内存 剩余内存 可用内存 缺页异常 主缺页异常 次缺页异常 缓存/缓冲区 使用量 命中率 Slabs 进程内存指标 虚拟内存(VSS) 常驻内存(RSS) 按比例分配共享内存后的物理内存(PSS) 独占内存(USS) 共享内存 SWAP内存 缺页异常 主缺页异常 次缺页异常 SWAP 已用空间 剩余空间 换入速度 换出速度
系统层面的优化手段:
- 最好禁止 Swap。如果必须开启 Swap,降低 swappiness 的值,减少内存回收时 Swap 的使用倾向
- 减少内存的动态分配。比如,可以使用内存池、大页(HugePage)等
- 尽量使用缓存和缓冲区来访问数据。比如,可以使用堆栈明确声明内存空间,来存储需要缓存的数据;或者用 Redis 这类的外部缓存组件,优化数据的访问
- 使用 cgroups 等方式限制进程的内存使用情况。这样,可以确保系统内存不会被异常进程耗尽
- 通过 /proc/pid/oom_adj ,调整核心应用的 oom_score。这样,可以保证即使内存紧张,核心应用也不会被 OOM 杀死
分配与回收
不同内存分配器(TCMalloc、Ptmalloc2)适合不同的场景(分配单元大小、是否并发环境),栈上分配的内存相比堆内分配的内存,申请效率高,回收也容易
malloc()
对小块内存(小于 128K),C 标准库使用 brk() 来分配,也就是通过移动堆顶的位置来分配内存。这些内存释放后并不会立刻归还系统,而是被缓存起来,这样就可以重复使用,brk() 方式的缓存,可以减少缺页异常的发生,提高内存访问效率
而大块内存(大于 128K),则直接使用内存映射 mmap() 来分配,也就是在文件映射段找一块空闲内存分配出去
当进程通过 malloc() 申请内存后,内存并不会立即分配,而是在首次访问时,才通过缺页异常陷入内核中分配内存
buff/cache
buff 是对磁盘读写数据的缓存,而 cache 是对文件读写数据的缓存
在读写普通文件时,会经过文件系统,由文件系统负责与磁盘交互;而读写磁盘或者分区时,就会跳过文件系统,也就是所谓的裸I/O
swap
swap 是一种虚拟内存交换到磁盘的机制
有一个专门的内核线程用来定期回收内存,也就是 kswapd0
kswapd0 定义了三个内存阈值:页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)
- 剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存
- 剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩余内存大于高阈值为止
- 剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求
- 剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力
NUMA 下,多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间,每个 Node 会有自己的 swap
Linux 提供了一个 /proc/sys/vm/swappiness 选项,用来调整使用 Swap 的积极程度:swappiness 的范围是 0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页
- 对文件页的回收,是直接回收缓存,或者把脏页写回磁盘后再回收
- 对匿名页的回收,是通过 Swap 机制,把它们写入磁盘后再释放内存
IO
mindmap IO 性能指标 磁盘 使用率 IOPS 吞吐量 响应时间 缓冲区 相关因素 读写类型(如顺序还是随机) 读写比例 读写大小 存储类型(如RAID级别、本地还是网络) 文件系统 存储空间容量、使用量以及剩余空间 索引节点容量、使用量以及剩余量 缓存 页缓存 目录项缓存 索引节点缓存 具体文件系统缓存(如ext4的缓存) IOPS(文件IO) 响应时间(延迟) 吞吐量(B/s)
一些优化手段:
- 应用层
- 追加写代替随机写
- 缓存 I/O
- 自建应用程序内部缓存
- mmap代替read/write
- 合并写请求: 在同步写场景中,尽量将写请求合并,可用fsync()替代O_SYNC,提高效率。
- 使用cgroups的I/O子系统
- ionice调整I/O调度优先级: 在使用CFQ调度器时,使用ionice提高核心应用的I/O优先级
- 大文件交给异步 IO 和直接 IO 处理,小文件交给零拷贝处理:大文件使用异步 IO 允许在数据读取或写入的同时进行其他操作,直接 IO 绕过了操作系统的缓存机制可提高并发性能和数据传输效率,小文件使用零拷贝可减少内存拷贝次数。
- PageCache 技术减少磁盘的工作量:PageCache 缓存最近访问的文件数据,减少磁盘读取次数,提高访问速度。
- 文件系统层
- 选择适合负载场景的文件系统:如 xfs 支持更大的磁盘分区和文件数量,但无法收缩
- 优化文件系统配置选项: 在选定文件系统后,进一步优化其配置选项,包括文件系统特性(如 ext_attr、dir_index)、日志模式(如 journal、ordered、writeback)、挂载选项(如 noatime)
- 优化文件系统缓存: 如优化 pdflush 脏页的刷新频率(dirty_expire_centisecs 和 dirty_writeback_centisecs)、脏页的限额(dirty_background_ratio 和 dirty_ratio),以及内核回收目录项缓存和索引节点缓存的倾向(vfs_cache_pressure)
- 使用内存文件系统 tmpfs
- 磁盘层
- 使用性能更好的磁盘
- 使用RAID
- 选择适合的I/O调度算法: SSD和虚拟机中的磁盘通常使用 noop 调度算法,而数据库应用更适合使用 deadline 算法
- 进行磁盘级别的隔离: 为I/O压力重的应用配置单独的磁盘,提高性能。
- 增大磁盘的预读数据: 在顺序读较多的场景中,增大磁盘的预读数据,可以通过调整内核选项或使用 blockdev 工具设置来实现。
- 优化内核块设备I/O选项: 调整内核块设备I/O的选项,例如调整磁盘队列的长度,适当增大队列长度可以提升磁盘的吞吐量,但可能导致I/O延迟增大。
- 注意硬件错误: 硬件错误可能导致磁盘性能急剧下降
容量
Linux 通过 inode 记录文件的元数据
可以通过 df -i 查看 inode 所占用的空间
缓存
内核使用 Slab 机制,管理目录项和 inode 的缓存,可以通过 /proc/slabinfo 查看这个缓存
IO栈
由上到下分为三个层次,分别是:
- 文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口对下会通过通用块层,来存储和管理磁盘数据
- 通用块层,包括块设备 I/O 队列和 I/O 调度器。它会对文件系统的 I/O 请求进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层
- NONE 调度算法:不使用任何 I/O 调度器,对文件系统和应用程序的 I/O 其实不做任何处理,常用在虚拟机中
- NOOP:是一个先入先出的队列,只做一些最基本的请求合并,常用于 SSD 磁盘
- CFQ:完全公平调度器,为每个进程维护了一个 I/O 调度队列,并按照时间片来均匀分布每个进程的 I/O 请求
- DeadLine:别为读、写请求创建了不同的 I/O 队列,可以提高机械磁盘的吞吐量,并确保达到最终期限(deadline)的请求被优先处理,多用在 I/O 压力比较重的场景,比如数据库
- 设备层,包括存储设备和相应的驱动程序,负责最终物理设备的 I/O 操作
磁盘性能指标
- 使用率,是指磁盘处理 I/O 的时间百分比。过高的使用率(比如超过 80%),通常意味着磁盘 I/O 存在性能瓶颈
- 饱和度,是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求
- IOPS(Input/Output Per Second),是指每秒的 I/O 请求数
- 吞吐量,是指每秒的 I/O 请求大小
- 响应时间,是指 I/O 请求从发出到收到响应的间隔时间
在数据库、大量小文件等这类随机读写比较多的场景中,IOPS 更能反映系统的整体性能;而在多媒体等顺序读写较多的场景中,吞吐量才更能反映系统的整体性能
网络
网络包的接收流程:当一个网络帧到达网卡后,网卡会通过 DMA 方式,把这个网络包放到收包队列中,通过硬中断告诉中断处理程序已经收到了网络包,接着,网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到 sk_buff 缓冲区中;然后再通过软中断,通知内核收到了新的网络帧,内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧
网络包发送流程:内核协议栈处理过的网络包被放到发包队列后,会有软中断通知驱动程序发包队列中有新的网络帧需要发送。驱动程序通过 DMA ,从发包队列中读出网络帧,并通过物理网卡把它发送出去
- 收包队列与发包队列的内存都属于网卡设备驱动的范围
- sk_buff 缓冲区,是一个维护网络帧结构的双向链表,链表中的每一个元素都是一个网络帧
- 还有一个是 socket 的读写缓冲区
性能指标
通过 ifconfig 可以看到网卡网络收发的字节数、包数、错误数以及丢包情况:
- errors 表示发生错误的数据包数,比如校验错误、帧同步错误等
- dropped 表示丢弃的数据包数,即数据包已经收到了 Ring Buffer,但因为内存不足等原因丢包
- overruns 表示超限数据包数,即网络 I/O 速度过快,导致 Ring Buffer 中的数据包来不及处理(队列满)而导致的丢包
- carrier 表示发生 carrirer 错误的数据包数,比如双工模式不匹配、物理电缆出现问题等
- collisions 表示碰撞数据包数
netstat 可以看到套接字的接收队列(Recv-Q)和发送队列(Send-Q)
当套接字处于连接状态(Established)时,Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。而 Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)。
当套接字处于监听状态(Listening)时,Recv-Q 表示全连接队列的长度。而 Send-Q 表示全连接队列的最大长度。全连接是指服务器收到了客户端的 ACK,完成了 TCP 三次握手,然后就会把这个连接挪到全连接队列中,半连接是指还没有完成 TCP 三次握手的连接
netstat -s
可以查看协议栈各层的统计信息
工作模型
主进程 + 多个 worker 子进程:主进程执行 bind() + listen() 后,创建多个子进程;然后在每个子进程中,都通过 accept() 或 epoll_wait() ,来处理相同的套接字
监听到相同端口的多进程模型:所有的进程都监听相同的接口,并且开启 SO_REUSEPORT 选项,由内核负责将请求负载均衡到这些监听进程中去
NAT
NAT 基于 Linux 内核的 conntrack 连接跟踪机制来实现,Linux 内核需要为 NAT 维护状态,维护状态也带来了很高的性能成本
传输层
握手优化
- tcp_syn_retries:控制SYN重传次数。通过调整此参数,可以避免在网络状况较差的情况下过多地重传SYN报文,减少握手过程的延迟。
- tcp_max_syn_backlog:调整SYN半连接队列的长度。根据netstat -s的统计结果,判断队列长度是否合适。通过调整此参数,可以防止SYN队列溢出,确保连接建立成功。
- tcp_synack_retries:控制服务器回复SYN+ACK报文的重试次数。在网络稳定的情况下,适当减小此参数的值,可以减少不必要的重试,提高握手的效率。
- tcp_syncookies:设置为1以启用SYN cookie功能。在遭受SYN洪泛攻击时,当SYN队列满后,启用syncookie可以确保连接成功建立,提高系统的抗攻击能力。
- tcp_abort_on_overflow:通过向客户端发送RST报文通知连接建立失败,防止accept队列溢出。当accept队列溢出时,默认系统会丢弃ACK报文。调整此参数,可以在队列溢出时采取更明确的处理方式,提高系统的稳定性。
- backlog参数和somaxconn系统参数:通过调整listen函数的backlog参数和系统的somaxconn参数,可以提高accept队列的上限。这对于处理大量连接请求时非常有用,确保能够容纳更多的连接并提高系统的扩展性和性能
---title: 使用TFO(TCP Fast Open )减少一轮RTT---sequenceDiagram participant Client as 客户端 participant Server as 服务器 Client->>Server: SYN (请求 TFO 功能) Note over Server: 生成加密的 Cookie Server-->>Client: SYN+ACK (带加密的 Cookie) Note over Client: 缓存 Cookie Client->>Server: SYN+Data (携带请求数据和缓存的 Cookie) Server-->>Client: ACK+Data (携带响应数据)
挥手优化
- tcp_orphan_retries:允许在tcp_orphan_retries次数内重发FIN报文。该参数控制了主动方在处理丢包情况时的重传次数。通过适当调整此参数,可以减少因丢包而导致挥手过程延迟的情况,从而优化性能。2.tcp_fin_timeout:定义了在FIN_WAIT2状态下,在tcp_fin_timeout秒内没有收到对方的FIN报文时,连接直接关闭。调整此参数可以控制在没有收到对方FIN报文时的等待时间,避免无效等待,提高挥手的效率。
- tcp_max_orphans:定义了最大孤儿连接的数量。孤儿连接指的是关闭连接时对方没有收到FIN报文的连接。通过设置该参数,可以限制系统中孤儿连接的数量,防止资源被过多的孤儿连接占用。
- tcp_max_tw_buckets:定义了最大TIME_WAIT状态的数量。TIME_WAIT状态是指在挥手过程中进入的状态,持续一段时间以确保网络中的延迟数据段被处理完毕。通过设置该参数,可以限制系统中TIME_WAIT状态的数量,避免占用过多的资源。
- tcp_tw_reuse和tcp_timestamps:设置tcp_tw_reuse为1,并启用tcp_timestamps,可以将TIME_WAIT状态的端口复用于作为客户端的新连接。这样可以提高端口的利用率,避免TIME_WAIT状态占用过多的资源,但同时有数据错乱的风险
缓冲区优化
- tcp_window_scaling:通过将tcp_window_scaling设置为1,在Linux下提升滑动窗口的上限。滑动窗口是控制TCP发送速度和接收方处理能力的重要参数。通过提高滑动窗口的上限,可以提高TCP的发送速度,同时兼顾接收方的处理能力,从而优化性能。
- tcp_mem:内核缓冲区大小的调节参考依据。内核缓冲区决定了滑动窗口的上限。为了避免过大的缓冲区减少并发连接数,应将缓冲区的上限设置为带宽时延积。tcp_mem参数提供了缓冲区大小的参考范围。
- Socket 的 SO_SNDBUF:发送缓冲区大小的调节功能。默认情况下,Linux会自动调节发送缓冲区的大小。通过适当调整SO_SNDBUF选项,可以对发送缓冲区大小进行手动设置,以满足带宽和时延积的要求。
- tcp_moderate_rcvbuf:接收缓冲区大小的调节功能。通过将tcp_moderate_rcvbuf设置为1,开启接收缓冲区的自动调节功能。根据tcp_mem参数的设置,系统可以根据网络状况和带宽时延积的要求自动调整接收缓冲区的大小,以优化性能
拥塞控制优化
- 连接建立成功后,拥塞控制算法就会发生作用,首先进入慢启动阶段。决定连接此时网速的是初始拥塞窗口,改它。通常,在带宽时延积较大的网络中,应当调高初始拥塞窗口
- 可以通过 tcp_congestion_control 配置以 BBR 算法为代表的测量型拥塞控制算法
TLS优化
- 对称加密算法:选择安全性高且性能好的对称加密算法,如AES-GCM,该算法能够充分利用多核CPU的并行计算能力
- 密钥协商算法:选择性能较好的密钥协商算法,如基于椭圆曲线的ECDH算法,尤其是X25519曲线。
- 会话复用和缓存:通过长连接复用会话,减少密钥协商次数,并使用会话缓存和会话票据。
- 升级到TLS1.3:提升握手速度(减少了一次RTT)和安全性,限制不安全算法,难以进行降级攻击
网络层
路由和转发的角度
- 在需要转发的服务器中,比如用作 NAT 网关的服务器,开启 IP 转发,即设置 net.ipv4.ip_forward = 1
- 调整数据包的生存周期 TTL,设置 net.ipv4.ip_default_ttl = 64。增大该值会降低系统性能
- 开启数据包的反向地址校验,设置 net.ipv4.conf.eth0.rp_filter = 1。可以防止 IP 欺骗,并减少伪造 IP 带来的 DDoS 问题
调整 MTU 大小:很多网络设备都支持巨帧,可以把 MTU 调大为 9000,提升网络吞吐量
为了避免 ICMP 主机探测、ICMP Flood 等各种网络问题:可以禁止 ICMP 协议,即设置 net.ipv4.icmp_echo_ignore_all = 1,还可以禁止广播 ICMP,即设置 net.ipv4.icmp_echo_ignore_broadcasts = 1
链路层
由于网卡收包后调用的中断处理程序(特别是软中断),需要消耗大量的 CPU。所以,将这些中断处理程序调度到不同的 CPU 上执行,就可以显著提高网络吞吐量
- 为网卡硬中断配置 CPU 亲和性(smp_affinity),或者开启 irqbalance 服务
- 开启 RPS(Receive Packet Steering)和 RFS(Receive Flow Steering),将应用程序和软中断的处理,调度到相同 CPU 上,这样就可以增加 CPU 缓存命中率
将原先内核中通过软件处理的功能卸载到网卡中,通过硬件来执行:
- TSO(TCP Segmentation Offload)和 UFO(UDP Fragmentation Offload):在 TCP/UDP 协议中直接发送大包;而 TCP 包的分段(按照 MSS 分段)和 UDP 的分片(按照 MTU 分片)功能,由网卡来完成
- GSO(Generic Segmentation Offload):在网卡不支持 TSO/UFO 时,将 TCP/UDP 包的分段,延迟到进入网卡前再执行。这样,不仅可以减少 CPU 的消耗,还可以在发生丢包时只重传分段后的包
- LRO(Large Receive Offload):在接收 TCP 分段包时,由网卡将其组装合并后,再交给上层网络处理。不过要注意,在需要 IP 转发的情况下,不能开启 LRO,因为如果多个包的头部信息不一致,LRO 合并会导致网络包的校验错误
- GRO(Generic Receive Offload):GRO 修复了 LRO 的缺陷,并且更为通用,同时支持 TCP 和 UDP
- RSS(Receive Side Scaling):也称为多队列接收,它基于硬件的多个接收队列,来分配网络接收进程,这样可以让多个 CPU 来处理接收到的网络包
- VXLAN 卸载:也就是让网卡来完成 VXLAN 的组包功能
对于网络接口本身:
- 开启网络接口的多队列功能,调度到不同 CPU 上执行,从而提升网络的吞吐量
- 增大网络接口的缓冲区大小,以及队列长度等,提升网络传输的吞吐量
- 使用 Traffic Control 工具,为不同网络流量配置 QoS
内核线程
Linux 在启动过程中 2 号进程为 kthreadd 进程,在内核态运行,用来管理内核线程
ps -f --ppid 2 -p 2
- kswapd0:用于内存回收
- kworker:用于执行内核工作队列,分为绑定 CPU (名称格式为 kworker/CPU:ID)和未绑定 CPU(名称格式为 kworker/uPOOL:ID)两类
- migration:在负载均衡过程中,把进程迁移到 CPU 上。每个 CPU 都有一个 migration 内核线程
- jbd2/sda1-8:jbd 是 Journaling Block Device 的缩写,用来为文件系统提供日志功能,以保证数据的完整性;名称中的 sda1-8,表示磁盘分区名称和设备号。每个使用了 ext4 文件系统的磁盘分区,都会有一个 jbd2 内核线程
- pdflush:用于将内存中的脏页(被修改过,但还未写入磁盘的文件页)写入磁盘(已经在 3.10 中合并入了 kworker 中)