阿里妹導讀:日常工作中,我們多少都會遇到應用的效能問題。在阿里面試中,效能優化也是常被問到的題目,用來考察是否有實際的線上問題處理經驗。面對這類問題,阿里工程師齊光給出了詳細流程。來阿里面試前,先看看這篇文章哦。
效能問題和Bug不同,後者的分析和解決思路更清晰,很多時候從應用日誌(文中的應用指分散式服務下的單個節點)即可直接找到問題根源,而效能問題,其排查思路更為複雜一些。
對應用進行效能優化,是一個系統性的工程,對工程師的技術廣度和技術深度都有所要求。一個簡單的應用,它不僅包含了應用程式碼本身,還和容器(虛擬機器)、作業系統、儲存、網路、檔案系統等緊密相關,線上應用一旦出現了效能問題,需要我們從多方面去考慮。
與此同時,除了一些低階的程式碼邏輯引發的效能問題外,很多效能問題隱藏的較深,排查起來會比較困難,需要我們對應用的各個子模組、應用所使用的框架和元件的原理有所了解,同時掌握一定的效能優化工具和經驗。
本文總結了我們在進行效能優化時常用的一些工具及技巧,目的是希望通過一個全面的視角,去感知效能優化的整體脈絡。本文主要分為下面三個部分:
第一部分會介紹效能優化的一些背景知識。第二部分會介紹效能優化的通用流程以及常見的一些誤區。第三部分會從系統層和業務層的角度,介紹高效的效能問題定位工具和高頻效能瓶頸點分佈。本文中提到的執行緒、堆、垃圾回收等名詞,如無特別說明,指的是 Java 應用中的相關概念。
1.效能優化的背景前面提到過,應用出現效能問題和應用存在缺陷是不一樣的,後者大多數是由於程式碼的品質問題導致,會導致應用功能性的缺失或出現風險,一經發現,會被及時修復。而效能問題,可能是由多方面的因素共同作用的結果:程式碼品質一般、業務發展太快、應用架構設計不合理等,這些問題處理起來一般耗時較長、分析鏈路複雜,大家都不願意幹,因此可能會被一些臨時性的補救手段所掩蓋,如:系統水位高或者單機的執行緒池佇列爆炸,那就叢集擴容增加機器;記憶體佔用高/高峰時段 OOM,那就重啟分分鐘解決......
臨時性的補救措施只是在給應用埋雷,同時也只能解決部分問題。譬如,在很多場景下,加機器也並不能解決應用的效能問題,如對時延比較敏感的一些應用必須把單機的效能優化到極致,與此同時,加機器這種方式也造成了資源的浪費,長期來看是得不償失的。對應用進行合理的效能優化,可在應用穩定性、成本核算獲得很大的收益。
上面我們闡述了進行效能優化的必要性。假設現在我們的應用已經有了效能問題(eg. CPU 水位比較高),準備開始進行優化工作了,在這個過程中,潛在的痛點會有哪些呢?下面列出一些較為常見的:
對效能優化的流程不是很清晰。初步定為一個疑似瓶頸點後,就興高采烈地吭哧吭哧開始幹,最終解決的問題其實只是一個淺層次的效能瓶頸,真實的問題的根源並未觸達;對效能瓶頸點的分析思路不是很清晰。CPU、網路、記憶體......這麼多的效能指標,我到底該關注什麼,應該從哪一塊兒開始入手?對效能優化的工具不了解。遇到問題後,不清楚該用哪個工具,不知道通過工具得到的指標代表什麼。2.效能優化的流程在效能優化這個領域,並沒有一個嚴格的流程定義,但是對於絕大多數的優化場景,我們可以將其過程抽象為下面四個步驟。
準備階段:主要工作是是通過效能測試,了解應用的概況、瓶頸的大概方向,明確優化目標;分析階段:通過各種工具或手段,初步定位效能瓶頸點;調優階段:根據定位到的瓶頸點,進行應用效能調優;測試階段:讓調優過的應用進行效能測試,與準備階段的各項指標進行對比,觀測其是否符合預期,如果瓶頸點沒有消除或者效能指標不符合預期,則重複步驟2和3。下圖即為上述四個階段的簡要流程。
2.1 通用流程詳解
在上述通用流程的四個步驟當中,步驟2和3我們會在接下來兩個部分重點進行介紹。首先我們來看一下,在準備階段和測試階段,我們需要做一些什麼。
| 2.1.1 準備階段
準備階段是非常關鍵的一步,不能省略。
首先,需要對我們進行調優的物件進行詳盡的了解,所謂知己知彼,百戰不殆。
對效能問題進行粗略評估,過濾一些因為低階的業務邏輯導致的效能問題。譬如,線上應用日誌級別不合理,可能會在大流量時導致 CPU 和磁碟的負載飆高,這種情況調整日誌級別即可;了解應用的的總體架構,比如應用的外部依賴和核心介面有哪些,使用了哪些元件和框架,哪些介面、模組的使用率較高,上下游的資料鏈路是怎麼樣的等;了解應用對應的伺服器資訊,如伺服器所在的叢集資訊、伺服器的 CPU/記憶體資訊、安裝的 Linux 版本資訊、伺服器是容器還是虛擬機器、所在宿主機混部後是否對當前應用有干擾等;其次,我們需要獲取基準資料,然後結合基準資料和當前的一些業務指標,確定此次效能優化的最終目標。
使用基準測試工具獲取系統細粒度指標。可以使用若干 Linux 基準測試工具(eg. jmeter、ab、loadrunnerwrk、wrk等),得到檔案系統、磁碟 I/O、網路等的效能報告。除此之外,類似 GC、Web 伺服器、網絡卡流量等資訊,如有必要也是需要了解記錄的;通過壓測工具或者壓測平臺(如果有的話),對應用進行壓力測試,獲取當前應用的巨集觀業務指標,譬如:響應時間、吞吐量、TPS、QPS、消費速率(對於有 MQ 的應用)等。壓力測試也可以省略,可以結合當前的實際業務和過往的監控資料,去統計當前的一些核心業務指標,如午高峰的服務 TPS。| 2.1.2 測試階段
進入到這一階段,說明我們已經初步確定了應用效能瓶頸的所在,而且已經進行初步的調優了。檢測我們調優是否有效的方式,就是在模擬的條件下,對應用進行壓力測試。注意:由於 Java 有 JIT(just-in-time compilation)過程,因此壓力測試時可能需要進行前期預熱。
如果壓力測試的結果符合了預期的調優目標,或者與基準資料相比,有很大的改善,則我們可以繼續通過工具定位下一個瓶頸點,否則,則需要暫時排除這個瓶頸點,繼續尋找下一個變數。
2.2 注意事項
在進行效能優化時,了解下面這些注意事項可以讓我們少走一些彎路。
效能瓶頸點通常呈現 2/8 分佈,即80%的效能問題通常是由20%的效能瓶頸點導致的,2/8 原則也意味著並不是所有的效能問題都值得去優化;效能優化是一個漸進、迭代的過程,需要逐步、動態地進行。記錄基準後,每次改變一個變數,引入多個變數會給我們的觀測、優化過程造成干擾;不要過度追求應用的單機效能,如果單機表現良好,則應該從系統架構的角度去思考; 不要過度追求單一維度上的極致優化,如過度追求 CPU 的效能而忽略了記憶體方面的瓶頸;選擇合適的效能優化工具,可以使得效能優化取得事半功倍的效果;整個應用的優化,應該與線上系統隔離,新的程式碼上線應該有降級方案。3.瓶頸點分析工具箱效能優化其實就是找出應用存在效能瓶頸點,然後設法通過一些調優手段去緩解。效能瓶頸點的定位是較困難的,快速、直接地定位到瓶頸點,需要具備下面兩個條件:
恰到好處的工具;一定的效能優化經驗。工欲善其事,必先利其器,我們該如何選擇合適的工具呢?不同的優化場景下,又該選擇那些工具呢?
首選,我們來看一下大名鼎鼎的「效能工具(Linux Performance Tools-full)圖」,想必很多工程師都知道,它出自系統性能專家 Brendan Gregg。該圖從 Linux 核心的各個子系統出發,列出了我們在對各個子系統進行效能分析時,可使用的工具,涵蓋了監測、分析、調優等效能優化的方方面面。除了這張全景圖之外,Brendan Gregg 還單獨提供了基準測試工具(Linux Performance Benchmark Tools)圖、效能監測工具(Linux Performance Observability Tools)圖等,更詳細的內容請參考 Brendan Gregg 的網站說明。
圖片來源:http://www.brendangregg.com/linuxperf.html?spm=ata.13261165.0.0.34646b44KX9rGc
上面這張圖非常經典,是我們做效能優化時非常好的參考資料,但事實上,我們在實際運用的時候,會發現可能它並不是最合適的,原因主要有下面兩點:
1)對分析經驗要求較高。上面這張圖其實是從 Linux 系統資源的角度去觀測效能指標的,這要求我們對 Linux 各個子系統的功能、原理要有所了解。舉例:遇到效能問題了,我們不會拿每個子系統下的工具都去試一遍,大多數情況是:我們懷疑某個子系統有問題,然後根據這張圖上列舉的工具,去觀測或者驗證我們的猜想,這無疑拔高了對效能優化經驗的要求;
2)適用性和完整性不是很好。我們在分析效能問題時,從系統底層自底向上地分析是較低效的,大多數時候,從應用層面去分析會更加有效。效能工具(Linux Performance Tools-full)圖只是從系統層一個角度給出了工具集,如果從應用層開始分析,我們可以使用哪些工具?哪些點是我們首先需要關注的?
鑑於上面若干痛點,下面給出了一張更為實用的「效能優化工具圖譜」,該圖分別從系統層、應用層(含元件層)的角度出發,列舉了我們在分析效能問題時首先需要關注的各項指標(其中?標註的是最需要關注的),這些點是最有可能出現效能瓶頸的地方。需要注意的是,一些低頻的指標或工具,在圖中並沒有列出來,如 CPU 中斷、索引節點使用、I/O事件跟蹤等,這些低頻點的排查思路較複雜,一般遇到的機會也不多,在這裡我們聚焦最常見的一些就可以了。
對比上面的效能工具(Linux Performance Tools-full)圖,下圖的優勢在於:把具體的工具同性能指標結合了起來,同時從不同的層次去描述了效能瓶頸點的分佈,實用性和可操作性更強一些。系統層的工具分為CPU、記憶體、磁碟(含檔案系統)、網路四個部分,工具集同性能工具(Linux Performance Tools-full)圖中的工具基本一致。元件層和應用層中的工具構成為:JDK 提供的一些工具 + Trace 工具 + dump 分析工具 + Profiling 工具等。
這裡就不具體介紹這些工具的具體用法了,我們可以使用 man 命令得到工具詳盡的使用說明,除此之外,還有另外一個查詢命令手冊的方法:info。info 可以理解為 man 的詳細版本,如果 man 的輸出不太好理解,可以去參考 info 文件,命令太多,記不住也沒必要記住。
上面這張圖該如何使用?
首先,雖然從系統、元件、應用兩個三個角度去描述瓶頸點的分佈,但在實際執行時,這三者往往是相輔相成、相互影響的。系統是為應用提供了執行時環境,效能問題的本質就是系統資源達到了使用的上限,反映在應用層,就是應用/元件的各項指標開始下降;而應用/元件的不合理使用和設計,也會加速系統資源的耗盡。因此,分析瓶頸點時,需要我們結合從不同角度分析出的結果,抽出共性,得到最終的結論。
其次,建議先從應用層入手,分析圖中標註的高頻指標,抓出最重要的、最可疑的、最有可能導致效能的點,得到初步的結論後,再去系統層進行驗證。這樣做的好處是:很多效能瓶頸點體現在系統層,會是多變數呈現的,譬如,應用層的垃圾回收(GC)指標出現了異常,通過 JDK 自帶的工具很容易觀測到,但是體現在系統層上,會發現系統當前的 CPU 利用率、記憶體指標都不太正常,這就給我們的分析思路帶來了困擾。
最後,如果瓶頸點在應用層和系統層均呈現出多變數分佈,建議此時使用 ZProfiler、JProfiler 等工具對應用進行 Profiling,獲取應用的綜合性能資訊(注:Profiling 指的是在應用執行時,通過事件(Event-based)、統計抽樣(Sampling Statistical)或植入附加指令(Byte-Code instrumentation)等方法,收集應用執行時的資訊,來研究應用行為的動態分析方法)。譬如,可以對 CPU 進行抽樣統計,結合各種符號表資訊,得到一段時間內應用內的程式碼熱點。
下面介紹在不同的分析層次,我們需要關注的核心效能指標,同時,也會介紹如何初步根據這些指標,判斷系統或應用是否存在效能瓶頸點,至於瓶頸點的確認、瓶頸點的成因、調優手段,將會在下一部分展開。
3.1 CPU&&執行緒
和 CPU 相關的指標主要有以下幾個。常用的工具有 top、 ps、uptime、 vmstat、 pidstat等。
CPU利用率(CPU Utilization)CPU 平均負載(Load Average)上下文切換次數(Context Switch)top - 12:20:57 up 25 days, 20:49, 2 users, load average: 0.93, 0.97, 0.79
Tasks: 51 total, 1 running, 50 sleeping, 0 stopped, 0 zombie%Cpu(s): 1.6 us, 1.8 sy, 0.0 ni, 89.1 id, 0.1 wa, 0.0 hi, 0.1 si, 7.3 stKiB Mem : 8388608 total, 476436 free, 5903224 used, 2008948 buff/cacheKiB Swap: 0 total, 0 free, 0 used. 0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
119680 admin 20 0 600908 72332 5768 S 2.3 0.9 52:32.61 obproxy65877 root 20 0 93528 4936 2328 S 1.3 0.1 449:03.61 alisentry_cli
第一行顯示的內容:當前時間、系統執行時間以及正在登入使用者數。load average 後的三個數字,依次表示過去 1 分鐘、5 分鐘、15 分鐘的平均負載(Load Average)。平均負載是指單位時間內,系統處於可執行狀態(正在使用 CPU 或者正在等待 CPU 的程序,R 狀態)和不可中斷狀態(D 狀態)的平均程序數,也就是平均活躍程序數,CPU 平均負載和 CPU 使用率並沒有直接關係。
第三行的內容表示 CPU 利用率,每一列的含義可以使用 man 檢視。CPU 使用率體現了單位時間內 CPU 使用情況的統計,以百分比的方式展示。計算方式為:CPU 利用率 = 1 - (CPU 空閒時間)/ CPU 總的時間。需要注意的是,通過效能分析工具得到的 CPU 的利用率其實是某個取樣時間內的 CPU 平均值。注:top 工具顯示的的 CPU 利用率是把所有 CPU 核的數值加起來的,即 8 核 CPU 的利用率最大可以到達800%(可以用 htop 等更新一些的工具代替 top)。
使用 vmstat 命令,可以檢視到「上下文切換次數」這個指標,如下表所示,每隔1秒輸出1組資料:
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st0 0 0 504804 0 1967508 0 0 644 33377 0 1 2 2 88 0 9
上表的 cs(context switch) 就是每秒上下文切換的次數,按照不同場景,CPU 上下文切換還可以分為中斷上下文切換、執行緒上下文切換和程序上下文切換三種,但是無論是哪一種,過多的上下文切換,都會把 CPU 時間消耗在暫存器、核心棧以及虛擬記憶體等資料的儲存和恢復上,從而縮短程序真正執行的時間,導致系統的整體效能大幅下降。vmstat 的輸出中 us、sy 分別使用者態和核心態的 CPU 利用率,這兩個值也非常具有參考意義。
vmstat 的輸只給出了系統總體的上下文切換情況,要想檢視每個程序的上下文切換詳情(如自願和非自願切換),需要使用 pidstat,該命令還可以檢視某個程序使用者態和核心態的 CPU 利用率。
CPU 相關指標異常的分析思路是什麼?
1)CPU 利用率:如果我們觀察某段時間系統或應用程序的 CPU利用率一直很高(單個 core 超過80%),那麼就值得我們警惕了。我們可以多次使用 jstack 命令 dump 應用執行緒棧檢視熱點程式碼,非 Java 應用可以直接使用 perf 進行 CPU 采采樣,離線分析取樣資料後得到 CPU 執行熱點(Java 應用需要符號表進行堆疊資訊對映,不能直接使用 perf得到結果)。
2)CPU 平均負載:平均負載高於 CPU 數量 70%,意味著系統存在瓶頸點,造成負載升高的原因有很多,在這裡就不展開了。需要注意的是,通過監控系統監測平均負載的變化趨勢,更容易定位問題,有時候大檔案的載入等,也會導致平均負載瞬時升高。如果 1 分鐘/5 分鐘/15 分鐘的三個值相差不大,那說明系統負載很平穩,則不用關注,如果這三個值逐漸降低,說明負載在漸漸升高,需要關注整體效能;
3)CPU 上下文切換:上下文切換這個指標,並沒有經驗值可推薦(幾十到幾萬都有可能),這個指標值取決於系統本身的 CPU 效能,以及當前應用工作的情況。但是,如果系統或者應用的上下文切換次數出現數量級的增長,就有很大概率說明存在效能問題,如非自願上下切換大幅度上升,說明有太多的執行緒在競爭 CPU。
上面這三個指標是密切相關的,如頻繁的 CPU 上下文切換,可能會導致平均負載升高。如何根據這三者之間的關係進行應用調優,將在下一部分介紹。
CPU 上的的一些異動,通常也可以從執行緒上觀測到,但需要注意的是,執行緒問題並不完全和 CPU 相關。與執行緒相關的指標,主要有下面幾個(均都可以通過 JDK 自帶的 jstack 工具直接或間接得到):
應用中的總的執行緒數;應用中各個執行緒狀態的分佈;執行緒鎖的使用情況,如死鎖、鎖分佈等;關於執行緒,可關注的異常有:
1)執行緒總數是否過多。過多的執行緒,體現在 CPU 上就是導致頻繁的上下文切換,同時執行緒過多也會消耗記憶體,執行緒總數大小和應用本身和機器配置相關;
2)執行緒的狀態是否異常。觀察 WAITING/BLOCKED 執行緒是否過多(執行緒數設定過多或鎖競爭劇烈),結合應用內部鎖使用的情況綜合分析;
3)結合 CPU 利用率,觀察是否存在大量消耗 CPU 的執行緒。
3.2 記憶體&&堆
和記憶體相關的指標主要有以下幾個,常用的分析工具有:top、free、vmstat、pidstat 以及 JDK 自帶的一些工具。
系統記憶體的使用情況,包括剩餘記憶體、已用記憶體、可用記憶體、快取/緩衝區;程序(含 Java 程序)的虛擬記憶體、常駐記憶體、共享記憶體;程序的缺頁異常數,包含主缺頁異常和次缺頁異常;Swap 換入和換出的記憶體大小、Swap 引數配置;JVM 堆的分配,JVM 啟動引數;JVM 堆的回收,GC 情況。使用 free 可以檢視系統記憶體的使用情況和 Swap 分割槽的使用情況,top 工具可以具體到每個程序,如我們可以用使用 top 工具檢視 Java 程序的常駐記憶體大小(RES),這兩個工具結合起來,可用覆蓋大多數記憶體指標。下面是使用 free命令的輸出:
$free -h
total used free shared buff/cache available
Mem: 125G 6.8G 54G 2.5M 64G 118G
Swap: 2.0G 305M 1.7G
上述輸出各列的具體含義在這裡不在贅述,也比較容易理解。重點介紹下 swap 和 buff/cache 這兩個指標。
Swap 的作用是把一個本地檔案或者一塊磁碟空間作為記憶體來使用,包括換出和換入兩個過程。Swap 需要讀寫磁碟,所以效能不是很高,事實上,包括 ElasticSearch 、Hadoop 在內絕大部分 Java 應用都建議關掉 Swap,這是因為記憶體的成本一直在降低,同時這也和 JVM 的垃圾回收過程有關:JVM在 GC 的時候會遍歷所有用到的堆的記憶體,如果這部分記憶體被 Swap 出去了,遍歷的時候就會有磁碟 I/O 產生。Swap 分割槽的升高一般和磁碟的使用強相關,具體分析時,需要結合快取使用情況、swappiness 閾值以及匿名頁和檔案頁的活躍情況綜合分析。
buff/cache 是快取和緩衝區的大小。快取(cache):是從磁碟讀取的檔案的或者向磁碟寫檔案時的臨時儲存資料,面向檔案。使用 cachestat 可以檢視整個系統快取的讀寫命中情況,使用 cachetop 可以觀察每個程序快取的讀寫命中情況。緩衝區(buffer)是寫入磁碟資料或從磁碟直接讀取的資料的臨時儲存,面向塊裝置。free 命令的輸出中,這兩個指標是加在一起的,使用 vmstat 命令可以區分快取和緩衝區,還可以看到 Swap 分割槽換入和換出的記憶體大小。
了解到常見的記憶體指標後,常見的記憶體問題又有哪些?總結如下:
系統剩餘記憶體/可用不足(某個程序佔用太多、系統本身記憶體不足),記憶體溢位;記憶體回收異常:記憶體洩漏(程序在一段時間內記憶體使用持續走高)、GC 頻率異常;快取使用過大(大檔案讀取或寫入)、快取命中率不高;缺頁異常過多(頻繁的 I/O 讀);Swap 分割槽使用異常(使用過大);記憶體相關指標異常後,分析思路是怎麼樣的?
使用 free/top 檢視記憶體的全域性使用情況,如系統記憶體的使用、Swap 分割槽記憶體使用、快取/緩衝區佔用情況等,初步判斷記憶體問題存在的方向:程序記憶體、快取/緩衝區、Swap 分割槽;觀察一段時間記憶體的使用趨勢。如通過 vmstat 觀察記憶體使用是否一直在增長;通過 jmap 定時統計物件記憶體分佈情況,判斷是否存在記憶體洩漏,通過 cachetop 命令,定位緩衝區升高的根源等;根據記憶體問題的型別,結合應用本身,進行詳細分析。舉例:使用 free 發現快取/緩衝區佔用不大,排除快取/緩衝區對記憶體的影響後 -> 使用 vmstat 或者 sar 觀察一下各個程序記憶體使用變化趨勢 -> 發現某個程序的記憶體時候用持續走高 -> 如果是 Java 應用,可以使用 jmap / VisualVM / heap dump 分析等工具觀察物件記憶體的分配,或者通過 jstat 觀察 GC 後的應用記憶體變化 -> 結合業務場景,定位為記憶體洩漏/GC引數配置不合理/業務程式碼異常等。
3.3 磁碟&&檔案
在分析和磁碟相關的問題時,通常是將其和檔案系統同時考慮的,下面不再區分。和磁碟/檔案系統相關的指標主要有以下幾個,常用的觀測工具為 iostat和 pidstat,前者適用於整個系統,後者可觀察具體程序的 I/O。
磁碟 I/O 利用率:是指磁碟處理 I/O 的時間百分比;磁碟吞吐量:是指每秒的 I/O 請求大小,單位為 KB;I/O 響應時間,是指 I/O 請求從發出到收到響應的間隔,包含在佇列中的等待時間和實際處理時間;IOPS(Input/Output Per Second):每秒的 I/O 請求數;I/O 等待佇列大小,指的是平均 I/O 佇列長度,佇列長度越短越好;使用 iostat 的輸出介面如下:
$iostat -dx
Linux 3.10.0-327.ali2010.alios7.x86_64 (loginhost2.alipay.em14) 10/20/2019 x86_64 (32 CPU)
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %utilsda 0.01 15.49 0.05 8.21 3.10 240.49 58.92 0.04 4.38 2.39 4.39 0.09 0.07
上圖中 %util ,即為磁碟 I/O 利用率,同 CPU 利用率一樣,這個值也可能超過 100%(存在並行 I/O);rkB/s 和 wkB/s分別表示每秒從磁碟讀取和寫入的資料量,即吞吐量,單位為 KB;磁碟 I/O處理時間的指標為 r_await 和 w_await 分別表示讀/寫請求處理完成的響應時間,svctm 表示處理 I/O 所需要的平均時間,該指標已被廢棄,無實際意義。r/s + w/s 為 IOPS 指標,分別表示每秒傳送給磁碟的讀請求數和寫請求數;aqu-sz 表示等待佇列的長度。
pidstat 的輸出大部分和 iostat 類似,區別在於它可以實時檢視每個程序的 I/O 情況。
如何判斷磁碟的指標出現了異常?
當磁碟 I/O 利用率長時間超過 80%,或者響應時間過大(對於 SSD,從 0.0x 毫秒到 1.x 毫秒不等,機械磁碟一般為5ms~10ms),通常意味著磁碟 I/O 存在效能瓶頸;如果 %util 很大,而 rkB/s 和 wkB/s 很小,一般是因為存在較多的磁碟隨機讀寫,最好把隨機讀寫優化成順序讀寫,(可以通過 strace 或者 blktrace 觀察 I/O 是否連續判斷是否是順序的讀寫行為,隨機讀寫應可關注 IOPS 指標,順序讀寫可關注吞吐量指標);如果 avgqu-sz 比較大,說明有很多 I/O 請求在佇列中等待。一般來說,如果單塊磁碟的佇列長度持續超過2,一般認為該磁碟存在 I/O 效能問題。3.4 網路
網路這個概念涵蓋的範圍較廣,在應用層、傳輸層、網路層、網路介面層都有不同的指標去衡量。這裡我們討論的「網路」,特指應用層的網路,通常使用的指標如下:
網路頻寬:表示鏈路的最大傳輸速率;網路吞吐:表示單位時間內成功傳輸的資料量大小;網路延時:表示從網路請求發出後直到收到遠端響應,所需要的時間;網路連線數和錯誤數;一般來說,應用層的網路瓶頸有如下幾類:
叢集或機器所在的機房的網路頻寬飽和,影響應用 QPS/TPS 的提升;網路吞吐出現異常,如介面存在大量的資料傳輸,造成頻寬佔用過高;網路連接出現異常或錯誤;網路出現分割槽。頻寬和網路吞吐這兩個指標,一般我們會關注整個應用的,通過監控系統可直接得到,如果一段時間內出現了明顯的指標上升,說明存在網路效能瓶頸。對於單機,可以使用 sar 得到網路介面、程序的網路吞吐。
使用 ping 或者 hping3 可以得到是否出現網路分割槽、網路具體時延。對於應用,我們更關注整個鏈路的時延,可以通過中介軟體埋點後輸出的 trace 日誌得到鏈路上各個環節的時延資訊。
使用 netstat、ss 和 sar 可以獲取網路連線數或網路錯誤數。過多網路連結造成的開銷是很大的,一是會佔用檔案描述符,二是會佔用快取,因此係統可以支撐的網路連結數是有限的。
3.5 工具總結
可以看到的是,在分析 CPU、記憶體、磁碟等的效能指標時,有幾種工具是高頻出現的,如 top、vmstat、pidstat,這裡稍微總結一下:
CPU:top、vmstat、pidstat、sar、perf、jstack、jstat;記憶體:top、free、vmstat、cachetop、cachestat、sar、jmap;磁碟:top、iostat、vmstat、pidstat、du/df;網路:netstat、sar、dstat、tcpdump;應用:profiler、dump分析。上述的很多工具,大部分是用於檢視系統層指標的,在應用層,除了有 JDK 提供的一系列工具,一些商用的產品如 gceasy.io(分析 GC 日誌)、fastthread.io(分析執行緒 dump 日誌)也是不錯的。
排查 Java 應用的線上異常或者分析應用程式碼瓶頸,可以使用阿里開源的 Arthas ,這個工具非常強大,下面簡單介紹下。
Arthas 主要面向線上應用實時診斷,解決的是類似「線上應用異常了,需要線上進行分析和定位」的問題,當然,Arthas 提供的一些方法呼叫追蹤工具,對我們排查諸如「慢查詢」等問題,也是非常有幫助的。Arthas 提供的主要功能有:
獲取執行緒統計,如執行緒持有的鎖統計、CPU 利用率統計等;類載入資訊、動態類載入、方法載入資訊;呼叫棧追蹤,呼叫耗時統計;方法呼叫引數、結果檢測;系統配置、應用配置資訊;反編譯載入類;....需要注意的是,效能工具只是解決效能問題的手段,我們了解常用工具的一般用法即可,不要在工具學習上投入過多精力。