Linux技巧:多核下繫結網絡卡中斷到不同CPU(core)總結
http://www.cnblogs.com/zackyang/archive/2012/02/08/2342141.html
http://blog.chinaunix.net/uid-20737871-id-3491415.html
http://smilejay.com/2012/02/irq_affinity/
http://flash520.blog.163.com/blog/static/344144752010730103640949/
http://www.cnblogs.com/Bozh/archive/2013/01/17/2864201.html
http://blog.chinaunix.net/uid-20737871-id-3600093.html
http://www.cnblogs.com/Bozh/archive/2013/03/21/2973769.html
http://blog.chinaunix.net/uid-26642180-id-3131179.html
硬體中斷髮生頻繁,是件很消耗 CPU 資源的事情,在多核 CPU 條件下如果有辦法把大量硬體中斷分配給不同的 CPU (core) 處理顯然能很好的平衡效能。現在的伺服器上動不動就是多 CPU 多核、多網絡卡、多硬碟,如果能讓網絡卡中斷獨佔1個 CPU (core)、磁碟 IO 中斷獨佔1個 CPU 的話將會大大減輕單一 CPU 的負擔、提高整體處理效率。我前天收到一位網友的郵件提到了 SMP IRQ Affinity,引發了今天的話題。以下操作在 SUN FIre X2100 M2 伺服器+ 64位版本 CentOS 5.5 + Linux 2.6.18-194.3.1.el5 上執行。
什麼是中斷
中文教材上對 “中斷” 的定義太生硬了,簡單的說就是,每個硬體裝置(如:硬碟、網絡卡等)都需要和 CPU 有某種形式的通訊以便 CPU 及時知道發生了什麼事情,這樣 CPU 可能就會放下手中的事情去處理應急事件,硬體裝置主動打擾 CPU 的現象就可稱為硬體中斷,就像你正在工作的時候受到 QQ 干擾一樣,一次 QQ 搖頭就可以被稱為中斷。
中斷是一種比較好的 CPU 和硬體溝通的方式,還有一種方式叫做輪詢(polling),就是讓 CPU 定時對硬體狀態進行查詢然後做相應處理,就好像你每隔5分鐘去檢查一下 QQ 看看有沒有人找你一樣,這種方式是不是很浪費你(CPU)的時間?所以中斷是硬體主動的方式,比輪詢(CPU 主動)更有效一些。
好了,這裡又有了一個問題,每個硬體裝置都中斷,那麼如何區分不同硬體呢?不同裝置同時中斷如何知道哪個中斷是來自硬碟、哪個來自網絡卡呢?這個很容易,不是每個 QQ 號碼都不相同嗎?同樣的,系統上的每個硬體裝置都會被分配一個 IRQ 號,通過這個唯一的 IRQ 號就能區別張三和李四了。
在計算機裡,中斷是一種電訊號,由硬體產生,並直接送到中斷控制器(如 8259A)上,然後再由中斷控制器向 CPU 傳送訊號,CPU 檢測到該訊號後,就中斷當前的工作轉而去處理中斷。然後,處理器會通知作業系統已經產生中斷,這樣作業系統就會對這個中斷進行適當的處理。現在來看一下中斷控制器,常見的中斷控制器有兩種:可程式設計中斷控制器 8259A 和高階可程式設計中斷控制器(APIC),中斷控制器應該在大學的硬體介面和計算機體系結構的相關課程中都學過。傳統的 8259A 只適合單 CPU 的情況,現在都是多 CPU 多核的 SMP 體系,所以為了充分利用 SMP 體系結構、把中斷傳遞給系統上的每個 CPU 以便更好實現並行和提高效能,Intel 引入了高階可程式設計中斷控制器(APIC)。
光有高階可程式設計中斷控制器的硬體支援還不夠,Linux 核心還必須能利用到這些硬體特質,所以只有 kernel 2.4 以後的版本才支援把不同的硬體中斷請求(IRQs)分配到特定的 CPU 上,這個繫結技術被稱為 SMP IRQ Affinity. 更多介紹請參看 Linux 核心原始碼自帶的文件:linux-2.6.31.8/Documentation/IRQ-affinity.txt
如何使用
先看看系統上的中斷是怎麼分配在 CPU 上的,很顯然 CPU0 上處理的中斷多一些:
# cat /proc/interrupts
CPU0 CPU1
0: 918926335 0 IO-APIC-edge timer
1: 2 0 IO-APIC-edge i8042
8: 0 0 IO-APIC-edge rtc
9: 0 0 IO-APIC-level acpi
12: 4 0 IO-APIC-edge i8042
14: 8248017 0 IO-APIC-edge ide0
50: 194 0 IO-APIC-level ohci_hcd:usb2
58: 31673 0 IO-APIC-level sata_nv
90: 1070374 0 PCI-MSI eth0
233: 10 0 IO-APIC-level ehci_hcd:usb1
NMI: 5077 2032
LOC: 918809969 918809894
ERR: 0
MIS: 0
為了不讓 CPU0 很累怎麼把部分中斷轉移到 CPU1 上呢?或者說如何把 eth0 網絡卡的中斷轉到 CPU1 上呢?先檢視一下 IRQ 90 中斷的 smp affinity,看看當前中斷是怎麼分配在不同 CPU 上的(ffffffff 意味著分配在所有可用 CPU 上):
# cat /proc/irq/90/smp_affinity
7fffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff
在進一步動手之前我們需要先停掉 IRQ 自動調節的服務程序,這樣才能手動繫結 IRQ 到不同 CPU,否則自己手動繫結做的更改將會被自動調節程序給覆蓋掉。如果想修改 IRQ 90 的中斷處理,繫結到第2個 CPU(CPU1):
# /etc/init.d/irqbalance stop
# echo "2" > /proc/irq/90/smp_affinity
過段時間在看 /proc/interrupts,是不是 90:eth0 在 CPU1 上的中斷增加了(145)、在 CPU0 上的中斷沒變?不斷列印 /proc/interrupts 就會發現 eth0 在 CPU0 上的中斷數始終保持不變,而在 CPU1 上的中斷數是持續增加的,這正是我們想要的結果:
# cat /proc/interrupts
CPU0 CPU1
0: 922506515 0 IO-APIC-edge timer
1: 2 0 IO-APIC-edge i8042
8: 0 0 IO-APIC-edge rtc
9: 0 0 IO-APIC-level acpi
12: 4 0 IO-APIC-edge i8042
14: 8280147 0 IO-APIC-edge ide0
50: 194 0 IO-APIC-level ohci_hcd:usb2
58: 31907 0 IO-APIC-level sata_nv
90: 1073399 145 PCI-MSI eth0
233: 10 0 IO-APIC-level ehci_hcd:usb1
NMI: 5093 2043
LOC: 922389696 922389621
ERR: 0
MIS: 0
有什麼用
在網路非常 heavy 的情況下,對於檔案伺服器、高流量 Web 伺服器這樣的應用來說,把不同的網絡卡 IRQ 均衡繫結到不同的 CPU 上將會減輕某個 CPU 的負擔,提高多個 CPU 整體處理中斷的能力;對於資料庫伺服器這樣的應用來說,把磁碟控制器綁到一個 CPU、把網絡卡繫結到另一個 CPU 將會提高資料庫的響應時間、優化效能。合理的根據自己的生產環境和應用的特點來平衡 IRQ 中斷有助於提高系統的整體吞吐能力和效能。
本人經常收到網友來信問到如何優化 Linux、優化 VPS、這個問題不太好回答,要記住的是效能優化是一個過程而不是結果,不是看了些文件改了改引數就叫優化了,後面還需要大量的測試、監測以及持續的觀察和改進。
繫結程序到不同CPU
介紹了在 Linux 多核下如何繫結硬體中斷到不同 CPU,其實也可以用類似的做法把程序手動分配到特定的 CPU 上,平時在 Linux 上執行的各種程序都是由 Linux 核心統一分配和管理的,由程序排程演算法來決定哪個程序可以開始使用 CPU、哪個程序需要睡眠或等待、哪個程序執行在哪個 CPU 上等。如果你對作業系統的核心和程序排程程式感興趣的話,不妨看看那本經典的 Operating Systems Design and Implementation(Linus Torvalds 就是看了這本書受到啟發寫出了 Linux),從簡單的 Minix 入手,hack 核心是件很有意思的事情,本人以前修改過 Minix 核心的程序排程,學到了核心方面的很多東西。另外推薦一本課外讀物:Just for Fun,Linus Torvalds 寫的一本自傳。
Linux 給我們提供了方便的工具用來手動分配程序到不同的 CPU 上(CPU Affinity),這樣我們可以按照伺服器和應用的特性來安排特定的程序到特定的 CPU 上,比如 Oracle 要消耗大量 CPU 和 I/O 資源,如果我們能分配 Oracle 程序到某個或多個 CPU 上並由這些 CPU 專門處理 Oracle 的話會毫無疑問的提高應用程式的響應和效能。還有一些特殊情況是必須繫結應用程式到某個 CPU 上的,比如某個軟體的授權是單 CPU 的,如果想執行在多 CPU 機器上的話就必須限制這個軟體到某一個 CPU 上。
安裝 schedutils
在 CentOS/Fedora 下安裝 schedutils:
# yum install schedutils
在 Debian/Ubuntu 下安裝 schedutils:
# apt-get install schedutils
如果正在使用 CentOS/Fedora/Debian/Ubuntu 的最新版本的話,schedutils/util-linux 這個軟體包可能已經裝上了。
計算 CPU Affinity 和計算 SMP IRQ Affinity 差不多:
0x00000001 (CPU0)
0x00000002 (CPU1)
0x00000003 (CPU0+CPU1)
0x00000004 (CPU2)
...
使用 schedutils
如果想設定程序號(PID)為 12212 的程序到 CPU0 上的話:
# taskset 0x00000001 -p 12212
分類: LINUX
最近在做LVS做load balance測試時發現在併發達到1w以後網絡卡中斷只佔用了一個CPU,最終導致此CPU的100%,效能再無法提升。
逐步嘗試以下方法:
- 修改核心引數irqbalance。印象中此引數能把網絡卡中斷平分到多個CPU上。但是查詢最新文件發現此引數在最新的核心中已經不存在;
-
使用裝置中斷的smp_affinity:
- 首先先從/proc/interrupts裡查到網絡卡的中斷號,eth0或者bg0所在行的第一列;
- 修改/proc/irq/<中斷編號>/ 下修改 smp_affinity 檔案內容。這個檔案是一個位掩碼,01意味著只有第一個CPU能處理中斷,0F意味著四個CPU都會參與處理中斷。
- 但是經過測試發現此方法能把網絡卡中斷繫結到指定的CPU上,但是不能在多個CPU間平均分配。
- 使用user space態下的irqbalance daemon,未得到反饋,估計無效;
裝置中斷繫結到特定CPU(SMP IRQ AFFINITY)
在前陣子看到HelloDB的一篇文章“中提到:
因為單機執行多個例項,必須對網路進行優化,我們通過多個的IP的方式,將多個MySQL例項繫結在不同的網絡卡上,從而提高整體的網路能力。還有一種更高階的做法是,將不同網絡卡的中斷與CPU繫結,這樣可以大幅度提升網絡卡的效率。
於是,對“將不同網絡卡的中斷與CPU繫結,這樣可以大幅度提升網絡卡的效率”比較感興趣,所以找了點資料瞭解一下。先總結如下:
1. 不同的裝置一般都有自己的IRQ號碼(當然一個裝置還有可能有多個IRQ號碼)
通過命令:cat /proc/interrupts檢視
如:cat /proc/interrupts | grep -e “CPU\|eth4”
2. 中斷的smp affinity在cat /proc/irq/$Num/smp_affinity
可以echo “$bitmask” > /proc/irq/$num/smp_affinity來改變它的值。
注意smp_affinity這個值是一個十六進位制的bitmask,它和cpu No.序列的“與”運算結果就是將affinity設定在那個(那些)CPU了。(也即smp_affinity中被設定為1的位為CPU No.)
比如:我有8個邏輯core,那麼CPU#的序列為11111111 (從右到左依次為#0~#7的CPU)
如果cat /proc/irq/84/smp_affinity的值為:20(二進位制為:00100000),則84這個IRQ的親和性為#5號CPU。
每個IRQ的預設的smp affinity在這裡:cat /proc/irq/default_smp_affinity
另外,cat /proc/irq/$Num/smp_affinity_list 得到的即是CPU的一個List。
3. 預設情況下,有一個irqbalance在對IRQ進行負載均衡,它是/etc/init.d/irqbalance
在某些特殊場景下,可以根據需要停止這個daemon程序。
4. 如果要想提高效能,將IRQ繫結到某個CPU,那麼最好在系統啟動時,將那個CPU隔離起來,不被scheduler通常的排程。
可以通過在Linux kernel中加入啟動引數:isolcpus=cpu-list來將一些CPU隔離起來。
參考資料:
計算 SMP IRQ Affinity
如何繫結特定的硬體中斷到特定的 CPU 上 ,分散和平衡各個中斷到不同的 CPU 上以獲取更大效能的處理能力。上篇限於篇幅的關係,沒有來得及進一步說明 “echo 2 > /proc/irq/90/smp_affinity” 中的 ”2“ 是怎麼來的,這其實是個二進位制數字,代表 00000010,00000001 代表 CPU0 的話,00000010 就代表 CPU0, “echo 2 > /proc/irq/90/smp_affinity” 的意思就是說把 90 中斷繫結到 00000010(CPU1)上。所以各個 CPU 用二進位制和十六進位制表示就是:
Binary Hex
[separator] CPU 0 00000001 1
CPU 1 00000010 2
CPU 2 00000100 4
CPU 3 00001000 8
如果我想把 IRQ 繫結到 CPU2 上就是 00000100=4:
# echo "4" > /p
中斷過程簡單來說就是一種CPU 與硬體溝通的方式
中斷分為兩個過程,中間以中斷控制器作為分隔。上半部分即中斷上半部,下半部分為中斷下半部。
上半部分大部分為說說的硬體中斷,下半部分為軟中斷。
硬體中斷通常由真實物理裝置產生的脈衝訊號作為訊號源,也就是說這裡的物理裝置與中斷控制器溝通方式是通過物理電訊號來做的。
軟體中斷由中斷控制器負責統一排程,通常硬體裝置產生訊號,這個訊號帶有中斷號傳送給中斷控制器,中斷控制器輪訓收到的訊號來呼叫對應的中斷處理程式。
直觀一點來看:
通過
shell> cat /proc/interrupts
可以檢視到當前系統的軟中斷列表和對應的中斷號
從左到右依次表示:
中斷號,對應CPU中斷次數,裝置型別和裝置名
[[email protected] ~]# cat /proc/interrupts CPU0 CPU1 0: 14678 0 IO-APIC-edge timer 1: 2 0 IO-APIC-edge i8042 4: 2 0 IO-APIC-edge 7: 0 0 IO-APIC-edge parport0 8: 1 0 IO-APIC-edge rtc0 9: 0 0 IO-APIC-fasteoi acpi 12: 4 0 IO-APIC-edge i8042 14: 45394223 0 IO-APIC-edge ata_piix 15: 0 0 IO-APIC-edge ata_piix 16: 56 16232636 IO-APIC-fasteoi i915, p2p1 18: 5333843 11365439 IO-APIC-fasteoi uhci_hcd:usb4 20: 2277759 0 IO-APIC-fasteoi ata_piix 21: 3 0 IO-APIC-fasteoi ehci_hcd:usb1, uhci_hcd:usb2 22: 0 0 IO-APIC-fasteoi uhci_hcd:usb3 23: 3813 6412 IO-APIC-fasteoi uhci_hcd:usb5, Intel ICH7 NMI: 1037 925 Non-maskable interrupts LOC: 319530452 247726622 Local timer interrupts SPU: 0 0 Spurious interrupts PMI: 1037 925 Performance monitoring interrupts PND: 0 0 Performance pending work RES: 275434 264341 Rescheduling interrupts CAL: 4975165 5543634 Function call interrupts TLB: 452039 409944 TLB shootdowns TRM: 0 0 Thermal event interrupts THR: 0 0 Threshold APIC interrupts MCE: 0 0 Machine check exceptions MCP: 14411 14411 Machine check polls ERR: 0 MIS: 0
APIC表示高階可程式設計中斷控制器(Advanced Programmable Interrupt Controlle)
APIC是SMP體系的核心,通過APIC可以將中斷分發到不同的CPU 來處理
比如我這裡的0號中斷都是由CPU 來處理的,一些其他的中斷可以繫結CPU或者可以把中斷處理平攤到CPU 上,這個過程叫做 SMP IRQ Affinity
14號中斷是屬於硬碟裝置中斷,可以看到中斷處理全部由單個CPU完成,這是因為為了使CPU 快取的命中率提高等因素,使得CPU和硬碟中斷繫結(IRQBalance)
如果的多網絡卡多CPU的情況下,也可以考慮將指定的網絡卡軟中斷繫結到對應的CPU 上,這樣可以將負載有效的平衡,且能最大限度的利用CPU 快取。
這樣做的前提是先關閉IRQBalance
/etc/init.d/irqbalance stop
然後可以檢視到
cat /proc/irq/14/smp_affinity
對應的軟中斷的多核CPU親和性設定
我這裡顯示的是3,是什麼意思呢
對應的CPU情況是這樣的
CPU0 ---------- 00000001 1 CPU1 ---------- 00000010 2 CPU2 ---------- 00000100 4 . . . CPUN ---------- XXXXXXX 2^N
3 就表示1+2,也就是兩個CPU 都均衡,因為開啟了IRQ Balance,所以這裡中斷處理都會交給同一個CPU來保證效率
這裡的設定都需要硬體的支援,如果開啟關閉IRQBalance自己設定中斷處理的CPU親和,有的裝置在負載壓力大的時候也是會轉到其他CPU處理的,這裡的親和並不是強制性的CPU設定。
親和性設定建議:DB可以設定一部分CPU處理硬碟IO,一部分CPU處理網路IO,多網絡卡伺服器可以設定對應CPU對應網絡卡。當然具體情況看生產情況而定
roc/irq/90/smp_affinity如果我想把 IRQ 同時平衡到 CPU0 和 CPU2 上就是 00000001+00000100=00000101=5
# echo "5" > /proc/irq/90/smp_affinity
需要注意的是,在手動繫結 IRQ 到 CPU 之前需要先停掉 irqbalance 這個服務,irqbalance 是個服務程序、是用來自動繫結和平衡 IRQ 的:
# /etc/init.d/irqbalance stop
分類: LINUX
在前陣子看到HelloDB的一篇文章“中提到:
因為單機執行多個例項,必須對網路進行優化,我們通過多個的IP的方式,將多個MySQL例項繫結在不同的網絡卡上,從而提高整體的網路能力。還有一種更高階的做法是,將不同網絡卡的中斷與CPU繫結,這樣可以大幅度提升網絡卡的效率。
於是,對“將不同網絡卡的中斷與CPU繫結,這樣可以大幅度提升網絡卡的效率”比較感興趣,所以找了點資料瞭解一下。先總結如下:
1. 不同的裝置一般都有自己的IRQ號碼(當然一個裝置還有可能有多個IRQ號碼)
通過命令:cat /proc/interrupts檢視
如:cat /proc/interrupts | grep -e “CPU\|eth4″
2. 中斷的smp affinity在cat /proc/irq/$Num/smp_affinity
可以echo “$bitmask” > /proc/irq/$num/smp_affinity來改變它的值。
注意smp_affinity這個值是一個十六進位制的bitmask,它和cpu No.序列的“與”運算結果就是將affinity設定在那個(那些)CPU了。(也即smp_affinity中被設定為1的位為CPU No.)
比如:我有8個邏輯core,那麼CPU#的序列為11111111 (從右到左依次為#0~#7的CPU)
如果cat /proc/irq/84/smp_affinity的值為:20(二進位制為:00100000),則84這個IRQ的親和性為#5號CPU。
每個IRQ的預設的smp affinity在這裡:cat /proc/irq/default_smp_affinity
另外,cat /proc/irq/$Num/smp_affinity_list 得到的即是CPU的一個List。
3. 預設情況下,有一個irqbalance在對IRQ進行負載均衡,它是/etc/init.d/irqbalance
在某些特殊場景下,可以根據需要停止這個daemon程序。
4. 如果要想提高效能,將IRQ繫結到某個CPU,那麼最好在系統啟動時,將那個CPU隔離起來,不被scheduler通常的排程。
可以通過在Linux kernel中加入啟動引數:isolcpus=cpu-list來將一些CPU隔離起來。
參考資料:
SMP IRQ affinity
Linux 2.4核心之後引入了將特定中斷繫結到指定的CPU的技術,稱為SMP IRQ affinity.
原理
當一個硬體(如磁碟控制器或者乙太網卡), 需要打斷CPU的工作時, 它就觸發一箇中斷. 該中斷通知CPU發生了某些事情並且CPU應該放下當前的工作去處理這個事情. 為了防止多個設定傳送相同的中斷, Linux設計了一套中斷請求系統, 使得計算機系統中的每個裝置被分配了各自的中斷號, 以確保它的中斷請求的唯一性. 從2.4 核心開始, Linux改進了分配特定中斷到指定的處理器(或處理器組)的功能. 這被稱為SMP IRQ affinity, 它可以控制系統如何響應各種硬體事件. 允許你限制或者重新分配伺服器的工作負載, 從而讓伺服器更有效的工作. 以網絡卡中斷為例,在沒有設定SMP IRQ affinity時, 所有網絡卡中斷都關聯到CPU0, 這導致了CPU0負載過高,而無法有效快速的處理網路資料包,導致了瓶頸。 通過SMP IRQ affinity, 把網絡卡多箇中斷分配到多個CPU上,可以分散CPU壓力,提高資料處理速度。
使用前提
- 需要多CPU的系統
- 需要大於等於2.4的Linux 核心
相關設定檔案
1. /proc/irq/IRQ#/smp_affinity
- /proc/irq/IRQ#/smp_affinity 和 /proc/irq/IRQ#/smp_affinity_list 指定了哪些CPU能夠關聯到一個給定的IRQ源. 這兩個檔案包含了這些指定cpu的cpu位掩碼(smp_affinity)和cpu列表(smp_affinity_list). 不允許關閉所有CPU, 同時如果IRQ控制器不支援中斷請求親和(IRQ affinity),則這些設定的值將保持不變(既關聯到所有CPU). 設定方法如下
1 |
echo $bitmask
> /proc/irq/IRQ #/smp_affinity
|
- 示例(把44號中斷繫結到前4個CPU(CPU0-3)上面)
1 |
echo f
> /proc/irq/44/smp_affinity
|
2. /proc/irq/IRQ#/smp_affinity_list
- 設定該檔案取得的效果與/proc/irq/IRQ#/smp_affinity是一致的,它們兩者是聯動關係(既設定其中之一,另一個檔案也隨著改變), 有些系統可能沒有該檔案, 設定方法如下