1. 程式人生 > 其它 >12-套路篇:CPU效能優化的幾個思路

12-套路篇:CPU效能優化的幾個思路





效能優化方法論

通過各種效能分析方法,終於找到了引發效能問題的瓶頸後,是不是立刻就要開始優化了呢?
動手之前,可以先看看下面這三個問題
1.既然要做效能優化,那要怎麼判斷它是不是有效呢?特別是優化後,到底能提升多少效能呢?
2.效能問題通常不是獨立的,如果有多個性能問題同時發生,應該先優化哪一個呢?
3.提升效能的方法並不是唯一的,當有多種方法可以選擇時,是不是總選那個最大程度提升效能的方法就行了呢?


舉例
前面不可中斷程序案例中,通過效能分析,發現是因為一個程序的直接I/O 
導致了iowait高達90%。那是不是用“直接I/O換成快取I/O”的方法,就可以立即優化了呢?
1.直接I/O換成快取I/O,可以把iowait從90%降到接近0,效能提升很明顯
2.沒有發現其他效能問題,直接I/O是唯一的效能瓶頸,所以不用挑選優化物件
3.快取I/O是目前用到的最簡單的優化方法,而且這樣優化並不會影響應用的功能

這三個問題很容易就能回答,所以立即優化沒有任何問題


1.怎麼評估效能優化的效果?

解決效能問題的目的,自然是想得到一個性能提升的效果
為了評估這個效果,需要對系統的效能指標進行量化
並且要分別測試出優化前、後的效能指標,用前後指標的變化來對比呈現效果
1. 確定性能的量化指標
2. 測試優化前的效能指標
3. 測試優化後的效能指標


1. 確定性能的量化指標
效能的量化指標有很多,比如CPU使用率、應用程式的吞吐量、客戶端請求的延遲等,都可以評估效能
不要侷限在單一維度的指標上,至少要從應用程式和系統資源這兩個維度,分別選擇不同的指標
【舉例】以Web應用為例
應用程式的維度,可以用吞吐量和請求延遲來評估應用程式的效能
系統資源的維度,我們可以用CPU使用率來評估系統的CPU使用情況

之所以從這兩個不同維度選擇指標,主要是因為應用程式和系統資源這兩者間相輔相成的關係
好的應用程式是效能優化的最終目的和結果,系統優化總是為應用程式服務的
所以,必須要使用應用程式的指標,來評估效能優化的整體效果
系統資源的使用情況是影響應用程式效能的根源
所以,需要用系統資源的指標,來觀察和分析瓶頸的來源



2. 測試優化前的效能指標
3. 測試優化後的效能指標
這兩個步驟,主要是為了對比優化前後的效能,更直觀地呈現效果
如果第一步,是從兩個不同維度選擇了多個指標,那麼在效能測試時,就需要獲得這些指標的具體數值
【舉例】以剛剛的Web應用為例
對應上面提到的幾個指標,可以選擇ab等工具,測試Web應用的併發請求數和響應延遲
測試的同時,還可以用vmstat、pidstat等效能工具,觀察系統和程序的CPU使用率
這樣,我們就同時獲得了應用程式和系統資源這兩個維度的指標數值

不過,在進行效能測試時,有兩個特別重要的地方需要注意下
第一,要避免效能測試工具干擾應用程式的效能,對Web應用來說,效能測試工具跟目標應用程式要在不同的機器上執行
第二,避免外部環境的變化影響效能指標的評估
這要求優化前、後的應用程式,都執行在相同配置的機器上並且它們的外部依賴也要完全一致



2.多個性能問題同時存在,要怎麼選擇?

系統性能總是牽一髮而動全身,所以效能問題通常也不是獨立存在的
那當多個性能問題同時發生的時候,應該先去優化哪一個呢?

在效能測試的領域,流傳很廣的一個說法是“二八原則”,也就是說80%的問題都是由20%的程式碼導致的
只要找出這20%的位置,就可以優化80%的效能
所以,並不是所有的效能問題都值得優化

動手優化之前先動腦,先把所有這些效能問題給分析一遍,找出最重要的、可以最大程度提升效能的問題,從它開始優化
這樣的好處是,不僅效能提升的收益最大,而且很可能其他問題都不用優化,就已經滿足了效能要求


怎麼判斷出哪個效能問題最重要?
這是效能分析要解決的核心問題,只不過這裡要分析的物件,從原來的一個問題,變成了多個問題
思路其實還是一樣的
所以,依然可以用前面講過的方法挨個分析,分別找出它們的瓶頸
分析完所有問題後,再按照因果等關係,排除掉有因果關聯的效能問題
最後,再對剩下的效能問題進行優化


如果剩下的問題還是好幾個,就得分別進行效能測試了
比較不同的優化效果後,選擇能明顯提升效能的那個問題進行修復
這個過程通常會花費較多的時間,推薦兩個可以簡化這個過程的方法
第一,如果發現是系統資源達到了瓶頸,比如CPU使用率達到了100%,那麼首先優化的一定是系統資源使用問題
完成系統資源瓶頸的優化後,才要考慮其他問題

第二,針對不同型別的指標,首先去優化那些由瓶頸導致的,效能指標變化幅度最大的問題
比如產生瓶頸後,使用者CPU使用率升高了10%,而系統CPU使用率卻升高了50%
這個時候就應該首先優化系統CPU的使用



3.有多種優化方法時,要如何選擇?

當多種方法都可用時,應該選擇哪一種呢?是不是最大提升效能的方法,一定最好呢?
一般情況下,當然想選能最大提升效能的方法,這其實也是效能優化的目標
但要注意,現實情況要考慮的因素卻沒那麼簡單
最直觀來說,效能優化並非沒有成本
效能優化通常會帶來複雜度的提升,降低程式的可維護性,還可能在優化一個指標時,引發其他指標的異常
也就是說,很可能你優化了一個指標,另一個指標的效能卻變差了


【舉例】
一個很典型的例子是將在網路部分講到的DPDK(Data Plane Development Kit)
DPDK是一種優化網路處理速度的方法,它通過繞開核心網路協議棧的方法,提升網路的處理能力
不過它有一個很典型的要求,就是要獨佔一個CPU以及一定數量的記憶體大頁
並且總是以100%的CPU使用率執行,所以,如果你的CPU核數很少,就有點得不償失了


所以,在考慮選哪個效能優化方法時,要綜合多方面的因素
切記,不要想著“一步登天”,試圖一次性解決所有問題
也不要只會“拿來主義”,把其他應用的優化方法原封不動拿來用,卻不經過任何思考和分析




CPU優化

清楚了效能優化最基本的三個問題後
接下來從應用程式和系統的角度,分別來看看如何才能降低CPU使用率,提高CPU的並行處理能力



應用程式優化

從應用程式的角度來說,降低CPU使用率的最好方法當然是,排除所有不必要的工作,只保留最核心的邏輯
比如減少迴圈的層次、減少遞迴、減少動態記憶體分配等等


1.編譯器優化

很多編譯器都會提供優化選項,適當開啟它們,在編譯階段你就可以獲得編譯器的幫助,來提升效能
比如,gcc就提供了優化選項-O2,開啟後會自動對應用程式的程式碼進行優化


2.演算法優化

使用複雜度更低的演算法,可以顯著加快處理速度
比如,在資料比較大的情況下,可以用 O(nlogn) 的排序演算法(如快排、歸併排序等)
代替 O(n^2) 的排序演算法(如冒泡、插入排序等)


3.非同步處理

使用非同步處理,可以避免程式因為等待某個資源而一直阻塞,從而提升程式的併發處理能力
比如,把輪詢替換為事件通知,就可以避免輪詢耗費CPU的問題


4.多執行緒代替多程序

相對於程序的上下文切換,執行緒的上下文切換並不切換程序地址空間,因此可以降低上下文切換的成本


5.善用快取

經常訪問的資料或者計算過程中的步驟,可以放到記憶體中快取起來,這樣在下次用時就能直接從記憶體中獲取
加快程式的處理速度



系統優化

從系統的角度來說,優化CPU的執行,一方面要充分利用CPU快取的本地性,加速快取訪問
另一方面,就是要控制程序的CPU使用情況,減少程序間的相互影響


1.CPU繫結

把程序繫結到一個或者多個CPU上,可以提高CPU快取的命中率,減少跨CPU排程帶來的上下文切換問題


2.CPU獨佔

跟CPU繫結類似,進一步將CPU分組,並通過CPU親和性機制為其分配程序
這樣,這些CPU就由指定的程序獨佔,換句話說,不允許其他程序再來使用這些CPU


3.優先順序調整

使用nice調整程序的優先順序,正值調低優先順序,負值調高優先順序
在這裡,適當降低非核心應用的優先順序,增高核心應用的優先順序,可以確保核心應用得到優先處理


4.為程序設定資源限制

使用Linux cgroups來設定程序的CPU使用上限,可以防止由於某個應用自身的問題,而耗盡系統資源


5.NUMA優化

支援NUMA的處理器會被劃分為多個node,每個node都有自己的本地記憶體空間
NUMA優化,其實就是讓CPU儘可能只訪問本地記憶體


6.中斷負載均衡

無論是軟中斷還是硬中斷,它們的中斷處理程式都可能會耗費大量的CPU
開啟irqbalance服務或者配置smp_affinity,就可以把中斷處理過程自動負載均衡到多個CPU上




千萬避免過早優化

“過早優化是萬惡之源”,過早優化不可取
一方面,優化會帶來複雜性的提升,降低可維護性
另一方面,需求不是一成不變的。針對當前情況進行的優化,很可能並不適應快速變化的新需求
這樣,在新需求出現時,這些複雜的優化,反而可能阻礙新功能的開發


所以,效能優化最好是逐步完善,動態進行,不追求一步到位,而要首先保證能滿足當前的效能要求
當發現效能不滿足要求或者出現效能瓶頸時,再根據效能評估的結果,選擇最重要的效能問題進行優化


轉載請註明出處喲~ https://www.cnblogs.com/lichengguo