问题
多核CPU游戏战斗服务器高峰期时会出现网络丢包, 发现CPU0软中断%si 过高,导致%id值过低触发告警
如下图,在线低峰期软中断%si 处理时间百分比高达20多,id值变低,服务器变卡和丢包,影响业务
中断
什么是中断?
指接收来自硬件或者软件的信号发送给CPU和系统内核进行处理,发出这样的信号称为进行中断请求(IRQ)
中断又分为:
硬中断:外围硬件比如网卡发给CPU的信号
软中断:由硬中断处理后对操作系统内核发出信号的中断请求
查看中断情况即CPU都在哪些设备上干活
通过命令cat /proc/interrupts 查看系统中断信息,长下面这个样子的。
第一列是中断号,比如eth0对应的中断号是35,后面是每个cpu对应的中断次数。
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
0: 127 0 0 0 0 0 0 0 IR-IO-APIC-edge timer
7: 15 0 0 0 0 0 0 0 IR-IO-APIC-edge
8: 182900 0 0 0 0 0 0 0 IR-IO-APIC-edge rtc0
9: 1 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi acpi
23: 18575 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi ehci_hcd:usb1
24: 0 0 0 0 0 0 0 0 DMAR_MSI-edge dmar0
25: 132248 0 0 0 0 0 0 0 IR-HPET_MSI-edge hpet2
26: 0 0 0 0 0 0 0 0 IR-HPET_MSI-edge hpet3
27: 0 0 0 0 0 0 0 0 IR-HPET_MSI-edge hpet4
28: 0 0 0 0 0 0 0 0 IR-HPET_MSI-edge hpet5
29: 0 0 0 0 0 0 0 0 IR-HPET_MSI-edge hpet6
32: 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge aerdrv
33: 2735198364 0 0 0 0 0 0 0 IR-PCI-MSI-edge ahci
34: 1 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0
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
NMI: 121456 40118 30875 24931 27000 26053 21459 19945 Non-maskable interrupts
LOC: 3074687366 1216301963 1626527541 4049966581 4109422958 2708891166 1813301274 1373418058 Local timer interrupts
SPU: 0 0 0 0 0 0 0 0 Spurious interrupts
PMI: 121456 40118 30875 24931 27000 26053 21459 19945 Performance monitoring interrupts
IWI: 0 0 0 0 0 0 0 0 IRQ work interrupts
RES: 2454452061 1303706723 606598429 461072921 965186776 274559675 348785593 347963099 Rescheduling interrupts
CAL: 216 682 679 680 583 683 667 668 Function call interrupts
TLB: 19837873 5603975 5927817 4380569 12552909 11396903 7656446 6960058 TLB shootdowns
TRM: 0 0 0 0 0 0 0 0 Thermal event interrupts
THR: 0 0 0 0 0 0 0 0 Threshold APIC interrupts
MCE: 0 0 0 0 0 0 0 0 Machine check exceptions
MCP: 132236 132236 132236 132236 132236 132236 132236 132236 Machine check polls
ERR: 15
MIS: 0
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
35: 1157411688 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth0-TxRx-0从上面可以看得到eth0的网卡中断次数最多,意味着中断请求都在CPU0上面处理,固然就会出现图1的情况
优化
Linux系统采用中断机制协同处理CPU与其他设备工作。网卡的中断默认由cpu0处理,在大量请求的网络环境下可能出现cpu0负载高,而其他cpu空闲。后来出现网卡多队列技术解决这个问题
RSS(Receive Side Scaling)是网卡的硬件特性,实现了多队列,可以将不同的中断次数分发到不同的CPU上。多队列网卡是一种技术,最初是用来解决网络IO QoS (quality of service)问题的,后来随着网络IO的带宽的不断提升,单核CPU不能完全处满足网卡的需求,通过多队列网卡驱动的支持,将各个队列通过中断绑定到不同的核上,以满足网卡的需求,同时也可以降低CPU0的负载,解决图1的问题
查看网卡是否支持队列,支持多少个队列
awk '$NF~/eth/{print $1,$NF}' /proc/interrupts
37: eth0-TxRx-0
38: eth0-TxRx-1
39: eth0-TxRx-2
40: eth0-TxRx-3
41: eth0-TxRx-4
42: eth0-TxRx-5
43: eth0-TxRx-6
44: eth0-TxRx-7
以上网卡eth0为例支持队列,37-44是中断号, 一般现在主流网卡驱动都支持多队列,默认是7个队列
中断绑定
网卡支持了队列,意味着我们就可以绑定中断号与处理CPU之间的关系,
Linux系统默认使用irqbalance服务优化中断分配,它能自动收集数据,调度中断请求,但是它的分配调度机制极不均匀,不建议开启,为了了解中断绑定,我们把irqbalance服务关掉,手工调整绑定关系。
##相关配置文件:
/proc/irq/中断号/smp_affinity,中断IRQ_ID的CPU亲和配置文件,16进制
/proc/irq/中断号/smp_affinity_list,10进制,与smp_affinity相通,修改一个相应改变。
smp_affinity和smp_affinity_list修改其一即可,smp_affinity_list修改更方便
cat /proc/irq/37/smp_affinity
01
cat /proc/irq/38/smp_affinity_list
01
#上面表示01对应cpu0,可以直接修改绑定关系
echo 0 > /proc/irq/37/smp_affinity
echo 1 > /proc/irq/38/smp_affinity
echo 2 > /proc/irq/39/smp_affinity
echo 3 > /proc/irq/40/smp_affinity
echo 4 > /proc/irq/41/smp_affinity
echo 5 > /proc/irq/42/smp_affinity
echo 6 > /proc/irq/43/smp_affinity
echo 7 > /proc/irq/38/smp_affinity
cat /proc/irq/37/smp_affinity_list
0
cat /proc/irq/38/smp_affinity_list
1
cat /proc/irq/39/smp_affinity_list
2
cat /proc/irq/40/smp_affinity_list
3
cat /proc/irq/41/smp_affinity_list
4
cat /proc/irq/42/smp_affinity_list
5
cat /proc/irq/43/smp_affinity_list
6
cat /proc/irq/44/smp_affinity_list
7
#此时中断号37、38对应的处理CPU为cpu1、cpu2,top命令查看%si是否均衡分摊到0-7核CPU
支持RSS的网卡,通过上面这种方法将不同的中断号绑定到每个CPU上实现了中断的分配。
RPS/RFS
虽然说RSS实现了中断的分配,但是如果队列数 < 机器总核数 并且CPU与中断号一一对应了,会出现软中断负载跑在0-7核上,其他核不处理软中断的情况,0-7核负载依然会很高。RSS需要硬件支持,在只支持单队列或多队列的环境中,RPS/RFS提供了软件的解决方案。
RPS(Receive Packet Steering)是基于RSS软件方式实现CPU均衡,接收包中断的优化,是把一个或多个rx队列的软中断分发到多个CPU核上,从而达到全局负载均衡的目的。
RFS(Receive Flow Steering)是RPS的扩展,由于RPS只是单纯的把数据包均衡到不同的CPU上,此时如果应用程序所在CPU和中断处理的CPU不在同一个核,将会对CPU Cache影响很大,RFS的作用就是将应用程序和软中断处理分配到同一个CPU
配置RPS
一个十六进制 f 表示四个CPU核,那么均衡到32核即ffffffff,经研究测试,最大只支持32核调度分配
rps_cpus='ffffffff'
for rxdir in /sys/class/net/eth0/queues/rx-*
do
echo $rps_cpus >$rxdir/rps_cpus
done
配置RFS
RFS扩展了RPS的性能以增加CPU缓存命中率,减少网络延迟,默认是禁用的
/proc/sys/net/core/rps_sock_flow_entries
这个值依赖于系统期望的活跃连接数,注意是同一时间活跃的连接数,这个连接数正常来说会大大小于系统能承载的最大连接数,因为大部分连接不会同时活跃。推荐值是 32768
/sys/class/net/device/queues/rx-queue/rps_flow_cnt
将 device 改为想要配置的网络设备名称(例如,eth0),将 rx-queue 改为想要配置的接收队列名称(例如,rx-0)。
将此文件的值设为 rps_sock_flow_entries 除以 N,其中 N 是设备中接收队列的数量。例如,如果 rps_flow_entries 设为 32768,并且有 16 个配置接收队列,那么 rps_flow_cnt 就应设为 2048。对于单一队列的设备,rps_flow_cnt 的值和 rps_sock_flow_entries 的值是一样的
ls /sys/class/net/eth0/queues/rx-*|grep queues|wc -l
8
rps_flow_cnt=32768/8=4096
echo 32768 >/proc/sys/net/core/rps_sock_flow_entries
for rxdir in /sys/class/net/eth0/queues/rx-*
do
echo $rps_cpus >$rxdir/rps_cpus
echo $rps_flow_cnt >$rxdir/rps_flow_cnt
done
echo 32768 >/proc/sys/net/core/rps_sock_flow_entries
效果
RSS+RPS+RFS 优化过后可以看到软中断已均分到每个CPU上,%id值均匀,现在看已经是比较充分地利用多核CPU了,不用太担心单核出现高负载告警的问题。
来源:oschina
链接:https://my.oschina.net/u/4334340/blog/4267064