觀察發現4核CPU,只有第1個核心(CPU#0)很是忙,其餘都處於idle狀態。php
不瞭解Linux是如何調度的,但目前顯然有優化的餘地。除了處理正常任務,CPU#0還須要處理每秒網卡中斷。所以,若能將CPU#0分擔的任務攤派到其餘CPU核心上,能夠預見,系統的處理能力將有更大的提高。html
兩個名詞mysql
SMP (Symmetrical Multi-Processing):指在一個計算機上聚集了一組處理器(多CPU),各CPU之間共享內存子系統以及總線結構。SMP意爲對稱多處理系統,內有許多緊耦合多處理器,這種系統的最大特色就是共享全部資源。另外與之相對立的標準是MPP (Massively Parallel Processing),意爲大規模並行處理系統,這樣的系統是由許多鬆耦合處理單元組成的,要注意的是這裏指的是處理單元而不是處理器。每一個單元內的CPU都有本身私有的資源,如總線、內存、硬盤等。在每一個單元內都有操做系統和管理數據庫的實例複本。這種結構最大的特色在於不共享資源 [更多...]linux
CPU affinity:中文喚做「CPU親和力」,是指在CMP架構下,可以將一個或多個進程綁定到一個或多個處理器上運行。[更多...]nginx
1、在Linux上修改進程的「CPU親和力」sql
在Linux上,能夠經過 taskset 命令進行修改,安裝taskset工具。數據庫
# yum install util-linux-ng
對運行中的進程,文檔上說能夠用下面的命令,把CPU#1 #2 #3分配給PID爲2345的進程:緩存
# taskset -cp 1,2,3 2345
但我嘗試沒奏效,因而我關掉了MySQL,並用taskset將它啓動:bash
# taskset -c 1,2,3 /etc/init.d/mysql start
對於其餘進程,也可如此處理(nginx除外,詳見下文)。以後用top查看CPU的使用狀況,原來空閒的#1 #2 #3,已經在辛勤工做了。架構
2、配置nginx綁定CPU
剛纔說nginx除外,是由於nginx提供了更精確的控制。
在conf/nginx.conf中,有以下一行:
worker_processes 1;
這是用來配置nginx啓動幾個工做進程的,默認爲1。而nginx還支持一個名爲worker_cpu_affinity的配置項,也就是說,nginx能夠爲每一個工做進程綁定CPU。我作了以下配置:
worker_processes 3; worker_cpu_affinity 0010 0100 1000;
這裏000一、00十、0100、1000是掩碼,分別表明第一、二、三、4顆cpu核心。
重啓nginx後,3個工做進程就能夠各自用各自的CPU了。
3、刨根問底
4、Windows?
在Windows上修改「CPU親和力」,能夠經過任務管理器搞定。
* 我的感受,Windows系統中翻譯的「處理器關係」比「CPU親和力」容易理解點兒
—————–
進行了這樣的修改後,即便系統負載達到3以上,不帶緩存打開blogkid.net首頁(有40屢次查詢)依然順暢;之前一旦負載超過了1.5,響應就很慢了。效果很明顯。
linux taskset命令詳解
SYNOPSIS
taskset [options] [mask | list ] [pid | command [arg]...]
OPTIONS
-p, --pid
operate on an existing PID and not launch a new task
-c, --cpu-list
specifiy a numerical list of processors instead of a bitmask.
The list may contain multiple items, separated by comma, and
ranges. For example, 0,5,7,9-11.
-h, --help
display usage information and exit
-V, --version
output version information and exit
# taskset -p -c 0 16380 或者 taskset -cp 0 16380
# ps -e -o psr,pid,cmd |grep 29165 查驗
psr : 進程當前被分配的處理器
---------------------------------------------------------------
爲客戶提供一個有2個邏輯CPU計算能力的一個客戶機。要求CPU資源獨立被佔用,不受宿主機中其餘客戶機的負載水平的影響。爲了知足這個需求,能夠分爲以下兩個步驟來實現。
第一步,啓動宿主機時隔離出兩個邏輯CPU專門供一個客戶機使用。在Linux內核啓動的命令行加上「isolcpus=」參數,能夠實現CPU的隔離,讓系統啓動後普通進程默認都不會調度到被隔離的CPU上執行。例如,隔離了cpu2和cpu3的grub的配置文件以下:
title Red Hat Enterprise Linux Server (3.5.0)
root (hd0,0)
kernel /boot/vmlinuz-3.5.0 ro root=UUID=1a65b4bb-cd9b-4bbf-97ff-7e1f7698d3db isolcpus=2,3
initrd /boot/initramfs-3.5.0.img
系統啓動後,在宿主機中檢查是否隔離成功,命令行以下:
[root@jay-linux ~]# ps -eLo psr | grep 0 | wc -l 106 [root@jay-linux ~]# ps -eLo psr | grep 1 | wc -l 107 [root@jay-linux ~]# ps -eLo psr | grep 2 | wc -l 4 [root@jay-linux ~]# ps -eLo psr | grep 3 | wc -l 4 [root@jay-linux ~]# ps -eLo ruser,pid,ppid,lwp,psr,args | awk ‘{if($5==2) print $0}’ root 10 2 10 2 [migration/2] root 11 2 11 2 [kworker/2:0] root 12 2 12 2 [ksoftirqd/2] root 245 2 245 2 [kworker/2:1] [root@jay-linux ~]# ps –eLo ruser,pid,ppid,lwp,psr,args | awk ‘{if($5==3) print $0}’ root 13 2 13 3 [migration/3] root 14 2 14 3 [kworker/3:0] root 15 2 15 3 [ksoftirqd/3] root 246 2 246 3 [kworker/3:1]
從上面的命令行輸出信息可知,cpu0和cpu1上分別有106和107個線程在運行,而cpu2和cpu3上都分別只有4個線程在運行。並且,根據輸出信息中cpu2和cpu3上運行的線程信息(也包括進程在內),分別有migration進程(用於進程在不一樣CPU間遷移)、兩個kworker進程(用於處理workqueues)、ksoftirqd進程(用於調度CPU軟中斷的進程),這些進程都是內核對各個CPU的一些守護進程,而沒有其餘的普通進程在cup2和cpu3上運行,說明對其的隔離是生效的。
另外,簡單解釋一下上面的一些命令行工具及其參數的意義。ps命令顯示當前系統的進程信息的狀態,它的「-e」參數用於顯示全部的進程,「-L」參數用於將線程(LWP,light-weight process)也顯示出來,「-o」參數表示以用戶自定義的格式輸出(其中「psr」這列表示當前分配給進程運行的處理器編號,「lwp」列表示線程的ID,「ruser」表示運行進程的用戶,「pid」表示進程的ID,「ppid」表示父進程的ID,「args」表示運行的命令及其參數)。結合ps和awk工具的使用,是爲了分別將在處理器cpu2和cpu3上運行的進程打印出來。
第二步,啓動一個擁有2個vCPU的客戶機並將其vCPU綁定到宿主機中兩個CPU上。此操做過程的命令行以下:
#(啓動一個客戶機)
[root@jay-linux kvm_demo]# qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize
VNC server running on ‘::1:5900’
#(查看錶明vCPU的QEMU線程)
[root@jay-linux ~]# ps -eLo ruser,pid,ppid,lwp,psr,args | grep qemu | grep -v grep root 3963 1 3963 0 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize root 3963 1 3967 0 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize root 3963 1 3968 1 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 –daemonize
#(綁定表明整個客戶機的QEMU進程,使其運行在cpu2上)
[root@jay-linux ~]# taskset -p 0×4 3963
pid 3963′s current affinity mask: 3
pid 3963′s new affinity mask: 4
#(綁定第一個vCPU的線程,使其運行在cpu2上)
[root@jay-linux ~]# taskset -p 0×4 3967
pid 3967′s current affinity mask: 3
pid 3967′s new affinity mask: 4
#(綁定第二個vCPU的線程,使其運行在cpu3上)
[root@jay-linux ~]# taskset -p 0×8 3968
pid 3968′s current affinity mask: 4
pid 3968′s new affinity mask: 8
#(查看QEMU線程的綁定是否生效,以下的第5列爲處理器親和性)
[root@jay-linux ~]# ps -eLo ruser,pid,ppid,lwp,psr,args | grep qemu | grep -v grep root 3963 1 3963 2 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize root 3963 1 3967 2 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize root 3963 1 3968 3 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 –daemonize
#(執行vCPU的綁定後,查看在cpu2上運行的線程)
[root@jay-linux ~]# ps -eLo ruser,pid,ppid,lwp,psr,args | awk ‘{if($5==2) print $0}’ root 10 2 10 2 [migration/2] root 11 2 11 2 [kworker/2:0] root 12 2 12 2 [ksoftirqd/2] root 245 2 245 2 [kworker/2:1] root 3963 1 3963 2 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize root 3963 1 3967 2 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize
#(執行vCPU的綁定後,查看在cpu3上運行的線程)
[root@jay-linux ~]# ps –eLo ruser,pid,ppid,lwp,psr,args | awk ‘{if($5==3) print $0}’ root 13 2 13 3 [migration/3] root 14 2 14 3 [kworker/3:0] root 15 2 15 3 [ksoftirqd/3] root 246 2 246 3 [kworker/3:1] root 3963 1 3968 3 qemu-system-x86_64 rhel6u3.img -smp 2 -m 512 -daemonize
由上面的命令行及其輸出信息可知,CPU綁定以前,表明這個客戶機的QEMU進程和表明各個vCPU的QEMU線程分別被調度到cpu0和cpu1上。使用taskset命令將QEMU進程和第一個vCPU的線程綁定到cpu2,將第二個vCPU線程綁定到cpu3上。綁定以後,便可查看到綁定的結果是生效的,表明兩個vCPU的QEMU線程分別運行在cpu2和cpu3上(即便再過一段時間後,它們也不會被調度到其餘CPU上去)。
對taskset命令解釋一下,此處使用的語法是:taskset -p [mask] pid 。其中,mask是一個表明了處理器親和性的掩碼數字,轉化爲二進制表示後,它的值從最低位到最高位分別表明了第一個邏輯CPU到最後一個邏輯CPU,進程調度器可能將該進程調度到全部標爲「1」的位表明的CPU上去運行。根據上面的輸出,taskset運行以前,QEMU線程的處理器親和性mask值是0×3(其二進制值爲:0011),可知其可能會被調度到cpu0和cpu1上運行;而運行「taskset -p 0×4 3967」命令後,提示新的mask值被設爲0×4(其二進制值爲:0100),因此該進程就只能被調度到cpu2上去運行,即經過taskset工具實現了vCPU進程綁定到特定的CPU上。
上面命令行中,根據ps命令能夠看到QEMU的線程和進程的關係,但如何查看vCPU與QEMU線程之間的關係呢?能夠切換(「Ctrl+Alt+2」快捷鍵)到QEMU monitor中進行查看,運行「info cpus」命令便可(還記得3.6節中運行過的「info kvm」命令吧),其輸出結果以下:
(qemu) info cpus
* CPU #0: pc=0xffffffff810375ab thread_id=3967
CPU #1: pc=0xffffffff812b2594 thread_id=3968
從上面的輸出信息可知,客戶機中的cpu0對應的線程ID爲3967,cpu1對應的線程ID爲3968。另外,「CPU #0」前面有一個星號(*),是標識cpu0是BSP(Boot Strap Processor,系統最初啓動時在SMP生效前使用的CPU)。
總的來講,在KVM環境中,通常並不推薦手動地人爲設置QEMU進程的處理器親和性來綁定vCPU,可是,在很是瞭解系統硬件架構的基礎上,根據實際應用的需求,是能夠將其綁定到特定的CPU上去從而提升客戶機中的CPU執行效率或者實現CPU資源獨享的隔離性。
應該將中斷綁定至那些非隔離的CPU上,從而避免那些隔離的CPU處理中斷程序:
echo CPU_MASK > /proc/irq/ <irq number>/smp_affinity
[root@lopdb1 ~]# cat /proc/irq/2/smp_affinity
7fffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff
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隔離起來。
參考文檔:
https://www.kernel.org/doc/Documentation/IRQ-affinity.txt