【1024程序員節(jié)獻(xiàn)禮】鯤鵬性能優(yōu)化十板斧(二)——CPU與內(nèi)存子系統(tǒng)性能調(diào)優(yōu)
1.1 CPU與內(nèi)存子系統(tǒng)性能調(diào)優(yōu)簡(jiǎn)介
調(diào)優(yōu)思路
性能優(yōu)化的思路如下:
l?? 如果CPU的利用率不高,說(shuō)明資源沒(méi)有充分利用,可以通過(guò)工具(如strace)查看應(yīng)用程序阻塞在哪里,一般為磁盤(pán),網(wǎng)絡(luò)或應(yīng)用程序的業(yè)務(wù)處理中存在休眠或信號(hào)等待,這些優(yōu)化措施在后續(xù)其它章節(jié)描述。
l?? 如果CPU利用率高,通過(guò)優(yōu)化軟件硬件的配置參數(shù)來(lái)更好適配業(yè)務(wù)場(chǎng)景,減少CPU占用率,讓整個(gè)系統(tǒng)有更多的CPU時(shí)間來(lái)處理業(yè)務(wù)。
我們也可以選擇更好的硬件,根據(jù)CPU的能力配置合適的內(nèi)存條,建議內(nèi)存滿通道配置,發(fā)揮內(nèi)存最大帶寬:一顆鯤鵬920處理器的內(nèi)存通道數(shù)為8,兩顆鯤鵬920處理器的內(nèi)存通道數(shù)為16;建議選擇高頻率的內(nèi)存條,提升內(nèi)存帶寬:鯤鵬920在1DPC配置時(shí),支持的內(nèi)存最高頻率為2933MHz。
主要優(yōu)化參數(shù)
優(yōu)化項(xiàng)
優(yōu)化項(xiàng)簡(jiǎn)介
默認(rèn)值
生效范圍
鯤鵬916
鯤鵬920
優(yōu)化應(yīng)用程序的NUMA配置
在NUMA架構(gòu)下,CPU core訪問(wèn)臨近的內(nèi)存時(shí)訪問(wèn)延遲更低。將應(yīng)用程序綁在一個(gè)NUMA節(jié)點(diǎn),可減少因訪問(wèn)遠(yuǎn)端內(nèi)存帶來(lái)的性能下降。
默認(rèn)不綁定核
立即生效
yes
yes
修改CPU預(yù)取開(kāi)關(guān)
內(nèi)存預(yù)取在數(shù)據(jù)集中場(chǎng)景下可以提前將要訪問(wèn)的數(shù)據(jù)讀到CPU cache 中,提升性能;若數(shù)據(jù)不集中,導(dǎo)致預(yù)取命中率低,則浪費(fèi)內(nèi)存帶寬。
on
重啟生效
no
yes
調(diào)整定時(shí)器機(jī)制
nohz機(jī)制可減少不必要的時(shí)鐘中斷,減少CPU調(diào)度開(kāi)銷。
不同OS默認(rèn)配置不同
Euler:nohz=off
重啟生效
yes
yes
調(diào)整內(nèi)存的頁(yè)大小為64K
內(nèi)存的頁(yè)大小越大,TLB中每行管理的內(nèi)存越多,TLB命中率就越高,從而減少內(nèi)存訪問(wèn)次數(shù)。
不同OS默認(rèn)配置不同:
4KB或64K
重新編譯內(nèi)核、更新內(nèi)核后生效
yes
yes
優(yōu)化應(yīng)用程序的線程并發(fā)數(shù)
適當(dāng)調(diào)整應(yīng)用的線程并發(fā)數(shù),使得充分利用多核能力和資源爭(zhēng)搶之間達(dá)到平衡。
由應(yīng)用本身決定
立即生效或重啟生效(由應(yīng)用決定)
yes
yes
1.2 常用性能監(jiān)測(cè)工具
1.2.1 top工具
介紹
top是最常用的Linux性能監(jiān)測(cè)工具之一。通過(guò)top工具可以監(jiān)視進(jìn)程和系統(tǒng)整體性能。
命令參考舉例:
命令
說(shuō)明
top
查看系統(tǒng)整體的CPU、內(nèi)存資源消耗。
top執(zhí)行后輸入1
查看每個(gè)CPU core資源使用情況。
top執(zhí)行后輸入F,并選擇P選項(xiàng)
查看線程執(zhí)行過(guò)程中是否調(diào)度到其它CPU core。
top -p $PID -H
查看某個(gè)進(jìn)程內(nèi)所有線程的CPU資源占用。
安裝方式
系統(tǒng)自帶,無(wú)需安裝。
使用方法
步驟 1????? 使用top命令統(tǒng)計(jì)整體CPU、內(nèi)存資源消耗。
l?? CPU項(xiàng):顯示當(dāng)前總的CPU時(shí)間使用分布。
us表示用戶態(tài)程序占用的CPU時(shí)間百分比。
sy表示內(nèi)核態(tài)程序所占用的CPU時(shí)間百分比。
wa表示等待IO等待占用的CPU時(shí)間百分比。
hi表示硬中斷所占用的CPU時(shí)間百分比。
si表示軟中斷所占用的CPU時(shí)間百分比。
通過(guò)這些參數(shù)我們可以分析CPU時(shí)間的分布,是否有較多的IO等待。在執(zhí)行完調(diào)優(yōu)步驟后,我們也可以對(duì)CPU使用時(shí)間進(jìn)行前后對(duì)比。如果在運(yùn)行相同程序、業(yè)務(wù)情況下CPU使用時(shí)間降低,說(shuō)明性能有提升。
l?? KiB Mem:表示服務(wù)器的總內(nèi)存大小以及使用情況。
l?? KiB Swap:表示當(dāng)前所使用的Swap空間的大小。Swap空間即當(dāng)內(nèi)存不足的時(shí)候,把一部分硬盤(pán)空間虛擬成內(nèi)存使用。如果當(dāng)前所使用的Swap空間大于0,可以考慮優(yōu)化應(yīng)用的內(nèi)存占用或增加物理內(nèi)存。
步驟 2????? 在top命令執(zhí)行后按1,查看每個(gè)CPU core的使用情況。
通過(guò)該命令可以查看單個(gè)CPU core的使用情況,如果CPU占用集中在某幾個(gè)CPU core上,可以結(jié)合業(yè)務(wù)分析觸發(fā)原因,從而找到優(yōu)化思路。
步驟 3????? 選中top命令的P選項(xiàng),查看線程運(yùn)行在哪些 CPU core上。
在top命令執(zhí)行后按F,可以進(jìn)入top命令管理界面。在該界面通過(guò)上下鍵移動(dòng)光標(biāo)到P選項(xiàng),通過(guò)空格鍵選中后按Esc退出,即可顯示出線程運(yùn)行的CPU核。觀察一段時(shí)間,若業(yè)務(wù)線程在不同NUMA節(jié)點(diǎn)內(nèi)的CPU core上運(yùn)行,則說(shuō)明存在較多的跨NUMA訪問(wèn),可通過(guò)NUMA綁核進(jìn)行優(yōu)化。
步驟 4????? 使用top -p $PID -H命令觀察進(jìn)程中每個(gè)線程的CPU資源使用。
“-p”后接的參數(shù)為待觀察的進(jìn)程ID。通過(guò)該命令可以找出消耗資源多的線程,隨后可根據(jù)線程號(hào)分析線程中的熱點(diǎn)函數(shù)、調(diào)用過(guò)程等情況。
----結(jié)束
1.2.2 Perf工具
介紹
Perf工具是非常強(qiáng)大的Linux性能分析工具,可以通過(guò)該工具獲得進(jìn)程內(nèi)的調(diào)用情況、資源消耗情況并查找分析熱點(diǎn)函數(shù)。
命令參考舉例:
命令
說(shuō)明
perf top
查看當(dāng)前系統(tǒng)中的熱點(diǎn)函數(shù)。
perf sched record -- sleep 1 -p $PID
記錄進(jìn)程在1s內(nèi)的系統(tǒng)調(diào)用。
perf sched latency --sort max
查看上一步記錄的結(jié)果,以調(diào)度延遲排序。
安裝方式
以CentOS為例,使用如下命令安裝:
# yum -y install perf
使用方法
步驟 1????? 通過(guò)perf top命令查找熱點(diǎn)函數(shù)。
該命令統(tǒng)計(jì)各個(gè)函數(shù)在某個(gè)性能事件上的熱度,默認(rèn)顯示CPU占用率,可以通過(guò)“-e”監(jiān)控其它事件。
l?? Overhead表示當(dāng)前事件在全部事件中占的比例。
l?? Shared Object表示當(dāng)前事件生產(chǎn)者,如kernel、perf命令、C語(yǔ)言庫(kù)函數(shù)等。
l?? Symbol則表示熱點(diǎn)事件對(duì)應(yīng)的函數(shù)名稱。
通過(guò)熱點(diǎn)函數(shù),我們可以找到消耗資源較多的行為,從而有針對(duì)性的進(jìn)行優(yōu)化。
步驟 2????? 收集一段時(shí)間內(nèi)的線程調(diào)用。
perf sched record命令用于記錄一段時(shí)間內(nèi),進(jìn)程的調(diào)用情況。“-p”后接進(jìn)程號(hào),“sleep”后接統(tǒng)計(jì)時(shí)長(zhǎng),單位為秒。收集到的信息自動(dòng)存放在當(dāng)前目錄下,文件名為perf.data。
步驟 3????? 解析收集到的線程調(diào)度信息。
perf sched latency命令可以解析當(dāng)前目錄下的perf.data文件。“-s”表示進(jìn)行排序,后接參數(shù)“max”表示按照最大延遲時(shí)間大小排序。
----結(jié)束
1.2.3 numactl工具
介紹
numactl工具可用于查看當(dāng)前服務(wù)器的NUMA節(jié)點(diǎn)配置、狀態(tài),可通過(guò)該工具將進(jìn)程綁定到指定CPU core,由指定CPU core來(lái)運(yùn)行對(duì)應(yīng)進(jìn)程。
命令參考舉例:
命令
說(shuō)明
numactl -H
查看當(dāng)前服務(wù)器的NUMA配置。
numactl -C 0-7 ./test
將應(yīng)用程序test綁定到0~7核運(yùn)行。
numastat
查看當(dāng)前的NUMA運(yùn)行狀態(tài)。
安裝方式
以CentOS為例,使用如下命令安裝:
# yum -y install numactl numastat
使用方法
步驟 1????? 通過(guò)numactl查看當(dāng)前服務(wù)器的NUMA配置。
從numactl執(zhí)行結(jié)果可以看到,示例服務(wù)器共劃分為4個(gè)NUMA節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)包含16個(gè)CPU core,每個(gè)節(jié)點(diǎn)的內(nèi)存大小約為64GB。同時(shí),該命令還給出了不同節(jié)點(diǎn)間的距離,距離越遠(yuǎn),跨NUMA內(nèi)存訪問(wèn)的延時(shí)越大。應(yīng)用程序運(yùn)行時(shí)應(yīng)減少跨NUMA訪問(wèn)內(nèi)存。
步驟 2????? 通過(guò)numactl將進(jìn)程綁定到指定CPU core。
通過(guò) numactl -C 0-15 top 命令即是將進(jìn)程“top”綁定到0~15 CPU core上執(zhí)行。
步驟 3????? 通過(guò)numastat查看當(dāng)前NUMA節(jié)點(diǎn)的內(nèi)存訪問(wèn)命中率。
可以通過(guò)numastat命令觀察各個(gè)NUMA節(jié)點(diǎn)的狀態(tài)。
l?? numa_hit表示節(jié)點(diǎn)內(nèi)CPU核訪問(wèn)本地內(nèi)存的次數(shù)。
l?? numa_miss表示節(jié)點(diǎn)內(nèi)核訪問(wèn)其他節(jié)點(diǎn)內(nèi)存的次數(shù)。跨節(jié)點(diǎn)的內(nèi)存訪問(wèn)會(huì)存在高延遲從而降低性能,因此,numa_miss的值應(yīng)當(dāng)越低越好,如果過(guò)高,則應(yīng)當(dāng)考慮綁核。
----結(jié)束
1.3 優(yōu)化方法
1.3.1 NUMA優(yōu)化,減少跨NUMA訪問(wèn)內(nèi)存
原理
通過(guò)1.1 鯤鵬處理器NUMA簡(jiǎn)介章節(jié)可以看到不同NUMA內(nèi)的CPU core訪問(wèn)同一個(gè)位置的內(nèi)存,性能不同。內(nèi)存訪問(wèn)延時(shí)從高到低為:跨CPU > 跨NUMA不跨CPU > NUMA內(nèi)
因此在應(yīng)用程序運(yùn)行時(shí)要盡可能的避免跨NUMA訪問(wèn)內(nèi)存,我們可以通過(guò)設(shè)置線程的CPU親和性來(lái)實(shí)現(xiàn)。
修改方式
l?? 網(wǎng)絡(luò)可以通過(guò)如下方式綁定運(yùn)行的CPU core,其中$cpuMask是16進(jìn)制的數(shù),最右邊的bit表示core0;$irq為網(wǎng)卡隊(duì)列中斷號(hào)。
echo $cpuMask > /proc/irq/$irq/smp_affinity_list
l?? 通過(guò)numactl啟動(dòng)程序,如下面的啟動(dòng)命令表示啟動(dòng)test程序,只能在CPU core 28到core31運(yùn)行(-C控制)。
numactl -C 28-31 ./test
l?? 在C/C++代碼中通過(guò)sched_setaffinity函數(shù)來(lái)設(shè)置線程親和性。
l?? 很多開(kāi)源軟件已經(jīng)支持在自帶的配置文件中修改線程的親和性,例如nginx可以修改nginx.conf文件中的worker_cpu_affinity參數(shù)來(lái)設(shè)置nginx線程親和性。
1.3.2 修改CPU的預(yù)取開(kāi)關(guān)
原理
局部性原理分為時(shí)間局部性原理和空間局部性原理:
l?? 時(shí)間局部性原理(temporal locality):如果某個(gè)數(shù)據(jù)項(xiàng)被訪問(wèn),那么在不久的將來(lái)它可能再次被訪問(wèn)。
l?? 空間局部性原理(spatial locality):如果某個(gè)數(shù)據(jù)項(xiàng)被訪問(wèn),那么與其地址相鄰的數(shù)據(jù)項(xiàng)可能很快也會(huì)被訪問(wèn)。
CPU將內(nèi)存中的數(shù)據(jù)讀到CPU的高速緩沖Cache時(shí),會(huì)根據(jù)局部性原理,除了讀取本次要訪問(wèn)的數(shù)據(jù),還會(huì)預(yù)取本次數(shù)據(jù)的周邊數(shù)據(jù)到Cache里面,如果預(yù)取的數(shù)據(jù)是下次要訪問(wèn)的數(shù)據(jù),那么性能會(huì)提升,如果預(yù)取的數(shù)據(jù)不是下次要取的數(shù)據(jù),那么會(huì)浪費(fèi)內(nèi)存帶寬。
對(duì)于數(shù)據(jù)比較集中的場(chǎng)景,預(yù)取的命中率高,適合打開(kāi)CPU預(yù)取,反之需要關(guān)閉CPU預(yù)取。目前發(fā)現(xiàn)speccpu和X265軟件場(chǎng)景適合打開(kāi)CPU預(yù)取,STREAM測(cè)試工具、Nginx和數(shù)據(jù)庫(kù)場(chǎng)景需要關(guān)閉CPU預(yù)取。
修改方式
按照B 進(jìn)入BIOS界面的步驟進(jìn)入BIOS,然后在BIOS的如下位置設(shè)置CPU的預(yù)取開(kāi)關(guān)。
1.3.3 定時(shí)器機(jī)制調(diào)整,減少不必要的時(shí)鐘中斷
原理
在Linux內(nèi)核2.6.17版本之前,Linux內(nèi)核為每個(gè)CPU設(shè)置一個(gè)周期性的時(shí)鐘中斷,Linux內(nèi)核利用這個(gè)中斷處理一些定時(shí)任務(wù),如線程調(diào)度等。這樣導(dǎo)致就算CPU不需要定時(shí)器的時(shí)候,也會(huì)有很多時(shí)鐘中斷,導(dǎo)致資源的浪費(fèi)。Linux 內(nèi)核2.6.17版本引入了nohz機(jī)制,實(shí)際就是讓時(shí)鐘中斷的時(shí)間可編程,減少不必要的時(shí)鐘中斷。
修改方式
執(zhí)行cat /proc/cmdline查看Linux 內(nèi)核的啟動(dòng)參數(shù),如果有nohz=off關(guān)鍵字,說(shuō)明nohz機(jī)制被關(guān)閉,需要打開(kāi)。修改方法如下:
修改前后,可以通過(guò)如下命令觀察timer_tick的調(diào)度次數(shù),其中$PID為要觀察的進(jìn)程ID,可以選擇CPU占用高的進(jìn)程進(jìn)行觀察:
perf sched record -- sleep 1 -p $PID
perf sched latency -s max
輸出信息中有如下信息,其中591字段表示統(tǒng)計(jì)時(shí)間內(nèi)的調(diào)度次數(shù),數(shù)字變小說(shuō)明修改生效。
timer_tick:(97) | 7.364 ms | 591 | avg: 0.012 ms | max: 1.268 ms
步驟 1????? 在“/boot”目錄下通過(guò)find -name grub.cfg找到啟動(dòng)參數(shù)的配置文件。
步驟 2????? 在配置文件中將nohz=off去掉。
步驟 3????? 重啟服務(wù)器。
----結(jié)束
1.3.4 調(diào)整內(nèi)存頁(yè)的大小為64K,提升TLB命中率
原理
TLB(Translation lookaside buffer)為頁(yè)表(存放虛擬地址的頁(yè)地址和物理地址的頁(yè)地址的映射關(guān)系)在CPU內(nèi)部的高速緩存。TLB的命中率越高,頁(yè)表查詢性能就越好。
TLB的一行為一個(gè)頁(yè)的映射關(guān)系,也就是管理了一個(gè)頁(yè)大小的內(nèi)存:
TLB管理的內(nèi)存大小 = TLB行數(shù) x 內(nèi)存的頁(yè)大小
同一個(gè)CPU的TLB行數(shù)固定,因此內(nèi)存頁(yè)越大,管理的內(nèi)存越大,相同業(yè)務(wù)場(chǎng)景下的TLB命中率就越高。
修改方式
修改Linux內(nèi)核編譯選項(xiàng),并重新編譯:
修改前后可以通過(guò)如下命令觀察TLB的命中率($PID為進(jìn)程ID):
perf stat -p $PID -d -d -d
輸出結(jié)果包含如下信息,其中1.21%和0.59%分別表示數(shù)據(jù)的miss率和指令的miss率。
1,090,788,717????? dTLB-loads??????????????? #? 520.592 M/sec
13,213,603????? dTLB-load-misses????????? #??? 1.21% of all dTLB cache hits
669,485,765????? iTLB-loads??????????????? #? 319.520 M/sec
3,979,246????? iTLB-load-misses????????? #??? 0.59% of all iTLB cache hits
步驟 1????? 執(zhí)行make menuconfig。
步驟 2????? 選擇PAGESIZE大小為64K。
Kernel Features-->Page size(64KB)
步驟 3????? 編譯和安裝內(nèi)核。
參考https://bbs.huaweicloud.com/forum/thread-24362-1-1.html
----結(jié)束
1.3.5 調(diào)整線程并發(fā)數(shù)
原理
程序從單線程變?yōu)槎嗑€程時(shí),CPU和內(nèi)存資源得到充分利用,性能得到提升。但是系統(tǒng)的性能并不會(huì)隨著線程數(shù)的增長(zhǎng)而線性提升,因?yàn)殡S著線程數(shù)量的增加,線程之間的調(diào)度、上下文切換、關(guān)鍵資源和鎖的競(jìng)爭(zhēng)也會(huì)帶來(lái)很大開(kāi)銷。當(dāng)資源的爭(zhēng)搶比較嚴(yán)重時(shí),甚至?xí)?dǎo)致性能明顯降。下面數(shù)據(jù)為某業(yè)務(wù)場(chǎng)景下,不同并發(fā)線程數(shù)下的TPS,可以看到并發(fā)線程數(shù)達(dá)到128后,性能達(dá)到高峰,隨后開(kāi)始下降。我們需要針對(duì)不同的業(yè)務(wù)模型和使用場(chǎng)景做多組測(cè)試,找到適合本業(yè)務(wù)場(chǎng)景的最佳并發(fā)線程數(shù)。
修改方式
不同的軟件有不同的配置,需要根據(jù)代碼實(shí)現(xiàn)來(lái)修改,這里舉例幾個(gè)常用開(kāi)源軟件的修改方法:
MySql可以通過(guò)innodb_thread_concurrency設(shè)置工作線程的最大并發(fā)數(shù)。
Nginx可以通過(guò)worker_processes參數(shù)設(shè)置并發(fā)的進(jìn)程個(gè)數(shù)。
下一篇:網(wǎng)絡(luò)子系統(tǒng)性能調(diào)優(yōu),敬請(qǐng)期待
鯤鵬
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。