1. mpstat -P ALL 1 或 mpstat -I SUM -P ALL 1(有的机器得用这个命令),
2. sar -n DEV 1 显示 网络读写发生在eth1
3. cat /proc/interrupts | grep eth1 通过这个可以查看网卡队列数目,也可以查看哪个cpu占用的软中断
4.top命令查看
Cpu(s): 0.1%us, 0.0%sy, 0.0%ni, 99.9%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
第三行,cpu状态信息,具体信息说明如下:
0.1%us — 用户空间占用CPU的百分比
0.0% sy — 内核空间占用CPU的百分比
0.0% ni — 改变过优先级的进程占用CPU的百分比
99.9% id — 空闲CPU百分比
0.0% wa — IO等待占用CPU的百分比
0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比
0.0% si — 软中断(Software Interrupts)占用CPU的百分比
Linux内核在性能方面已经经历了很长一段时间的考验,尤其是2.6/3.x内核。然而,在高IO,尤其是网络方面的情况下,对中断的处理可能成为问题。我们已经 在拥有一个或多个饱和1Gbps网卡的高性能系统上发现过这个问题,近来在有许多小包并发(大约10000packets/second)超载的虚拟机上 也发现了这个问题。
原因很清楚:在最简单的模式中,内核通过硬件中断的方式来处理每个来自于网卡的包。但是随着 数据包速率的增长,带来的中断渐渐超过了单个cpu可处理的范围。单cpu概念很重要,系统管理员对此往往认识不足。在一个普通的4-16核的系统中,因 为整体cpu的使用率在6-25%左右并且系统看上去很正常,所以一个过载的内核很难被发现,。但是系统将运行很慢,并且会在没有告警,没有dmesg日 志,没有明显征兆的情况下严重丢包。
但是你使用top查看多个cpu模式(运行top,接着键入1)时,%si 列(系统中断)或者mpstat命令中 irq列(mpstat -P ALL 1),在一些繁忙的系统中你会发现中断明显很高,通过经进一步mpstat使用,你会看到哪个cpu或者哪个设备存在问题。
你需要一个较新版本的mpstat,可以运行-I 模式,用以列出irq负载,运行如下命令:
mpstat -I SUM -P ALL 1
超过5000/秒 有点繁忙, 1万-2万/秒相当高了。
运行如下命令来确认那个设备/项目导致负载:
mpstat -I CPU -P ALL 1 这个输出很难被阅读,但是你可以跟踪正确的列用来确认哪个中断导致负载,例如:15,19,995. 你也可以定义你想查看的cpu
mpstat -I CPU -P 3 1 # 3 在top,htop中可以定位不同的cpu。(top和mpstat都是从0开始,htop是从1开始计数)
记录下中断数,你就可以查看中断表 ,"cat /proc/interrupts" 找到mpstat's得到的数字,你可以发现是哪个设备在使用中断。这个文件也指示了使用该中断的#可以告诉你是什么导致过载。
查看中断分布情况即CPU都在哪些设备上干活
root@geekwolf:~# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 CPU16 CPU17 CPU18 CPU19 CPU20 CPU21 CPU22 CPU23 CPU24 CPU25 CPU26 CPU27 CPU28 CPU29 CPU30 CPU31
0: 620 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-edge timer
8: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-edge rtc0
9: 20774 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi acpi
16: 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi ehci_hcd:usb1
23: 243 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi ehci_hcd:usb2
88: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DMAR_MSI-edge dmar0
89: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DMAR_MSI-edge dmar1
90: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
91: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
92: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
93: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
94: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
95: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
96: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
97: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
98: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
99: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
100: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
101: 169988 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge mpt2sas0-msix0
134: 1900138 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth2-q0
150: 4262209 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-q0
166: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
167: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
168: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
169: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
170: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
171: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
172: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
173: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
174: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
175: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
176: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
177: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
178: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
179: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
180: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
181: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
NMI: 710 280 658 235 114 91 76 74 208 123 176 128 106 93 102 95 30 360 790 46 28 17 10 8 10 129 1166 22 18 16 11 7 Non-maskable interrupts
LOC: 4230314 2640664 2427443 1337890 1091372 892129 819153 816781 2695809 1563153 1368637 1608410 1241692 1166692 1205270 1124865 120831 1966946 328048 816162 163492 222276 129805 121126 111906 599782 1247371 194215 162828 145678 118762 114295 Local timer interrupts
SPU: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Spurious interrupts
PMI: 710 280 658 235 114 91 76 74 208 123 176 128 106 93 102 95 30 360 790 46 28 17 10 8 10 129 1166 22 18 16 11 7 Performance monitoring interrupts
IWI: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IRQ work interrupts
RES: 679921 1369165 1013002 573776 543083 540027 593345 588120 842115 846190 874862 890102 873810 860080 867322 848916 3879 63916 10863 12850 7463 6350 10889 16041 2065 13207 6870 6817 4030 4700 5190 7430 Rescheduling interrupts
CAL: 46507 67439 67569 67567 67565 67566 67566 67568 154689 67553 67511 67538 67568 67557 67534 67519 67520 26471 67470 67470 67476 67525 67518 67525 67545 64065 67210 67506 67485 67492 67526 67521 Function call interrupts
TLB: 6547 3416 1798 1015 361 637 271 447 822 113 1079 222 259 198 265 844 157 1470 3468 767 499 262 338 230 41 1457 4023 290 105 93 46 177 TLB shootdowns
TRM: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Thermal event interrupts
THR: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Threshold APIC interrupts
MCE: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Machine check exceptions
MCP: 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 Machine check polls
ERR: 0
MIS: 0
Receive Packet Steering/Receive Flow Streering,软件方式实现CPU均衡,接收包中断的优化
RPS: 网卡驱动对每一个数据库包根据四元组(SIP,SPORT,DIP,DPORT)生成HASH值,通过HASH值将每个连接和CPU 绑定
RFS: 由于RPS只是单纯的把数据包均衡到不同的CPU上,此时如果应用程序所在CPU和中断处理的CPU不在同一个核,将会对CPU Cache影响很大,RFS的作用就是将应用程序和软中断处理分配到同一个CPU
首先,确认你是否运行irqbalance,这个是nice守护进程它会自动在cpu间扩展中断。在繁忙的系统中很重要,尤其是两块网卡,因为默认cpu0 将处理所有中断,系统很容易过载。irqbalance扩散这些中断用以降低负载。为了性能最大化,你可以手动平衡这些中断将套接字和超线程共享内核分 散,但是通常没必要这么麻烦。
但是即使扩展了中断,某块网卡还是可能导致某一个cpu过载。这取决于你的网卡和驱动,但通常有两种有效的方法来防止这样的事情发生。
第一种是多网卡队列,有些Intel网卡就可以这么做。如果他们有4个队列,就可以有四个cpu内核同时处理不同的中断用以分散负载。通常驱动会自动这么做,你也可以通过mpstat命令来确认。
第二种,并且通常也是更加重要的,网卡驱动选项——'IRQ coalescing',中断请求合并。这个选项有着强大的功能,允许网卡在调用中断请求前缓存数个数据包,从而为系统节约大量的时间和负载。
举个例子: 如果网卡缓存10个包,那么cpu负载将大约降低90%。这个功能通常用ethtool工具来控制,使用'-c/-C'参数,但是有些驱动要求在驱动初次 加载时就做好相关设置。如何设置需要查看本机文档。举个例子,有些网卡,譬如我们使用的Intel网卡,就有automatic模式可以根据负载自动做到 最优化。 最后,就像我们在虚拟机中看到的一些驱动,它们不支持多队列或者中断请求合并。这种情况下,一旦处理中断的cpu繁忙,就会产生性能瓶颈,除非你更换设备或者驱动。 这是一个复杂的区域,并不广为人知,但有些不错的技术真的可以提高繁忙系统的性能。此外,一些额外的针对性监控,可以帮助到查找和诊断这些难以发现的问题。
前些天发现XEN虚拟机上的Nginx服务器存在一个问题:软中断过高,而且大部分都集中在同一个CPU,一旦系统繁忙,此CPU就会成为木桶的短板。
在问题服务器上运行「top」命令可以很明显看到「si」存在异样,大部分软中断都集中在 1 号CPU上,其它的CPU完全使不上劲儿:
shell> top
Cpu0: 11.3%us, 4.7%sy, 0.0%ni, 82.5%id, ... 0.8%si, 0.8%st
Cpu1: 21.3%us, 7.4%sy, 0.0%ni, 51.5%id, ... 17.8%si, 2.0%st
Cpu2: 16.6%us, 4.5%sy, 0.0%ni, 77.7%id, ... 0.8%si, 0.4%st
Cpu3: 15.9%us, 3.6%sy, 0.0%ni, 79.3%id, ... 0.8%si, 0.4%st
Cpu4: 17.7%us, 4.9%sy, 0.0%ni, 75.3%id, ... 1.2%si, 0.8%st
Cpu5: 23.6%us, 6.6%sy, 0.0%ni, 68.1%id, ... 0.9%si, 0.9%st
Cpu6: 18.1%us, 4.9%sy, 0.0%ni, 75.7%id, ... 0.4%si, 0.8%st
Cpu7: 21.1%us, 5.8%sy, 0.0%ni, 71.4%id, ... 1.2%si, 0.4%st
查询一下软中断相关数据,发现主要集中在 NET_RX 上,猜测是网卡问题:
shell> watch -d -n 1 'cat /proc/softirqs'
CPU0 CPU1 CPU2 ... CPU7
HI: 0 0 0 ... 0
TIMER: 3692566284 3692960089 3692546970 ... 3693032995
NET_TX: 130800410 652649368 154773818 ... 308945843
NET_RX: 443627492 3802219918 792341500 ... 2546517156
BLOCK: 0 0 0 ... 0
BLOCK_IOPOLL: 0 0 0 ... 0
TASKLET: 0 0 0 ... 0
SCHED: 1518716295 335629521 1520873304 ... 1444792018
HRTIMER: 160 1351 131 ... 196
RCU: 4201292019 3982761151 4184401659 ... 4039269755
补充:有一个查看中断(Interrupt)的top风格小工具 itop ,推荐试试。
确认一下宿主机上的网卡信息,发现其运行在单队列模式下:
shell> grep -A 10 -i network /var/log/dmesg
Initalizing network drop monitor service
Intel(R) Gigabit Ethernet Network Driver - version 3.0.19
igb 0000:05:00.0: Intel(R) Gigabit Ethernet Network Connection
igb 0000:05:00.0: eth0: (PCIe:2.5GT/s:Width x4) 00:1b:21:bf:b3:2c
igb 0000:05:00.0: eth0: PBA No: G18758-002
igb 0000:05:00.0: Using MSI-X ... 1 rx queue(s), 1 tx queue(s)
igb 0000:05:00.1: Intel(R) Gigabit Ethernet Network Connection
igb 0000:05:00.1: eth1: (PCIe:2.5GT/s:Width x4) 00:1b:21:bf:b3:2d
igb 0000:05:00.1: eth1: PBA No: G18758-002
igb 0000:05:00.1: Using MSI-X ... 1 rx queue(s), 1 tx queue(s)
接着确认一下网卡的中断号,因为是单队列,所以只有一个中断号 45:
shell> grep eth /proc/interrupts | awk '{print $1, $NF}'
45: eth0
知道了网卡的中断号,就可以查询其中断亲缘性配置「smp_affinity」:
shell> cat /proc/irq/45/smp_affinity
02
这里的 02 实际上是十六进制,表示 1 号CPU,计算方法如下(参考资料):
Binary Hex
CPU 0 0001 1
CPU 1 0010 2
CPU 2 0100 4
+ CPU 3 1000 8
-----------------------
both 1111 f
说明:如果 4 个CPU都参与中断处理,那么设为 f;同理 8 个CPU的就设置成 ff:
shell> echo ff > /proc/irq/45/smp_affinity
此外还有一个类似的配置「smp_affinity_list」:
shell> cat /proc/irq/45/smp_affinity_list
1
两个配置是相通的,修改了一个,另一个会跟着变。不过「smp_affinity_list」使用的是十进制,相比较「smp_affinity」的十六进制,可读性更好些。
了解了这些基本知识,我们可以尝试换一个CPU试试看会发生什么:
echo 0 > /proc/irq/45/smp_affinity_list
再通过「top」命令观察,会发现处理软中断的CPU变成了 0 号CPU。
说明:如果希望多个CPU参与中断处理的话,可以使用类似下面的语法:
echo 3,5 > /proc/irq/45/smp_affinity_list
echo 0-7 > /proc/irq/45/smp_affinity_list
坏消息是对单队列网卡而言,「smp_affinity」和「smp_affinity_list」配置多CPU无效。
好消息是Linux支持RPS,通俗点来说就是在软件层面模拟实现硬件的多队列网卡功能。
首先看看如何配置RPS,如果CPU个数是 8 个的话,可以设置成 ff:
shell> echo ff > /sys/class/net/eth0/queues/rx-0/rps_cpus
接着配置内核参数rps_sock_flow_entries(官方文档推荐设置: 32768):
shell> sysctl net.core.rps_sock_flow_entries=32768
最后配置rps_flow_cnt,单队列网卡的话设置成rps_sock_flow_entries即可:
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
说明:如果是多队列网卡,那么就按照队列数量设置成 rps_sock_flow_entries / N 。
做了如上的优化后,我们再运行「top」命令可以看到软中断已经分散到了两个CPU:
shell> top
Cpu0: 24.8%us, 9.7%sy, 0.0%ni, 52.2%id, ... 11.5%si, 1.8%st
Cpu1: 8.8%us, 5.1%sy, 0.0%ni, 76.5%id, ... 7.4%si, 2.2%st
Cpu2: 17.6%us, 5.1%sy, 0.0%ni, 75.7%id, ... 0.7%si, 0.7%st
Cpu3: 11.9%us, 7.0%sy, 0.0%ni, 80.4%id, ... 0.7%si, 0.0%st
Cpu4: 15.4%us, 6.6%sy, 0.0%ni, 75.7%id, ... 1.5%si, 0.7%st
Cpu5: 20.6%us, 6.9%sy, 0.0%ni, 70.2%id, ... 1.5%si, 0.8%st
Cpu6: 12.9%us, 5.7%sy, 0.0%ni, 80.0%id, ... 0.7%si, 0.7%st
Cpu7: 15.9%us, 5.1%sy, 0.0%ni, 77.5%id, ... 0.7%si, 0.7%st
疑问:理论上讲,我已经设置了RPS为ff,应该所有 8 个CPU一起分担软中断才对,可实际结果只有两个,有知道原因的请赐教,但是不管怎么说,两个总好过一个。
此外,因为这是一台Nginx服务器,所以通过「worker_cpu_affinity」指令可以配置Nginx使用哪些CPU,如此一来我们便可以绕开高负载的CPU,对性能会有一些帮助。
补充:如果服务器是NUMA架构的话,那么「numactl –cpubind」可能也会有用。
最后,推荐看看香草总结的一些关于软中断方面的资料和工具,很全面。