说明
这篇文章前面相关内容都是小林coding文章中的, 我太菜了而且对这些了解也不深,借用大佬的描述来了解软中断。
软中断也是导致CPU利用率过高的一种原因,在高并发情况下,比如lvs和haproxy,这种代理的性能非常高,转发网络包的数据很快,但是有时候CPU没满,性能却上不去,这个就有可能是软中断导致的,因为有的机器软中断只会在其中几个核处理,当跑满这个CPU核时,系统已经没办法接收更多数据了,吞吐量也就上不去。
中断
在计算机中,中断是系统用来响应硬件设备请求的一种机制,操作系统收到硬件的中断请求,会打断正在执行的进程,然后调用内核中的中断处理程序来响应请求。
- 中断是一种异步的事件处理机制,可以提高系统的并发处理能力
由于中断处理程序会打断其他进程的运行,为了减少对正常进程运行调度的影响,中断处理程序就需要尽可能快地运行
而且,中断处理程序在响应中断时,可能还会「临时关闭中断」,这意味着,如果当前中断处理程序没有执行完之前,系统中其他的中断请求都无法被响应,也就说中断有可能会丢失,所以中断处理程序要短且快。
软中断
Linux 系统为了解决中断处理程序执行过长和中断丢失的问题,将中断过程分成了两个阶段,分别是「上半部和下半部分」。
- 上半部用来快速处理中断,一般会暂时关闭中断请求,主要负责处理跟硬件紧密相关或者时间敏感的事情。
- 下半部用来延迟处理上半部未完成的工作,一般以「内核线程」的方式运行。
网卡接收数据包
网卡收到网络包后,会通过硬件中断通知内核有新的数据到了,于是内核就会调用对应的中断处理程序来响应该事件,这个事件的处理也是会分成上半部和下半部。
上部分要做到快速处理,所以只要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态,比如把状态更新为表示数据已经读到内存中的状态值。
接着,内核会触发一个软中断,把一些处理比较耗时且复杂的事情,交给「软中断处理程序」去做,也就是中断的下半部,其主要是需要从内存中找到网络数据,再按照网络协议栈,对网络数据进行逐层解析和处理,最后把数据送给应用程序。
所以,中断处理程序的上部分和下半部可以理解为:
- 上半部直接处理硬件请求,也就是硬中断,主要是负责耗时短的工作,特点是快速执行;
- 下半部是由内核触发,也就说软中断,主要是负责上半部未完成的工作,通常都是耗时比较长的事情,特点是延迟执行;
还有一个区别,硬中断(上半部)是会打断 CPU 正在执行的任务,然后立即执行中断处理程序,而软中断(下半部)是以内核线程的方式执行,并且每一个 CPU 都对应一个软中断内核线程,名字通常为「ksoftirqd/CPU 编号」,比如 0 号 CPU 对应的软中断内核线程的名字是 ksoftirqd/0
不过,软中断不只是包括硬件设备中断处理程序的下半部,一些内核自定义事件也属于软中断,比如内核调度等、RCU 锁(内核里常用的一种锁)等。
排查软中断导致的性能问题
在Centos中可以使用cat /proc/softirqs这个命令查看软中断的运行情况
1 | [root@localhost ~]# cat /proc/softirqs |
- 每一个 CPU 都有自己对应的不同类型软中断的累计运行次数
- 第一列的内容,它是代表着软中断的类型,其中NET_RX 表示网络接收中断,NET_TX 表示网络发送中断。
- 从我这台服务器上可以看出CPU6的NET_RX次数很大,CPU7的NET_TX次数很大,这是因为我进行过多次压测,而这2个核就是在处理对应网卡的软中断。
使用命令cat /proc/interrupts 可以查看硬中断的运行情况。
还有最常用的命令 top 可以查看CPU的使用情况,运行top后按1就可以查看每一个cpu核的使用情况, 这是一个正在接收压力的服务器情况,可以看到8个核的利用率
1 | top - 18:27:09 up 100 days, 9:15, 1 user, load average: 1.11, 0.54, 0.47 |
其中
- us:用户空间占用CPU百分比(Host.cpu.user)
- sy:内核空间占用CPU百分比(Host.cpu.system)
- ni:用户进程空间内改变过优先级的进程占用CPU百分比
- id:空闲CPU百分比(Host.cpu.idle)
- wa:等待输入输出的CPU时间百分比
- hi:硬件中断
- si:软件中断
- st:实时
可以看到us sy每个核都有使用,但是使用率不高,而CPU6的si(软中断)很高,有50%多,这是因为发压的数据请求字节数很大,响应字节数很小,而上面我提过这台机器CPU6处理网络接收中断的,所以进入的数据流会很大,也就是会更占CPU。
从这个情况就可以扩展想一下,整体的CPU我们可以看到利用率不高,因为每个核的空闲百分比都很大(70%多),但是软中断的CPU6则利用率有50%多,所以这个软中断就很有可能成为性能瓶颈,也就是当请求量增加到一定程度,CPU6会直接被打满,而其他CPU核往往还有大量空闲。
这是部署Nginx的一个情况,HaProxy和LVS等等都一样,都会受到这个限制,所以当发现吞吐量上不去,而CPU利用率也比较低的时候就应该看看是不是软中断导致的。
解决方法
如果排查到软中断导致性能问题,解决方法可以从以下几方面考虑
- 硬件升级,CPU越好,那么处理速度越快,就能缓解这个问题,但是得加钱。
- 网卡多队列、RSS,可以查看是否支持多队列,比如通过命令cat /proc/interrupts,如果是以下这种情况,可以看到有多个核都能处理网卡中断,那么这种性能会高很多。有的博客提到过可以修改参数配置,让网卡中断绑定到不同的核上,但是我试过不行,可能是操作不对或者系统不支持,后面也没深入研究,如果有这种需求可以再找一找相关资料。
1
2
3
4
5
6
7
8
9CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
35: 1157411688 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-0
36: 2199548159 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-1
37: 2210448541 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-2
38: 954381730 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-3
39: 3991435919 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-4
40: 2197207910 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-5
41: 2685654183 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-6
42: 2153260851 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-7 - DPDK ,DPDK 抛弃了传统的内核中断,采用轮询模式驱动( poll mode driver,PMD) 的方式直接操作网卡的接收和发送队列,将报文直接拷贝到用户空间,不再经过内核协议栈。这样就不会受到大量中断影响了,性能也会更高,比如可以看美团的MGV,也可以搜一下其他相关的技术。
- 使用不同的负载均衡方式,DNS、LVS、硬件负载等等