今天談下業務系統性能問題分析診斷和性能優化方面的内容。這篇文章重點還是談已經上線的業務系統後續出現性能問題後的問題診斷和優化重點。
系統性能問題分析流程
我們首先來分析下如果一個業務系統上線前沒有性能問題,而在上線後出現了比較嚴重的性能問題,那麼實際上潛在的場景主要來自于以下幾個方面。
- 業務出現大并發的通路,導緻出現性能瓶頸
- 上線後的系統資料庫資料日積月累,資料量增加後出現性能瓶頸
- 其它關鍵環境改變,比如我們常說的網絡帶寬影響
正是由于這個原因,當我們發現性能問題的時候,首先就需要判斷是單使用者非并發狀态下本身就有性能問題,還是說在并發狀态才存在性能問題。對于單使用者性能問題往往比較容易測試和驗證,對于并發性能問題我們可以在測試環境進行加壓測試和驗證,以判斷并發下的性能。
如果是單使用者本身就存性性能問題,那麼大部分問題都出在程式代碼和SQL需要進一步優化上面。如果是并發性能問題,我們就需要進一步分析資料庫和中間件本身的狀态,看是否需要對中間件進行性能調優。
在加壓測試過程中,我們還需要對CPU,記憶體和JVM進行監控,觀察是否存在類似記憶體洩漏無法釋放等情況,即并發下性能問題本身也可能是代碼本身原因導緻性能異常。
性能問題影響因素分析
對于性能問題影響因素,簡單來說包括了硬體環境,軟體運作環境和軟體程式三個方面的主要内容。下面分别再展開說明下。
硬體環境
硬體環境就是我們常說的計算,存儲和網絡資源。
對于伺服器的計算能力,一般來說廠家都會提供TPMC參數作為一個參考資料,但是我們實際看到相同TPMC能力下的X86伺服器能力仍然低于小型機的能力。
除了伺服器的計算能力參數,另外一個重點就是我們說的儲存設備,影響到存儲的重點又是IO讀寫性能問題。有時候我們監控發現CPU和記憶體居高不下,而真正的瓶頸通過分析反而發現是由于IO瓶頸導緻,由于讀寫性能跟不上,導緻大量資料無法快速持久化并釋放記憶體資源。
比如在Linux環境下,本身也提供了性能監控工具友善進行性能分析。比如常用的iostat,ps,sar,top,vmstat等,這些工具可以對CPU,記憶體,JVM,磁盤IO等進行性能監控和分析,以發現真正的性能問題在哪裡。
比如我們常說的記憶體使用率持續告警,你就必須發現是高并發調用導緻,還是JVM記憶體洩漏導緻,還是本身由于磁盤IO瓶頸導緻。
對于CPU,記憶體,磁盤IO性能監控和分析的一個思路可以參考:
運作環境-資料庫和應用中間件
資料庫和應用中間件性能調優是另外一個經常出現性能問題的地方。
資料庫性能調優
拿Oracle資料庫來說,影響資料庫性能的因素包括:系統、資料庫、網絡。資料庫的優化包括:優化資料庫磁盤I/O、優化復原段、優化Rrdo日志、優化系統全局區、優化資料庫對象。
要調整首先就需要對資料庫性能進行監控
我們可以在init.ora參數檔案中設定TIMED_STATISTICS=TRUE 和在你的會話層設定ALTER SESSION SET STATISTICS=TRUE 。運作svrmgrl 用 connect internal 注冊,在你的應用系統正常活動期間,運作utlbstat.sql 開始統計系統活動,達到一定的時間後,執行utlestat.sql 停止統計。統計結果将産生在report.txt 檔案中。
資料庫性能優化應該是一個持續性的工作,一個方面是本身的性能和參數巡檢,另外一個方面就是DBA也會經常提取最占用記憶體的低效SQL語句給開發人員進一步分析,同時也會從資料庫本身的以下告警KPI名額中發現問題。
比如我們可能會發現Oracle資料庫出現記憶體使用率高的告警,而通過檢查會發現是産生了大量的Redo日志導緻,那麼我們就需要從程式上進一步分析為何會産生如此多的復原。
應用中間件性能分析和調優
應用中間件容器即我們常說的Weblogic, Tomcat等應用中間件容器或Web容器。應用中間件調優一個方面是本身的配置參數優化設定,一個方面就是JVM記憶體啟動參數調優。
對于應用中間件本身的參數設定,主要包括了JVM啟動參數設定,線程池設定,連接配接數的最小最大值設定等。如果是叢集環境,還涉及到叢集相關的配置調優。
對于JVM啟動參數調優,往往也是應用中間件調優的一個關鍵點,但是一般JVM參數調優會結合應用程式一起進行分析。
比如我們常見的JVM堆記憶體溢出,如果程式代碼沒有記憶體洩漏問題的話,我就需要考慮調整JVM啟動時候堆記憶體設定。在32位作業系統下隻能夠設定到4G,但是在64位作業系統下已經可以設定到8G甚至更大的值。
其中JVM啟動的主要控制參數說明如下:
- -Xmx設定最大堆空間
- -Xms設定最小堆空間
- -XX:MaxNewSize設定最大新生代空間
- -XX:NewSize設定最小新生代空間
- -XX:MaxPermSize設定最大永久代空間(注:新記憶體模型已經替換為Metaspace)
- -XX:PermSize設定最小永久代空間(注:新記憶體模型已經替換為Metaspace)
- -Xss設定每個線程的堆棧大小
那麼這些值究竟設定多大合适,具體來講:
Java整個堆大小設定,Xmx 和 Xms設定為老年代存活對象的3-4倍,即FullGC之後的老年代記憶體占用的3-4倍。永久代 PermSize和MaxPermSize設定為老年代存活對象的1.2-1.5倍。
年輕代Xmn的設定為老年代存活對象的1-1.5倍。
老年代的記憶體大小設定為老年代存活對象的2-3倍。
注意在新的JVM記憶體模型下已經沒有PermSize而是變化為Metaspace,是以需要考慮Heap記憶體和Metaspace大小的配比,同時還需要考慮相關的垃圾回收機制是采用哪種類型等。
對于JVM記憶體溢出問題,我前面寫過一篇專門的分析文章可以參考。
從表象到根源-一個軟體系統JVM記憶體溢出問題分析解決全過程
軟體程式性能問題分析
在這裡首先要強調的一點就是,當我們發現性能問題後首先想到的就是擴充資源,但是大部分的性能問題本身并不是資源能力不夠導緻,而是我們程式實作上出現明顯缺陷。
比如我們經常看到的大量循環建立連接配接,資源使用了不釋放,SQL語句低效執行等。
為了解決這些性能問題,最好的方法仍然是在事前控制。其中包括了事前的代碼靜态檢查工具的使用,也包括了開發團隊對代碼進行的Code Review來發現性能問題。
所有已知的問題都必須形成開發團隊的開發規範要求,避免重複再犯。
業務系統性能問題擴充思考
對于業務系統的性能優化,除了上面談到的标準分析流程和分析要素外,再談下其它一些性能問題引發的關鍵思考。
上線前的性能測試是否有用?
有時候大家可能覺得奇怪,為何我們系統上線前都做了性能測試,為何上線後還是會出現系統性能問題。那麼我們可以考慮下實際上我們上線前性能測試可能存在的一些無法真實模拟生産環境的地方,具體為:
- 硬體能否完全模拟真實環境?最好的性能測試往往是直接在搭建完成的生産環境進行。
- 資料量能否模拟實際場景?真實場景往往是多個業務表都已經存在大資料量的積累而非空表。
- 并發能否模拟真實場景?一個是需要錄制複合業務場景,一個是需要多台壓測機。
而實際上我們在做性能測試的時候以上幾個點都很難真正做到,是以要想完全模拟出生産真實環境是相當困難的,這也導緻了很多性能問題是在真正上線後才發現。
系統本身水準彈性擴充是否完全解決性能問題?
第二個點也是我們經常談的比較多的點,就是我們的業務系統在進行架構設計的時候,特别是面對非功能性需求,我們都會談到系統本身的資料庫,中間件都采用了叢集技術,能夠做到彈性水準擴充。那麼這種彈性水準擴充能力是否又真正解決了性能問題?
實際上我們看到對于資料庫往往很難真正做到無限的彈性水準擴充,即使對于Oracle RAC叢集往往也是最多擴充到單點的2到3倍性能。對于應用叢集往往可以做到彈性水準擴充,目前技術也比較成熟。
當中間件能夠做到完全彈性擴充的時候,實際上仍然可能存在性能問題,即随着我們系統的運作和業務資料量的不斷積累增值。實際上你可以看到往往非并發狀态下的單使用者通路本身就很慢,而不是說并發上來後滿。是以也是我們常說的要給點,即:
- 單點通路性能正常的時候可以擴充叢集來應對大并發狀态下的同時通路
- 單點通路本身性能就有問題的時候,要優先優化單節點通路性能
業務系統性能診斷的分類
對于業務系統性能診斷,如果從靜态角度我們可以考慮從以下三個方面進行分類
- 作業系統和存儲層面
- 中間件層面(包括了資料庫,應用伺服器中間件)
- 軟體層面(包括了資料庫SQL和存儲過程,邏輯層,前端展現層等)
那麼一個業務系統應用功能出現問題了,我們當然也可以從動态層面來看實際一個應用請求從調用開始究竟經過了哪些代碼和硬體基礎設施,通過分段方法來定位和查詢問題。
比如我們常見的就是一個查詢功能如果出現問題了,首先就是找到這個查詢功能對應的SQL語句在背景查詢是否很慢,如果這個SQL本身就慢,那麼就要優化優化SQL語句。如果SQL本身快但是查詢慢,那就要看下是否是前端性能問題或者叢集問題等。
軟體代碼的問題往往是最不能忽視的一個性能問題點
對于業務系統性能問題,我們經常想到的就是要擴充資料庫的硬體性能,比如擴充CPU和記憶體,擴充叢集,但是實際上可以看到很多應用的性能問題并不是硬體性能導緻的,而是由于軟體代碼性能引起的。對于軟體代碼常見的性能問題我在以往的部落格文章裡面也談過到,比較典型的包括了。
- 循環中初始化大的結構對象,資料庫連接配接等
- 資源不釋放導緻的記憶體洩露等
- 沒有基于場景需求來适度通過緩存等方式提升性能
- 長周期事務處理耗費資源
- 處理某一個業務場景或問題的時候,沒有選擇最優的資料結構或算法
以上都是常見的一些軟體代碼性能問題點,而這些往往需要通過我們進行Code Review或代碼評審的方式才能夠發現出來。是以如果要做全面的性能優化,對于軟體代碼的性能問題排查是必須的。
通過IT資源監控或APM應用工具來發現性能問題
圖檔來源 OneAPM
對于性能問題的發現一般有兩條路徑,一個就是通過我們IT資源的監控,APM的性能監控和預警來提前發現性能問題,一個是通過業務使用者在使用過程中的回報來發現性能問題。
APM應用性能管理主要指對企業的關鍵業務應用進行監測、優化,提高企業應用的可靠性和品質,保證使用者得到良好的服務,降低IT總擁有成本(TCO)。
資源池-》應用層-》業務層
這個可以了解為APM的一個關鍵點,原有的網管類監控軟體更多的是資源和作業系統層面,包括計算和存儲資源的使用和使用率情況,網絡本身的性能情況等。但是當要分析所有的資源層問題如何對應到具體的應用,對應到具體的業務功能的時候很難。
傳統模式下,當出現CPU或記憶體滿負荷的時候,如果要查找到具體是哪個應用,哪個程序或者具體哪個業務功能,哪個sql語句導緻的往往并不是容易的事情。在實際的性能問題優化中往往也需要做大量的日志分析和問題定位,最終才可能找到問題點。
比如在我們最近的項目實施中,結合APM和服務鍊監控,我們可以快速的發現究竟是哪個服務調用出現了性能問題,或者快速的定位出哪個SQL語句有驗證的性能問題。這個都可以幫助我們快速的進行性能問題分析和診斷。
資源上承載的是應用,應用本身又包括了資料庫和應用中間件容器,同時也包括了前端;在應用之上則是對應到具體的業務功能。是以APM一個核心就是要将資源-》應用-》功能之間進行整合分析和銜接。
而随着DevOps和自動化運維的思路推進,我們更加希望是通過APM等工具主動監控來發現性能問題,對于APM工具最大的好處就是可以進行服務全鍊路的性能分析,友善我們發現性能問題究竟發生在哪裡。比如我們送出一個表單很慢,通過APM分析我們很容易發現究竟是調用哪個業務服務慢,或者是處理哪個SQL語句慢。這樣可以極大的提升我們性能問題分析診斷的效率。
性能分析的一般步驟
一、CPU 性能分析
關于 CPU 的性能分析方法,CPU性能分析優化套路 文中,已經整理了一個迅速分析 CPU 性能瓶頸的思路:
利用 top、vmstat、pidstat、strace 以及 perf 等幾個最常見的工具,擷取 CPU 性能名額後,再結合程序與 CPU 的工作原理,就可以迅速定位出 CPU 性能瓶頸的來源。
top、pidstat、vmstat 這類工具所彙報的 CPU 性能名額,都源自 /proc 檔案系統(比如 /proc/loadavg、/proc/stat、/proc/softirqs 等)。這些名額,都應該通過監控系統監控起來。雖然并非所有名額都需要報警,但這些名額卻可以加快性能問題的定位分析。
比如說,當收到系統的使用者 CPU 使用率過高告警時,
從監控系統中直接查詢到,導緻 CPU 使用率過高的程序;
然後再登入到程序所在的 Linux 伺服器中,分析該程序的行為。
可以使用 strace,檢視程序的系統調用彙總;
也可以使用 perf 等工具,找出程序的熱點函數;
甚至還可以使用動态追蹤的方法,來觀察程序的目前執行過程,直到确定瓶頸的根源。
二、記憶體性能分析
關于記憶體性能的分析方法,在 總結篇:系統記憶體問題如何快速定位 中也已經詳細介紹。
如上圖,就是一個迅速定位記憶體瓶頸的流程。可以通過 free 和 vmstat 輸出的性能名額,确認記憶體瓶頸;然後,再根據記憶體問題的類型,進一步分析記憶體的使用、配置設定、洩漏以及緩存等,最後找出問題的來源。
比如說,當你收到記憶體不足的告警時,
首先可以從監控系統中。找出占用記憶體最多的幾個程序。
然後,再根據這些程序的記憶體占用曆史,觀察是否存在記憶體洩漏問題。确定出最可疑的程序後,
再登入到程序所在的 Linux 伺服器中,分析該程序的記憶體空間或者記憶體配置設定,
最後弄清楚程序為什麼會占用大量記憶體。
三、磁盤和檔案系統 I/O 性能分析
關于磁盤和檔案系統的 I/O 性能分析方法,在總結篇:Linux I/O問題如何快速定位中也已經為你整理了一個快速分析的思路。
如下面這張圖。使用 iostat ,發現磁盤 I/O 存在性能瓶頸(比如 I/O 使用率過高、響應時間過長或者等待隊列長度突然增大等)後,可以再通過 pidstat、 vmstat 等,确認 I/O 的來源。接着,再根據來源的不同,進一步分析檔案系統和磁盤的使用率、緩存以及程序的 I/O 等,進而揪出 I/O 問題的真兇。
同 CPU 和記憶體性能類似,很多磁盤和檔案系統的性能名額,也來源于 /proc 和 /sys 檔案系統(比如 /proc/diskstats、/sys/block/sda/stat 等)。自然,它們也應該通過監控系統監控起來。這樣,當你收到 I/O 性能告警時,就可以從監控系統中,直接得到上圖中的各項性能名額,進而加快性能定位的過程。
比如說,當你發現某塊磁盤的 I/O 使用率為 100% 時,
首先可以從監控系統中,找出 I/O 最多的程序。
然後,再登入到程序所在的 Linux 伺服器中,借助 strace、lsof、perf 等工具,分析該程序的 I/O 行為。
最後,再結合應用程式的原理,找出大量 I/O 的原因。
四、網絡性能分析
網絡性能,其實包含兩類資源,即網絡接口和核心資源。在總結篇:系統的網絡性能評估及優化思路中提到過,網絡性能的分析,要從 Linux 網絡協定棧的原理來切入。
下面這張圖,就是 Linux 網絡協定棧的基本原理,包括應用層、套機字接口、傳輸層、網絡層以及鍊路層等。
要分析網絡的性能,自然也是要從這幾個協定層入手,通過使用率、飽和度以及錯誤數這幾類性能名額,觀察是否存在性能問題。比如 :
在鍊路層,可以從網絡接口的吞吐量、丢包、錯誤以及軟中斷和網絡功能解除安裝等角度分析;
在網絡層,可以從路由、分片、疊加網絡等角度進行分析;
在傳輸層,可以從 TCP、UDP 的協定原理出發,從連接配接數、吞吐量、延遲、重傳等角度進行分析;
在應用層,可以從應用層協定(如 HTTP 和 DNS)、請求數(QPS)、套接字緩存等角度進行分析。
網絡的性能名額也都來源于核心,包括 /proc 檔案系統(如 /proc/net)、網絡接口以及 conntrack 等核心子產品。這些名額同樣需要被監控系統監控。這樣,當你收到網絡告警時,就可以從監控系統中,查詢這些協定層的各項性能名額,進而更快定位出性能問題。
比如,當你收到網絡不通的告警時,
可以從監控系統中,查找各個協定層的丢包名額,确認丢包所在的協定層。
然後,從監控系統的資料中,确認網絡帶寬、緩沖區、連接配接跟蹤數等軟硬體,是否存在性能瓶頸。
最後,再登入到發生問題的 Linux 伺服器中,借助 netstat、tcpdump、bcc 等工具,分析網絡的收發資料,并且結合核心中的網絡選項以及 TCP 等網絡協定的原理,找出問題的來源。
五、應用程式瓶頸
除了以上這些來自網絡資源的瓶頸外,還有很多瓶頸,其實直接來自應用程式。比如,最典型的應用程式性能問題,就是吞吐量(并發請求數)下降、錯誤率升高以及響應時間增大。
不過,這些應用程式性能問題雖然各種各樣,但就其本質來源,實際上隻有三種,也就是資源瓶頸、依賴服務瓶頸以及應用自身的瓶頸。
第一種資源瓶頸,其實還是指剛才提到的 CPU、記憶體、磁盤和檔案系統 I/O、網絡以及核心資源等各類軟硬體資源出現了瓶頸,進而導緻應用程式的運作受限。對于這種情況,我們就可以用前面系統資源瓶頸子產品提到的各種方法來分析。
第二種依賴服務的瓶頸,也就是諸如資料庫、分布式緩存、中間件等應用程式,直接或者間接調用的服務出現了性能問題,進而導緻應用程式的響應變慢,或者錯誤率升高。這說白了就是跨應用的性能問題,使用全鍊路跟蹤系統,就可以幫你快速定位這類問題的根源。
最後一種,應用程式自身的性能問題,包括了多線程處理不當、死鎖、業務算法的複雜度過高等等。對于這類問題,在應用程式名額監控以及日志監控中,觀察關鍵環節的耗時和内部執行過程中的錯誤,就可以縮小問題的範圍。
不過,由于這是應用程式内部的狀态,外部通常不能直接擷取詳細的性能資料,是以就需要應用程式在設計和開發時,就提供出這些名額,以便監控系統可以了解應用程式的内部運作狀态。
如果這些手段過後還是無法找出瓶頸,還可以用系統資源子產品提到的各類程序分析工具,來進行分析定位。比如:
可以用 strace,觀察系統調用;
使用 perf 和火焰圖,分析熱點函數;
甚至使用動态追蹤技術,來分析程序的執行狀态。
當然,系統資源和應用程式本來就是互相影響、相輔相成的一個整體。實際上,很多資源瓶頸,也是應用程式自身運作導緻的。比如,程序的記憶體洩漏,會導緻系統記憶體不足;程序過多的 I/O 請求,會拖慢整個系統的 I/O 請求等。是以,很多情況下,資源瓶頸和應用自身瓶頸,其實都是同一個問題導緻的,并不需要重複分析。
系統是應用的運作環境,系統的瓶頸會導緻應用的性能下降;而應用的不合理設計,也會引發系統資源的瓶頸。
性能優化的一般方法
一、CPU 優化
CPU 性能優化的核心,在于排除所有不必要的工作、充分利用 CPU 緩存并減少程序排程對性能的影響。在CPU性能分析優化套路也介紹了CPU優化方法
最典型的三種優化方法:
第一種,把程序綁定到一個或者多個 CPU 上,充分利用 CPU 緩存的本地性,并減少程序間的互相影響。
第二種,為中斷處理程式開啟多 CPU 負載均衡,以便在發生大量中斷時,可以充分利用多 CPU 的優勢分攤負載。
第三種,使用 Cgroups 等方法,為程序設定資源限制,避免個别程序消耗過多的 CPU。同時,為核心應用程式設定更高的優先級,減少低優先級任務的影響。
二、記憶體優化
記憶體性能的優化,也就是要解決記憶體不足、記憶體洩漏、Swap 過多、缺頁異常過多以及緩存過多等的問題。可以通過以下幾種方法,來優化記憶體的性能。
詳情可以參考總結篇:系統記憶體問題如何快速定位
第一種,除非有必要,Swap 應該禁止掉。這樣就可以避免 Swap 的額外 I/O ,帶來記憶體通路變慢的問題。
第二種,使用 Cgroups 等方法,為程序設定記憶體限制。這樣就可以避免個别程序消耗過多記憶體,而影響了其他程序。對于核心應用,還應該降低 oom_score,避免被 OOM 殺死。
第三種,使用大頁、記憶體池等方法,減少記憶體的動态配置設定,進而減少缺頁異常。
三、磁盤和檔案系統 I/O 優化
磁盤和檔案系統 I/O 的優化方法。在總結篇:Linux I/O問題如何快速定位 中,梳理了一些常見的優化思路,這其中有如下典型的方法。
第一種,也是最簡單的方法,通過 SSD 替代 HDD、或者使用 RAID 等方法,提升 I/O 性能。
第二種,針對磁盤和應用程式 I/O 模式的特征,選擇最适合的 I/O 排程算法。比如,SSD 和虛拟機中的磁盤,通常用的是 noop 排程算法;而資料庫應用,更推薦使用 deadline 算法。
第三,優化檔案系統和磁盤的緩存、緩沖區,比如優化髒頁的重新整理頻率、髒頁限額,以及核心回收目錄項緩存和索引節點緩存的傾向等。
第四,使用不同磁盤隔離不同應用的資料、優化檔案系統的配置選項、優化磁盤預讀、增大磁盤隊列長度等
四、網絡優化
在總結篇:系統的網絡性能評估及優化思路中,我也已經梳理了一些常見的優化思路。這些優化方法都是從 Linux 的網絡協定棧出發,針對每個協定層的工作原理進行優化。最典型的幾種網絡優化方法。
1、首先,從核心資源和網絡協定的角度來說,我們可以對核心選項進行優化,比如:
可以增大套接字緩沖區、連接配接跟蹤表、最大半連接配接數、最大檔案描述符數、本地端口範圍等核心資源配額;
也可以減少 TIMEOUT 逾時時間、SYN+ACK 重傳數、Keepalive 探測時間等異常處理參數;
還可以開啟端口複用、反向位址校驗,并調整 MTU 大小等降低核心的負擔。
這些都是核心選項優化的最常見措施。
2、其次,從網絡接口的角度來說,我們可以考慮對網絡接口的功能進行優化,比如:
可以将原來 CPU 上執行的工作,解除安裝到網卡中執行,即開啟網卡的 GRO、GSO、RSS、VXLAN 等解除安裝功能;
也可以開啟網絡接口的多隊列功能,這樣,每個隊列就可以用不同的中斷号,排程到不同 CPU 上執行;
還可以增大網絡接口的緩沖區大小以及隊列長度等,提升網絡傳輸的吞吐量。
3、最後,在極限性能情況(比如 C10M)下,核心的網絡協定棧可能是最主要的性能瓶頸,是以,一般會考慮繞過核心協定棧。
可以使用 DPDK 技術,跳過核心協定棧,直接由使用者态程序用輪詢的方式,來處理網絡請求。同時,再結合大頁、CPU 綁定、記憶體對齊、流水線并發等多種機制,優化網絡包的處理效率。
可以使用核心自帶的 XDP 技術,在網絡包進入核心協定棧前,就對其進行處理。這樣,也可以達到目的,獲得很好的性能。
五、應用程式優化
雖然系統的軟硬體資源,是保證應用程式正常運作的基礎,但你要知道,性能優化的最佳位置,還是應用程式内部。為什麼這麼說呢?如下舉例:
第一個例子,是系統 CPU 使用率(sys%)過高的問題。有時候出現問題,雖然表面現象是系統 CPU 使用率過高,但分析過後,很可能會發現,應用程式的不合理系統調用才是罪魁禍首。這種情況下,優化應用程式内部系統調用的邏輯,顯然要比優化核心要簡單也有用得多。
第二個例子,資料庫的 CPU 使用率高、I/O 響應慢的性能問題。一般來說,并不是因為資料庫本身性能不好,而是應用程式不合理的表結構或者 SQL 查詢語句導緻的。這時候,優化應用程式中資料庫表結構的邏輯或者 SQL 語句,顯然要比優化資料庫本身,能帶來更大的收益。
是以,在觀察性能名額時,應該先檢視應用程式的響應時間、吞吐量以及錯誤率等名額,因為它們才是性能優化要解決的終極問題。以終為始,從這些角度出發,你一定能想到很多優化方法,下面幾種方法。
第一,從 CPU 使用的角度來說,簡化代碼、優化算法、異步處理以及編譯器優化等,都是常用的降低 CPU 使用率的方法,這樣可以利用有限的 CPU 處理更多的請求。
第二,從資料通路的角度來說,使用緩存、寫時複制、增加 I/O 尺寸等,都是常用的減少磁盤 I/O 的方法,這樣可以獲得更快的資料處理速度。
第三,從記憶體管理的角度來說,使用大頁、記憶體池等方法,可以預先配置設定記憶體,減少記憶體的動态配置設定,進而更好地記憶體通路性能。
第四,從網絡的角度來說,使用 I/O 多路複用、長連接配接代替短連接配接、DNS 緩存等方法,可以優化網絡 I/O 并減少網絡請求數,進而減少網絡延時帶來的性能問題。
第五,從程序的工作模型來說,異步處理、多線程或多程序等,可以充分利用每一個 CPU 的處理能力,進而提高應用程式的吞吐能力。
除上述方法,也可以使用消息隊列、CDN、負載均衡等各種方法,來優化應用程式的架構,将原來單機要承擔的任務,排程到多台伺服器中并行處理。這樣也往往能獲得更好的整體性能。
雖然性能優化的方法很多,不過,一定要避免過早優化。性能優化往往會提高複雜性,這一方面降低了可維護性,另一方面也為适應複雜多變的新需求帶來障礙。是以,性能優化最好是逐漸完善,動态進行;不追求一步到位,而要首先保證,能滿足目前的性能要求。發現性能不滿足要求或者出現性能瓶頸後,再根據性能分析的結果,選擇最重要的性能問題進行優化。
性能工具
一、工具選擇的原則
隻有當想了解某個性能名額,卻不知道該怎麼辦的時候,才會想到,“要是有一個性能工具速查表就好了”這個問題。如果已知一個性能工具可用,我們更多會去檢視這個工具的手冊,找出它的功能、用法以及注意事項。
關于工具手冊的檢視,man 應該是我們最熟悉的方法,除了 man 之外,還有另外一個查詢指令手冊的方法info。info 可以了解為 man 的詳細版本,提供了諸如節點跳轉等更強大的功能。相對來說,man 的輸出比較簡潔,而 info 的輸出更詳細。是以,通常使用 man 來查詢工具的使用方法,隻有在 man 的輸出不太好了解時,才會再去參考 info 文檔。
要查詢手冊,前提一定是已知哪個工具可用。如果你還不知道要用哪個工具,就要根據想了解的名額,去查找有哪些工具可用。這其中:
有些工具不需要額外安裝,就可以直接使用,比如核心的 /proc 檔案系統;
而有些工具,則需要安裝額外的軟體包,比如 sar、pidstat、iostat 等。
是以,在選擇性能工具時,除了要考慮性能名額這個目的外,還要結合待分析的環境來綜合考慮。比如,實際環境是否允許安裝軟體包,是否需要新的核心版本等。
明白了工具選擇的基本原則後,我們來看 Linux 的性能工具。如下面這張圖,也就是 Brendan Gregg 整理的性能工具譜圖。從 Linux 核心的各個子系統出發,彙總了對各個子系統進行性能分析時可以選擇的工具。但還不夠具體,比如,當你需要檢視某個性能名額時,這張圖裡對應的子系統部分,可能有多個性能工具可供選擇。但實際上,并非所有這些工具都适用,具體要用哪個,還需要你去查找每個工具的手冊,對比分析做出選擇。
如下,就從 CPU、記憶體、磁盤 I/O 以及網絡等幾個角度,梳理這些常見的 Linux 性能工具,特别是從性能名額的角度出發,理清楚到底有哪些工具,可以用來監測特定的性能名額。
CPU 性能工具
從 CPU 的角度來說,主要的性能名額就是 CPU 的使用率、上下文切換以及 CPU Cache 的命中率等。下面這張圖就列出了常見的 CPU 性能名額。
從這些名額出發,再把 CPU 使用率,劃分為系統和程序兩個次元,我們就可以得到,下面這個 CPU 性能工具速查表。
網絡性能工具
從網絡的角度來說,主要性能名額就是吞吐量、響應時間、連接配接數、丢包數等。根據 TCP/IP 網絡協定棧的原理,可以把這些性能名額,進一步細化為每層協定的具體名額。如下圖分别從鍊路層、網絡層、傳輸層和應用層,列出了各層的主要名額。從這些名額出發,我們就可以得到下面的網絡性能工具速查表。