最佳化 Go 應用程式
在本教學課程中,您會部署刻意降低效率的 Go 應用程式,並設定收集設定檔資料。您可以使用 Profiler 介面查看設定檔資料,並找出可進行的最佳化。接著,您修改應用程式、部署應用程式,並評估修改效果。
事前準備
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Enable the required API.
- 如要開啟 Cloud Shell,請在 Google Cloud 控制台工具列中,按一下「啟用 Cloud Shell」:
稍後,Cloud Shell 工作階段會在Google Cloud 控制台中開啟:
在 Cloud Shell 中執行下列指令:
git clone https://github.com/GoogleCloudPlatform/golang-samples.git cd golang-samples/profiler/shakesapp
執行應用程式,將版本設為
1
,並將回合數設為 15:go run . -version 1 -num_rounds 15
一兩分鐘後,系統就會顯示設定檔資料。設定檔資料如下所示:
在螢幕截圖中,請注意「Profile type」(設定檔類型) 已設為
CPU time
。 這表示火焰圖中顯示的是 CPU 使用率資料。Cloud Shell 中列印的輸出內容範例如下所示:
$ go run . -version 1 -num_rounds 15 2020/08/27 17:27:34 Simulating client requests, round 1 2020/08/27 17:27:34 Stackdriver Profiler Go Agent version: 20200618 2020/08/27 17:27:34 profiler has started 2020/08/27 17:27:34 creating a new profile via profiler service 2020/08/27 17:27:51 Simulated 20 requests in 17.3s, rate of 1.156069 reqs / sec 2020/08/27 17:27:51 Simulating client requests, round 2 2020/08/27 17:28:10 Simulated 20 requests in 19.02s, rate of 1.051525 reqs / sec 2020/08/27 17:28:10 Simulating client requests, round 3 2020/08/27 17:28:29 Simulated 20 requests in 18.71s, rate of 1.068947 reqs / sec ... 2020/08/27 17:44:32 Simulating client requests, round 14 2020/08/27 17:46:04 Simulated 20 requests in 1m32.23s, rate of 0.216849 reqs / sec 2020/08/27 17:46:04 Simulating client requests, round 15 2020/08/27 17:47:52 Simulated 20 requests in 1m48.03s, rate of 0.185134 reqs / sec
Cloud Shell 輸出內容會顯示每次疊代的經過時間和平均要求率。應用程式啟動時,「Simulated 20 requests in 17.3s, rate of 1.156069 reqs / sec」項目表示伺服器每秒執行約 1 個要求。在最後一輪中,「Simulated 20 requests in 1m48.03s, rate of 0.185134 reqs / sec」項目表示伺服器大約每 5 秒執行 1 項要求。
執行應用程式,並將應用程式版本設為
2
:go run . -version 2 -num_rounds 40
稍後會說明,經過最佳化後,執行單一回合所需的時間遠少於未修改的應用程式。為確保應用程式執行時間足夠長,可收集及上傳設定檔,因此增加了回合數。
等待應用程式完成,然後查看這個應用程式版本的剖析資料:
- 按一下「立即」即可載入最新的設定檔資料。詳情請參閱「時間範圍」一節。
- 在「版本」選單中,選取「2」。
每秒要求數從每秒不到 1 個增加到每秒 5.8 個。
CPU 使用率除以每秒要求數後,每個要求的 CPU 時間從 23.7% 降至 13.4%。
請注意,雖然 CPU 時間用量從 2.37 秒 (相當於單一 CPU 核心的 23.7% 使用率) 增加到 7.8 秒 (相當於 CPU 核心的 78%),但每個要求的 CPU 時間仍減少。
堆積設定檔會顯示在收集設定檔時,程式堆積中分配到的記憶體大小。
「分配的堆積」設定檔會顯示在收集設定檔的間隔期間,程式堆積中分配到的記憶體總量。將這些值除以 10 秒 (設定檔收集間隔),即可解讀為分配率。
執行應用程式,並將應用程式版本設為
3
,然後啟用堆積和已分配堆積設定檔的收集作業。go run . -version 3 -num_rounds 40 -heap -heap_alloc
等待應用程式完成,然後查看這個應用程式版本的剖析資料:
- 按一下「立即」即可載入最新的設定檔資料。
- 在「版本」選單中,選取「3」。
- 在「分析器類型」選單中,選取「已分配的堆積」。
舉例來說,火焰圖如下所示:
執行應用程式,並將應用程式版本設為
4
:go run . -version 4 -num_rounds 60 -heap -heap_alloc
等待應用程式完成,然後查看這個應用程式版本的剖析資料:
- 按一下「立即」即可載入最新的設定檔資料。
- 在「版本」選單中,選取「4」。
- 在「分析器類型」選單中,選取「已分配的堆積」。
如要量化變更
readFiles
對堆積分配率的影響,請比較版本 4 的已分配堆積剖析資料與版本 3 的資料:根架構的工具提示顯示,與第 3 版相比,第 4 版在剖析資料收集期間分配的平均記憶體量減少了 1.301 GiB。
readFiles.func1
的工具提示顯示減少 1.045 GiB:如要量化垃圾收集的影響,請設定 CPU 作業時間剖析資料的比較。在下列螢幕截圖中,系統已套用篩選器,顯示 Go 垃圾收集器的堆疊
runtime.gcBgMarkWorker.*
。螢幕截圖顯示垃圾收集的 CPU 使用率從 16.8% 降至 4.97%。如要判斷這項變更是否會影響應用程式每秒處理的要求數,請查看 Cloud Shell 中的輸出內容。在本例中,第 4 版每秒最多可完成 15 個要求,遠高於第 3 版的每秒 5.8 個要求:
$ go run . -version 4 -num_rounds 60 -heap -heap_alloc 2020/08/27 21:51:42 Simulating client requests, round 1 2020/08/27 21:51:42 Stackdriver Profiler Go Agent version: 20200618 2020/08/27 21:51:42 profiler has started 2020/08/27 21:51:42 creating a new profile via profiler service 2020/08/27 21:51:44 Simulated 20 requests in 1.47s, rate of 13.605442 reqs / sec 2020/08/27 21:51:44 Simulating client requests, round 2 2020/08/27 21:51:45 Simulated 20 requests in 1.3s, rate of 15.384615 reqs / sec 2020/08/27 21:51:45 Simulating client requests, round 3 2020/08/27 21:51:46 Simulated 20 requests in 1.31s, rate of 15.267176 reqs / sec ...
應用程式每秒處理的查詢次數增加,可能是因為垃圾收集所花的時間減少。
如要更全面瞭解修改對
readFiles
的影響,請查看堆積設定檔。比較第 4 版和第 3 版的堆積剖析資料,可看出堆積用量從 70.95 MiB 減少至 18.47 MiB:使用 CPU 時間設定檔時,系統會識別出 CPU 密集型函式。 套用簡單變更後,伺服器的要求頻率從每秒約 1 次增加至每秒 5.8 次。
使用已分配的堆積剖析,發現
shakesapp/server.go
函式readFiles
的分配率偏高。最佳化readFiles
後,伺服器的要求傳送頻率提高至每秒 15 次,且在 10 秒的剖析資料收集期間,平均分配到的記憶體量減少了 1.301 GiB。
應用程式範例
主要目標是盡可能提高伺服器每秒可處理的查詢次數。次要目標是減少記憶體用量,方法是消除不必要的記憶體配置。
伺服器會使用 gRPC 架構接收字詞或詞組,然後傳回該字詞或詞組在莎士比亞作品中出現的次數。
伺服器每秒可處理的平均查詢次數,取決於伺服器負載測試。在每輪測試中,系統會呼叫用戶端模擬器,並指示發出 20 個連續查詢。一輪完成後,系統會顯示用戶端模擬器傳送的查詢數量、經過的時間,以及每秒平均查詢數量。
伺服器程式碼效率不彰。
執行範例應用程式
下載並執行範例應用程式:
使用 CPU 時間設定檔,盡可能提高每秒查詢次數
如要盡可能提高每秒查詢次數,其中一個方法是找出耗用大量 CPU 的方法,並最佳化實作方式。在本節中,您會使用 CPU 時間設定檔,找出伺服器中耗用大量 CPU 的方法。
找出 CPU 時間用量
火焰圖的根框架會列出應用程式在 10 秒的收集間隔內使用的 CPU 總時間:
在本範例中,使用的服務為 2.37 s
。如果系統在單一核心上執行,2.37 秒的 CPU 時間用量就相當於該核心的 23.7% 使用率。詳情請參閱可用的剖析類型。
修改應用程式
評估變更
如要評估變更,請按照下列步驟操作:
舉例來說,火焰圖如下所示:
在本圖中,根影格顯示的值為 7.8 s
。由於變更了字串比對函式,應用程式使用的 CPU 時間從 2.37 秒增加到 7.8 秒,也就是應用程式從使用 23.7% 的 CPU 核心,增加到使用 78% 的 CPU 核心。
影格寬度是 CPU 時間用量的比例測量值。在這個範例中,GetMatchCount
的框架寬度表示函式約佔應用程式所用 CPU 作業時間的 49%。在原始火焰圖中,這個影格約占圖表寬度的 72%。如要查看確切的 CPU 時間用量,可以使用影格工具提示,或使用「Focus function list」(聚焦函式清單):
Cloud Shell 的輸出內容顯示,修改後的版本每秒完成約 5.8 個要求:
$ go run . -version 2 -num_rounds 40 2020/08/27 18:21:40 Simulating client requests, round 1 2020/08/27 18:21:40 Stackdriver Profiler Go Agent version: 20200618 2020/08/27 18:21:40 profiler has started 2020/08/27 18:21:40 creating a new profile via profiler service 2020/08/27 18:21:44 Simulated 20 requests in 3.67s, rate of 5.449591 reqs / sec 2020/08/27 18:21:44 Simulating client requests, round 2 2020/08/27 18:21:47 Simulated 20 requests in 3.72s, rate of 5.376344 reqs / sec 2020/08/27 18:21:47 Simulating client requests, round 3 2020/08/27 18:21:51 Simulated 20 requests in 3.58s, rate of 5.586592 reqs / sec ... 2020/08/27 18:23:51 Simulating client requests, round 39 2020/08/27 18:23:54 Simulated 20 requests in 3.46s, rate of 5.780347 reqs / sec 2020/08/27 18:23:54 Simulating client requests, round 40 2020/08/27 18:23:58 Simulated 20 requests in 3.4s, rate of 5.882353 reqs / sec
應用程式的微小變更產生了兩種不同的影響:
使用已分配的堆積設定檔來提升資源用量
本節說明如何使用堆積和已分配堆積的剖析檔,找出應用程式中耗用大量分配空間的方法:
啟用堆積設定檔收集功能
找出堆積分配率
根框架會顯示在收集剖析資料的 10 秒期間內分配到的堆積總量,並計算所有剖析資料的平均值。在本例中,根影格顯示平均分配了 1.535 GiB 的記憶體。
修改應用程式
評估變更
如要評估變更,請按照下列步驟操作:
摘要
在本快速入門導覽課程中,我們使用 CPU 時間和已分配堆積設定檔,找出應用程式的潛在最佳化項目。目標是盡量提高每秒要求數,並消除不必要的分配作業。