1. 程式人生 > >14.效能優化答疑二

14.效能優化答疑二

一、使用perf 工具,看到的是十六進位制地址而不是函式名。

檢視perf最後歐,就會看到警告資訊:

Failed to open /opt/bitnami/php/lib/php/extensions/opcache.so, continuing without symbols

這說明,perf 找不到待分析程序依賴的庫。當然,實際上這個案例中有很多依賴庫都找不到,只不過,perf 工具本身只在最後一行顯示警告資訊,所以你只能看到這一條警告。

這個問題,其實也是在分析 Docker 容器應用時,我們經常碰到的一個問題,因為容器應用依賴的庫都在映象裡面。

針對這種情況,我總結了下面四個解決方法。

第一個方法,在容器外面構建相同路徑的依賴庫。這種方法從原理上可行,但是我並不推薦,一方面是因為找出這些依賴庫比較麻煩,更重要的是,構建這些路徑,會汙染容器主機的環境。

第二個方法,在容器內部執行 perf。不過,這需要容器執行在特權模式下,但實際的應用程式往往只以普通容器的方式執行。所以,容器內部一般沒有許可權執行 perf 分析。

比方說,如果你在普通容器內部執行 perf record ,你將會看到下面這個錯誤提示:

$ perf_4.9 record -a -g
perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error 
1 (Operation not permitted) perf_event_open(..., 0) failed unexpectedly with error 1 (Operation not permitted)

當然,其實你還可以通過配置 /proc/sys/kernel/perf_event_paranoid (比如改成 -1),來允許非特權使用者執行 perf 事件分析。

不過還是那句話,為了安全起見,這種方法我也不推薦。

第三個方法,指定符號路徑為容器檔案系統的路徑。比如對於第 05 講的應用,你可以執行下面這個命令:

$ mkdir /tmp/foo
$ PID=$(docker inspect --format {{.State.Pid}} phpfpm)
$ bindfs 
/proc/$PID/root /tmp/foo $ perf report --symfs /tmp/foo

# 使用完成後不要忘記解除繫結
$ umount /tmp/foo/

不過這裡要注意,bindfs 這個工具需要你額外安裝。bindfs 的基本功能是實現目錄繫結(類似於 mount --bind),這裡需要你安裝的是 1.13.10 版本(這也是它的最新發布版)。

如果你安裝的是舊版本,你可以到 GitHub上面下載原始碼,然後編譯安裝。

第四個方法,在容器外面把分析紀錄儲存下來,再去容器裡檢視結果。這樣,庫和符號的路徑也就都對了。

比如,你可以這麼做。先執行 perf record -g -p < pid>,執行一會兒(比如 15 秒)後,按 Ctrl+C 停止。

然後,把生成的 perf.data 檔案,拷貝到容器裡面來分析:

$ docker cp perf.data phpfpm:/tmp 
$ docker exec -i -t phpfpm bash

接下來,在容器的 bash 中繼續執行下面的命令,安裝 perf 並使用 perf report 檢視報告:

$ cd /tmp/ 
$ apt-get update && apt-get install -y linux-tools linux-perf procps
$ perf_4.9 report

不過,這裡也有兩點需要你注意。

首先是 perf 工具的版本問題。在最後一步中,我們執行的工具是容器內部安裝的版本 perf_4.9,而不是普通的 perf 命令。這是因為, perf 命令實際上是一個軟連線,會跟核心的版本進行匹配,但映象裡安裝的 perf 版本跟虛擬機器的核心版本有可能並不一致。

另外,php-fpm 映象是基於 Debian 系統的,所以安裝 perf 工具的命令,跟 Ubuntu 也並不完全一樣。比如, Ubuntu 上的安裝方法是下面這樣:

$ apt-get install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r))

而在 php-fpm 容器裡,你應該執行下面的命令來安裝 perf:

$ apt-get install -y linux-perf

當你按照前面這幾種方法操作後,你就可以在容器內部看到 sqrt 的堆疊:

 

 二、使用perf工具分析Java

 

兩個問題,其實是上一個 perf 問題的延伸。 像是 Java 這種通過 JVM 來執行的應用程式,執行堆疊用的都是 JVM 內建的函式和堆疊管理。所以,從系統層面你只能看到 JVM 的函式堆疊,而不能直接得到 Java 應用程式的堆疊。

perf_events 實際上已經支援了 JIT,但還需要一個 /tmp/perf-PID.map 檔案,來進行符號翻譯。當然,開源專案 perf-map-agent 可以幫你生成這個符號表。

此外,為了生成全部呼叫棧,你還需要開啟 JDK 的選項 -XX:+PreserveFramePointer。因為這裡涉及到大量的 Java 知識,我就不再詳細展開了。如果你的應用剛好基於 Java ,那麼你可以參考 NETFLIX 的技術部落格 Java in Flames (連結為 https://medium.com/netflix-techblog/java-in-flames-e763b3d32166),來檢視詳細的使用步驟。

說到這裡,我也想強調一個問題,那就是學習效能優化時,不要一開始就把自己限定在具體的某個程式語言或者效能工具中,糾結於語言或工具的細節出不來。

掌握整體的分析思路,才是我們首先要做的。因為,效能優化的原理和思路,在任何程式語言中都是相通的。

三、為什麼 perf 的報告中,很多符號都不顯示呼叫棧

perf record -g 命令手機資訊,收集多次,每次都是command列為swapper的左側有加號,而app或其他的沒有加號,在symbol列看到sys_read,new_sync_read,blkdev_read_iter等資訊。(Ubunt系統)。

perf report是視覺化展示perf.data工具,在執行時,看到以下介面:

清楚看到只有swapper呼叫棧,其他所有符號都不能看到堆疊。發現效能工具無法理解時檢視手冊,man perf-report,找到 -g 說明:

通過這個說明可以看到,-g 選項等同於 --call-graph,它的引數是後面那些被逗號隔開的選項,意思分別是輸出型別、最小閾值、輸出限制、排序方法、排序關鍵詞、分支以及值的型別。

我們可以看到,這裡預設的引數是 graph,0.5,caller,function,percent,具體含義文件中都有詳細講解,這裡我就不再重複了。

現在再回過頭來看我們的問題,堆疊顯示不全,相關的引數當然就是最小閾值 threshold。通過手冊中對 threshold 的說明,我們知道,當一個事件發生比例高於這個閾值時,它的呼叫棧才會顯示出來。

threshold 的預設值為 0.5%,也就是說,事件比例超過 0.5% 時,呼叫棧才能被顯示。再觀察我們案例應用 app 的事件比例,只有 0.34%,低於 0.5%,所以看不到 app 的呼叫棧就很正常了。

這種情況下,你只需要給 perf report 設定一個小於 0.34% 的閾值,就可以顯示我們想看到的呼叫圖了。比如執行下面的命令:

$ perf report -g graph,0.3

你就可以得到下面這個新的輸出介面,展開 app 後,就可以看到它的呼叫棧了。

 

四、perf report 報告。

 在perf展開的分析詳情中,有children和self都有90%多的swapper程序,進而去圍繞這個程序展開,忽略只佔用0.6%的app程序?

      看到swapper,先想到的是SWAP分割槽,swapper跟SWAP沒有任何關係,它只是系統初始化時  的init程序,之後就成了一個最低優先順序空閒任務。當CPU上沒有任何任務執行時,就會執行swapper,被稱為“空閒任務”。

在perf report介面中,展開它的呼叫棧,看到swapper時鐘事件都消耗費在了do_idle上,也就是在執行空閒任務:

所以,分析圖,直接忽略前面99%的符號,轉而分析後面只有0.3%的app。其實在多工系統中,次數的事件,不一定就是效能瓶頸。

所以在只觀察一個大數值,並不能說明什麼問題,具體有沒有瓶頸還要觀測多個方面的多個指標,交叉驗證。

另外,關於Children和Self的含義,手冊有詳細說明:

  • Self 是最後一列的符號(可以理解為函式)本身所佔比例;
  • Children 是這個符號呼叫的其他符號(理解為子函式,包括直接呼叫和間接呼叫)佔用的比列之和。

perf,需要在核心中跟蹤核心棧的各種事件,不可避免帶來一定的效能損失,雖然對大部分應用沒有太大影響,但特定某些應用(像對時鐘週期特別敏感的應用),可能就是災難。

在使用效能工具時,要考慮工具本身對系統的影響,就要了解工具的原理:

  • perf 這種動態追蹤工具,會帶來效能損失。
  • vmstat、pidstat這些直接讀取proc 檔案的系統來獲取指標的工具,不會帶來效能損失。 

 五、效能優化書籍和參考資料推薦。

Brendan Gregg 是一位當之無愧的效能優化大師,他的效能工具圖譜很多文章中都會看到:Linux效能篇一

Brendan Gregg 的效能優化書籍《Systems Performance:Enterprise and the Cloud》。中文版的名字是:《效能之巔:洞悉系統、企業與雲端計算》。雖然在2013年出版,但依然是經典,分析思路雞效能工具依然適合現在。

Brendan Gregg 的個人網站:http://www.brendangregg.com/  ,特別是 Linux Performance 這一頁包含很多Linux效能優化資料,比如:

  • Linux效能工具圖譜
  • 效能分析參考資料
  • 效能優化演講視訊

但很多內容涉及到核心知識,對於初學者不太友好,要循序漸進一遍遍閱讀。