火焰圖:全局視野的Linux性能剖析

文章背景

平常的工做中,會收到一堆CPU使用率太高的告警郵件,遇到某臺服務的CPU被佔滿了,這時候咱們就要去查看是什麼進程將服務器的CPU資源佔用滿了。一般咱們會經過top或者htop來快速的查看佔據CPU最高的那個進程,以下圖:php

image-20200704183558634.png

這裏是經過一個普通的服務器作演示使用,如圖所示當前服務器佔用CPU最高的是一個叫作kube-apiserver命令運行的一個進程,該進程的PID爲25633,固然你可能遇到一個服務器上運行有多個服務,想快速知道佔用率最高的那幾個進程的話,你可使用如下命令:html

ps aux|head -1;ps -aux | sort -k3nr | head -n 10 //查看前10個最佔用CPU的進程
ps aux|head -1;ps -aux | sort -k4nr | head -n 10 //查看前10個最佔用內存的進程

可是經過以上的方法獲取到服務器佔用資源的進程以後,仍是不知道CPU使用究竟耗時在哪裏,不清楚瓶頸在哪裏,此時就能夠經過Linux系統的性能分析工具perf分析,分析其返回的正在消耗CPU的函數以及調用棧。而後能夠經過解析perf採集的數據,渲染到火焰圖?,就清楚的知道究竟佔用系統CPU資源的罪魁禍首了。java

在製做火焰圖以前,須要先來講說這個Linux性能分析工具perf,該工具是一個相對簡單易上手的性能分析工具,是Performance單詞的縮寫,經過其perf的命令選項完成系統事件的採集到解析,咱們來簡單的認識一下:linux

linux上的性能分析工具Perf

安裝perf

我目前的服務器發行版是Ubuntu 16.04.6 LTS所以須要先安裝perf才能使用,該工具由linux-tools-common提供,可是它須要安裝後面的依賴。git

#安裝
root@master:~# apt install linux-tools-common linux-tools-4.4.0-142-generic linux-cloud-tools-4.4.0-142-generic -y

root@master:~# perf -v #顯示perf的版本
perf version 4.4.167

在安裝完成時候,咱們就能夠對上圖CPU使用率最高的進程ID爲25633的進程進行採樣分析。github

首選咱們採集一下該進程的調用棧信息:api

root@master:~# sudo perf record -F 99 -p 25633 -g -- sleep 30
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.039 MB perf.data (120 samples) ]

這個命令會產生一個大的數據文件,取決與你採集的進程與CPU的配置,若是一臺服務器有16個 CPU,每秒抽樣99次,持續30秒,就獲得 47,520 個調用棧,長達幾十萬甚至上百萬行。上面的命令中,perf record表示記錄,-F 99表示每秒99次,-p 25633是進程號,即對哪一個進程進行分析,-g表示記錄調用棧,sleep 30則是持續30秒,參數信息能夠視狀況調整。生成的數據採集文件在當前目錄下,名稱爲perf.data瀏覽器

perf record命令能夠從高到低排列統計每一個調用棧出現的百分比,顯示結果以下圖所示:bash

root@master:~# sudo perf report -n --stdio

image-20200704190236668.png

這樣的效果對使用者來講仍是不那麼直觀易讀,這時候,火焰?圖也就真正的派上用途了。服務器

製做火焰?圖

火焰?圖並不是必定就是火焰系列的顏色主題,只是經過?色系更能表達出含義。火焰圖常見的類型有 On-CPU, Off-CPU, 還有 Memory, Hot/Cold, [Differential](http://www.brendangregg.com/blog/2014-11-09/differential-flame-graphs.html "Differential") 等等. on-CPU/off-cpu`的區別就是一個是用於CPU是性能瓶頸,一個是IO是性能瓶頸,當你不知道當前的服務器的性能瓶頸到底是什麼的時候,你可使用這兩種類型進行對比,經過兩種火焰圖的差異是比較大的,若是兩張火焰圖長得差很少, 那麼一般認爲CPU被其它進程搶佔了.

另一種狀況就是若是沒法肯定當前的系統瓶頸, 能夠經過壓測工具來確認 : 經過壓測工具看看可否讓CPU使用率趨於飽和, 若是能那麼使用 On-CPU 火焰圖, 若是無論怎麼壓, CPU 使用率始終上不來, 那麼多半說明程序被 IO 或鎖卡住了, 此時適合使用 Off-CPU 火焰圖. 你能夠經過壓測工具進行測試,目前比較經常使用的就是abwrk,我建議嘗試使用諸如 wrk 之類更現代的壓測工具.

若是選擇 ab 的話, 那麼務必記得開啓 -k 選項, 以免耗盡系統的可用端口

Github上有Brendan D. GreggFlame Graph 工程實現了一套生成火焰圖的腳本.咱們能夠直接克隆下來直接用。

cd && git clone https://github.com/brendangregg/FlameGraph.git

生成火焰?圖,咱們通常都遵循如下流程

image-20200704192051139.png

  • 捕獲堆棧: 使用perf捕捉進程運行堆棧信息
  • 摺疊堆棧: 對抓取的系統和程序運行每一時刻的堆棧信息進行分析組合, 將重複的堆棧累計在一塊兒, 從而體現出負載和關鍵路徑,經過stackcollapse腳本完成
  • 生成火焰圖:分析 stackcollapse 輸出的堆棧信息渲染成火焰圖

Flame Graph中提供了抓取不一樣信息的腳本,能夠按需使用。下面咱們須要對捕獲到的進程堆棧信息perf.data進行摺疊,生成摺疊的堆棧信息:

root@master:~# perf script -i /root/perf.data &> /root/perf.unfold

stackcollapse-perf.pl 將 perf 解析出的內容 perf.unfold 中的符號進行摺疊

root@master:~/FlameGraph# ls
aix-perf.pl    docs                        example-perf.svg  pkgsplit-perf.pl  stackcollapse-aix.pl       stackcollapse-go.pl               stackcollapse-ljp.awk         stackcollapse-pmc.pl        stackcollapse-vsprof.pl   test.sh
demos          example-dtrace-stacks.txt   files.pl          range-perf.pl     stackcollapse-bpftrace.pl  stackcollapse-instruments.pl      stackcollapse-perf.pl         stackcollapse-recursive.pl  stackcollapse-vtune.pl
dev            example-dtrace.svg          flamegraph.pl     README.md         stackcollapse-elfutils.pl  stackcollapse-java-exceptions.pl  stackcollapse-perf-sched.awk  stackcollapse-sample.awk    stackcollapse-xdebug.php
difffolded.pl  example-perf-stacks.txt.gz  jmaps             record-test.sh    stackcollapse-gdb.pl       stackcollapse-jstack.pl           stackcollapse.pl              stackcollapse-stap.pl       test
root@master:~/FlameGraph# ./stackcollapse-perf.pl /root/perf.unfold &> /root/perf.folded
root@master:~/FlameGraph#

最後就是生成火焰?圖了

root@master:~/FlameGraph# ./flamegraph.pl /root/perf.folded > /root/perf.svg

固然也能夠經過管道符|將整個過程簡化:

cd && perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > process.svg

最後在谷歌瀏覽器上打開該火焰圖:

image-20200704193400492.png

火焰圖是基於stack信息生成的SVG 圖片, 用來展現 CPU 的調用棧。

  • y 軸表示調用棧, 每一層都是一個函數. 調用棧越深, 火焰就越高, 頂部就是正在執行的函數, 下方都是它的父函數.
  • x 軸表示抽樣數, 若是一個函數在 x 軸佔據的寬度越寬, 就表示它被抽到的次數多, 即執行的時間長. 注意, x 軸不表明時間, 而是全部的調用棧合併後, 按字母順序排列的.

火焰圖就是看頂層的哪一個函數佔據的寬度最大. 只要有"平頂"(plateaus), 就表示該函數可能存在性能問題。顏色沒有特殊含義, 由於火焰圖表示的是 CPU 的繁忙程度, 因此通常選擇暖色調.

調用棧不完整調用棧過深時,某些系統只返回前面的一部分(好比前10層);當函數名缺失,函數沒有名字,編譯器只用內存地址來表示(好比匿名函數),因此使用火焰圖也是存在分析不到的地方。你也能夠經過如下腳本進行採集分析火焰圖:

if [ $# -ne 1 ];then
    echo "Usage: $0 seconds"
    exit 1
fi
perf record -a -g -o perf.data &
PID=`ps aux| grep "perf record"| grep -v grep| awk '{print $2}'`
if [ -n "$PID" ]; then
    sleep $1
    kill -s INT $PID
fi
# wait until perf exite
sleep 1

perf script -i perf.data &> perf.unfold
perl stackcollapse-perf.pl perf.unfold &> perf.folded
perl flamegraph.pl perf.folded >perf.svg

qrcode_for_gh_0b6359cd6479_258.jpg

相關文章
相關標籤/搜索