硬體中斷髮生頻繁,是件很消耗 CPU 資源的事情,在多核 CPU 條件下如果有辦法把大量硬體中斷分配給不同的 CPU (core) 處理顯然能很好的平衡效能。現在的伺服器上動不動就是多 CPU 多核、多網卡、多硬碟,如果能讓網卡中斷獨佔1個 CPU (core)、磁碟 IO 中斷獨佔1個 CPU 的話將會大大減輕單一 CPU 的負擔、提高整體處理效率。VPSee 前天收到一位網友的郵件提到了 SMP IRQ Affinity,引發了今天的話題:D,以下操作在 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 eth0233: 10 0 IO-APIC-level ehci_hcd:usb1NMI: 5077 2032LOC: 918809969 918809894ERR: 0MIS: 0
為了不讓 CPU0 很累怎麼把部分中斷轉移到 CPU1 上呢?或者說如何把 eth0 網卡的中斷轉到 CPU1 上呢?先查看一下 IRQ 90 中斷的 smp affinity,看看當前中斷是怎麼分配在不同 CPU 上的(ffffffff 意味著分配在所有可用 CPU 上):
# cat /proc/irq/90/smp_affinity7fffffff,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
(上面的 echo “2″ 是怎麼來的?為什麼是 ”2“?請參考這篇:計算 SMP IRQ 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 eth0233: 10 0 IO-APIC-level ehci_hcd:usb1NMI: 5093 2043LOC: 922389696 922389621ERR: 0MIS: 0
有什麼用
在網路非常 heavy 的情況下,對於檔案伺服器、高流量 Web 服務器這樣的應用來說,把不同的網卡 IRQ 均衡綁定到不同的 CPU 上將會減輕某個 CPU 的負擔,提高多個 CPU 整體處理中斷的能力;對於資料庫伺服器這樣的應用來說,把磁碟控制卡綁到一個 CPU、把網卡綁定到另一個 CPU 將會提高資料庫的回應時間、最佳化效能。合理的根據自己的生產環境和應用的特點來平衡 IRQ 中斷有助於提高系統的整體吞吐能力和效能。
VPSee 經常收到網友來信問到如何最佳化 Linux、最佳化 VPS、這個問題不太好回答,要記住的是效能最佳化是一個過程而不是結果,不是看了些文檔改了改參數就叫最佳化了,後面還需要大量的測試、監測以及持續的觀察和改進。