前言
何為性能優化?個人認為,性能優化是為了提高應用程序或系統能力為目的。那么如何才能實現對應用程序的性能調優呢?這里很設計到很多的內容,包括Linux內核、CPU架構以及Linux內核對資源的分配以及管理,了解進程的創建過程等。這方面由於篇幅較多,所以我的文章就不過多介紹。接下來的幾篇文章中,都是講解如何發現應用程序故障根源為目標講解,這也是每一個系統工程師應該具備的能力。廢話不多說,我直接進入主題。
常用術語
延時:延時是描述操作之后用來等待返回結果的時間。在某些情況下,它可以指的是整個操作時間,等同於響應時間。
IOPS:每秒發生的輸入/輸出操作的次數,是數據傳輸的一個度量方法。對於磁盤的讀寫,IOPS指的是每秒讀寫的次數。
響應時間:一般操作完成的時間。包括用於等待和服務的時間,也包括用來返回結果的時間。
使用率:對於服務所請求的資源,使用率描述在所給定時間區間內資源的繁忙程度。對於春初資源來說,使用率指的就是所消耗的存儲容量。
飽和度:指的就是某一資源無法滿足服務的排隊工作量。
吞吐量:評價工作秩序的速率,尤其是在數據傳輸方面,這個屬於用於數據傳輸速度(字節/秒和比特/秒)。在某些情況下,吞吐量指的是操作的速度。
Linux內核功能
CPU調度級別:各種先進的CPU調度算法,非一直存儲訪問架構(NUMA);
I/O調度界別:I/O調度算法,包括deadline/anticipatory和完全公平隊列(CFQ);
TCP網絡阻塞:TCP擁堵算法,允許按需選擇;
常見問題
進程、線程和任務之間的區別是什么?
進程通常定義為程序的執行。用以執行用戶級別程序的環境。它包括內存地址空間、文件描述符、線程棧和寄存器。
線程是某一進程中單獨運行的程序。也就是說線程在進程之中。
任務是程序完成的某一活動,可以使一個進程,也可以是一個線程。
參考連接:http://blog.chinaunix.net/uid-25100840-id-271078.html
什么是上下文切換?
執行一段程序代碼,實現一個功能的過程介紹,當得到CPU的時候,相關的資源必須也已經就位,就是顯卡、內存、GPS等,然后CPU開始執行。這里除了CPU以外所有的就構成了這個程序的執行環境,也就是我們所定義的程序上下文。當這個程序執行完或者分配給他的CPU執行時間用完了,那它就要被切換出去,等待下一次CPU的臨幸。在被切換出去的最后一步工作就是保存程序上下文,因為這個是下次他被CPU臨幸的運行環境,必須保存。
I/O密集型和CPU密集型工作負載之間的區別?
I/O密集型指的是系統的CPU耗能相對硬盤/內存的耗能能要好很多,此時,系統運作,大部分的狀況是 CPU 在等 I/O(硬盤/內存)的讀/寫,此時CPU負載不高。CPU密集型指的是系統的硬盤/內存耗能相對CPU的耗能要好很多,此時,系統運作,大部分的狀況是 CPU負載 100%,CPU 要讀/寫 I/O (硬盤/內存),I/O在很短的時間就可以完成,而CPU還有許多運算要處理,CPU負載很高。一般而言CPU占用率相當高,大部份時間用來做計算、邏輯判斷等CPU動作的程序。
應用程序性能技術
1.選擇I/O尺寸
執行I/O的開銷包括初始化緩沖區、系統調用、上下文切換、分配內核元數據、檢查進程權限和限制、映射地址到設備、執行內核和驅動代碼來執行I/O,以及在最后釋放元數據和緩沖區。增加I/O尺寸是應用程序提高吞吐量的常用策略。
2.緩存
操作系統用緩存提高文件系統的讀性能和內存的分配性能,應用程序使用緩存也處於類似的原因。將經常執行的操作結果保存在本地緩存中以備后用,而非總是執行開銷較高的操作。
3.緩沖區
為了提高寫操作性能,數據在送入下一層級之前會合並並放在緩沖區中。這樣會增加寫延時,因為第一次寫入緩沖區后,在發送之前,還要等待后續的寫入。
4. 並發和並行
並行:裝在和開始執行多個可運行程序的能力(比如,同時接電話和吃飯)。為了利用多核處理器系統的優勢,應用程序需要在同一時間運行在多顆CPU上,這種方式稱為並行。應用程序通過多進程或多線程實現。
並發:有處理多個任務的能力,不一定要同時。比如,接完電話在去吃飯,存在資源搶占;
同步原語:同步原語監管內存的訪問,當不允許訪問時,就會引起等待時間(延時)。常見三種類型:
mutex鎖:只有鎖持有者才能操作,其他線程會阻塞並等待CPU;
自旋鎖:自旋鎖允許鎖持有者操作,其他的需要自旋鎖的線程會在CPU上循環自選,檢查鎖是否被釋放。雖然這樣可以提供低延時的訪問,被阻塞的線程不會離開CPU,時刻准備着運行知道鎖可用,但是線程自旋、等待也是對CPU資源的浪費。
讀寫鎖:讀/寫鎖通過允許多個讀者或者只允許一個寫者而沒有讀者,來保證數據的完整性。
自適應自旋鎖:低延遲的訪問而不浪費CPU資源,是mutex鎖和自旋鎖的混合。
5.綁定CPU
關於CPU性能分析
uptime:
系統負載,通過匯總正在運行的線程數和正在排隊等待運行的線程數計算得出。分別反映1/5/15分鍾以內的負載。現在的平均負載不僅用來表示CPU余量或者飽和度,也不能單從這個值推斷出CPU或者磁盤負載。
vmstat:
虛擬內存統計信息命令。最后幾列打印系統全局范圍內的CPU使用狀態,在第一列顯示可運行進程數。如下所示:
[root@zbredis-30104 ~]# vmstat procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 14834208 158384 936512 0 0 0 0 1 3 0 0 100 0 0
提示:
r: 運行隊列長度和正在運行的線程數;
b: 表示阻塞的進程數;
swpd: 虛擬內存已使用的大小,如果大於0,表示你的機器物理內存不足了,如果不是程序內存泄露的原因,那么你該升級內存了或者把耗內存的任務遷移到其他機器;
si: 每秒從磁盤讀入虛擬內存的大小,如果這個值大於0,表示物理內存不夠用或者內存泄露了,要查找耗內存進程解決掉。我的機器內存充裕,一切正常。
so: 每秒虛擬內存寫入磁盤的大小,如果這個值大於0,同上;
bi: 塊設備每秒接收的塊數量,這里的塊設備是指系統上所有的磁盤和其他塊設備,默認塊大小是1024byte,我本機上沒什么IO操作,所以一直是0,但是我曾在處理拷貝大量數據(2-3T)的機器上看過可以達到140000/s,磁盤寫入速度差不多140M每秒;
bo: 塊設備每秒發送的塊數量,例如我們讀取文件,bo就要大於0。bi和bo一般都要接近0,不然就是IO過於頻繁,需要調整;
in: 每秒CPU的中斷次數,包括時間中斷;
cs: 每秒上下文切換次數,例如我們調用系統函數,就要進行上下文切換,線程的切換,也要進程上下文切換,這個值要越小越好,太大了,要考慮調低線程或者進程的數目,例如在apache和nginx這種web服務器中,我們一般做性能測試時會進行幾千並發甚至幾萬並發的測試,選擇web服務器的進程可以由進程或者線程的峰值一直下調,壓測,直到cs到一個比較小的值,這個進程和線程數就是比較合適的值了。系統調用也是,每次調用系統函數,我們的代碼就會進入內核空間,導致上下文切換,這個是很耗資源,也要盡量避免頻繁調用系統函數。上下文切換次數過多表示你的CPU大部分浪費在上下文切換,導致CPU干正經事的時間少了,CPU沒有充分利用,是不可取的。
st: cpu在虛擬化環境上在其他租戶上的開銷;
mpstat:
多處理器統計信息工具,能夠報告每個CPU的統計信息。
[root@zbredis-30104 ~]# mpstat -P ALL 1 Linux 2.6.32-573.el6.x86_64 (zbredis-30104) 09/14/2017 _x86_64_ (12 CPU) 03:14:03 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 03:14:04 PM all 0.00 0.00 0.08 0.00 0.00 0.00 0.00 0.00 99.92 03:14:04 PM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 4 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 5 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 6 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 8 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 9 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 10 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 03:14:04 PM 11 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
提示:
irq: 硬件中斷CPU用量;
sofr: 軟件中斷CPU用量;
steal: 耗費在服務其他租戶的時間;
guest: 花在訪客虛擬機的時間;
重要關注列有%user/%sys/%idle。顯示了每個CPU的用量以及用戶態和內核態的時間比例。可以根據這些值查看那些跑到100%使用率(%user + %sys)的CPU,而其他CPU並未跑滿可能是由單線程應用程序的負載或者設備中斷映射造成。
sar:
系統活動報告器。用來觀察當前的活動,以及配置用以歸檔和報告歷史統計信息。基本上所有資源使用的信息,它都能夠查看到。具體的參數說明如下所示:
-A: 所有報告的總和,類似"-bBdqrRSuvwWy -I SUM -I XALL -n ALL -u ALL -P ALL"參數一起使用;
-b: 顯示I/O和傳輸速率的統計信息;
-B:顯示分頁狀態;
-d:硬盤使用報告;
-r:內存和交換空間的使用統計;
-g:串口I/O的情況;
-b:緩沖區使用情況;
-a:文件讀寫情況;
-c:系統調用情況;
-n: 統計網絡信息;
-q:報告隊列長度和系統平均負載;
-R:進程的活動情況;
-y:終端設備活動情況;
-w:系統交換活動;
-x { pid | SELF | ALL }:報告指定進程ID的統計信息,SELF關鍵字是sar進程本身的統計,ALL關鍵字是所有系統進程的統計;
常用參數組合:
查看CPU:
整體CPU統計— sar -u 3 2,表示采樣時間為3秒,采樣次數為2次;
各個CPU統計— sar -P ALL 1 1,表示采樣時間為1秒,次數為1次;
1. 若 %iowait 的值過高,表示硬盤存在I/O瓶頸;
2. 若 %idle 的值高但系統響應慢時,有可能是 CPU 等待分配內存,此時應加大內存容量;
3. 若 %idle 的值持續低於1,則系統的 CPU 處理能力相對較低,表明系統中最需要解決的資源是 CPU;
查看內存:
查看內存使用情況 - sar -r 1 2
kbcommit:保證當前系統所需要的內存,即為了確保不溢出而需要的內存(RAM+swap);
%commit:這個值是kbcommit與內存總量(包括swap)的一個百分比;
pidstat:主要用於監控全部或指定進程占用系統資源的情況,如CPU,內存、設備IO、任務切換、線程等。
cpu使用情況統計
執行 "pidstat -u" 與單獨執行 "pidstat"
內存使用情況統計
pidstat -r -p PID 1
minflt/s: 每秒次缺頁錯誤次數(minor page faults),次缺頁錯誤次數意即虛擬內存地址映射成物理內存地址產生的page fault次數;
majflt/s: 每秒主缺頁錯誤次數(major page faults),當虛擬內存地址映射成物理內存地址時,相應的page在swap中,這樣的page fault為major page fault,一般在內存使用緊張時產生;
IO情況統計
pidstat -d 1 2
關於CPU方面的優化
1.編譯器優化
2.調度優先級和調度類(設置nice值)
例如,nice -n 19 command
renice 更改已經運行進程的優先級;
chrt 命令顯示並直接修改優先級和調度策略;
3.進程綁定(一個進程可以綁定在一個或者多個CPU上)
例如,taskset -pc 0-3 10790
4.獨占CPU
5.BIOS調優
啟用睿頻