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