剖析概念

本頁面提供有關剖析的一般背景資訊、Stackdriver Profiler 可用的剖析類型及其他相關資訊。

什麼是剖析?

剖析是一種動態程式碼分析作業。也就是說,剖析可讓您在程式碼「執行期間」 (即「動態」部分) 擷取程式碼的特性,以便您掌握實際的資源使用情況或程式的效能特徵。

在開發和測試期間剖析程式碼,有助您最佳化程式碼設計並找出錯誤,降低實際運作時發生災難性失敗事件的風險。

剖析實際工作環境中的程式碼能協助您預測潛在問題發生的時機,並診斷可能出現的問題。

剖析不同於程式碼分析,前者會在收集執行中程式碼的統計資料時對程式加上額外的負載,而後者是檢查應用程式的原始碼 (並不是對運作中的應用程式進行檢查)。此外,剖析需要一個能從執行環境中收集和擷取相關統計資料的途徑;而這會對程式增加額外的負載。

收集剖析資料的方式很多,減少執行中應用程式額外負載的方式也不少。不過,這些方式通常需要在特性剖析的準確率和執行中應用程式的效能之間做取捨。

Stackdriver Profiler

Stackdriver Profiler 是一種統計型 (或取樣型) 分析器,不需要廣泛更動程式的程式碼也能收集資料。基本上,只要將一小段程式碼 (稱為「剖析代理程式」) 附加到程式碼,就能定期查看程式的呼叫堆疊,進而收集 CPU 或記憶體使用情況等相關資訊。

取樣分析器只取樣剖析特徵,因此準確率和精確度通常比較低,但對剖析的應用程式效能影響最小,這點對於持續剖析實際工作環境中的程式碼來說尤其重要。儘管只是統計上的約略值,但隨著樣本數增加,準確率也會隨之提升。

如要瞭解如何將 Stackdriver Profiler 代理程式搭配您的應用程式執行,請參閱以下頁面:

收集 Profiler 資料之後,您可使用 Profiler 介面來進行分析。

可用的剖析類型

Stackdriver Profiler 支援的剖析類型因程式的撰寫語言而異。下表按語言列出支援的剖析類型:

剖析類型 Go Java Node.js Python
[CPU time] (CPU 作業時間)
[Heap] (堆積)
[Allocated heap] (分配的堆積)
[Contention] (爭用情況)
[Threads] (執行緒)
[Wall time] (實際時間)

時間計算

  • CPU 時間是指 CPU 花費在執行程式碼區塊的時間。

  • 時鐘時間 (又稱為「實際時間」) 是指執行一個程式碼區塊所需的時間。

函式的 CPU 時間能讓您知道在函式中執行特定程式碼需要多久的時間。這個指標會計算 CPU 忙於處理指令的時間,但不會計入 CPU 等候 (或處理其他指令) 的時間。

函式的時鐘時間是計算從進入到離開函式所經歷的時間,包含等候資料庫存取權解除鎖定、執行緒同步處理、鎖定等作業的時間。理論上,程式碼區塊的實際時間一定會比 CPU 時間長。

程式碼區塊有可能需要很長的執行時間,實際上卻只佔用少數 CPU 時間。如果實際時間值遠大於 CPU 時間值,這意味著程式碼花很多時間等候其他作業進行;而需要花大量時間等候其他作業完成的程式碼區塊可能會發生資源瓶頸,也就是有太多要求者嘗試存取部分有限的資源。

如果 CPU 作業時間與實際時間很接近,則表示程式碼區塊會耗用大量 CPU 資源;幾乎所有執行時間都是由 CPU 所占用。長時間執行的 CPU 密集型程式碼區塊可能可列入最佳化候選名單:是否有更能充分發揮 CPU 效益的工作方式?比如說作業數較少或執行速度更快的做法?

堆積 (記憶體) 使用量

  • 堆積使用量 (又稱為「堆積」) 是指在收集剖析資料時,在程式的堆積中分配到的記憶體大小。

  • 堆積分配量 (又稱為「分配的堆積」) 是指在程式的堆積中分配到的記憶體總和大小,包括已釋出且不再使用的記憶體。

程式在執行時會用到記憶體;程式建立的物件會佔用空間,程式呼叫的函式也會佔用空間。

運作良好的程式會有效且適度地利用記憶體資源。程式會只使用需要的記憶體,不佔用大量記憶體空間;且不再需要記憶體時將釋回該記憶體空間,不致於平白流失。

假如程式使用比實際需求更多的記憶體,或不再需要時仍繼續佔用記憶體,啟動時速度可能會比較慢或逐漸變慢,甚至當機或影響到其他應用程式可用的資源。針對垃圾收集,如果程式分配記憶體的頻率多過實際需求,就會為垃圾收集器帶來更多工作。

剖析堆積使用量可協助您發現程式中潛在的效率低落及記憶體流失狀況。剖析堆積分配量可協助您掌握哪些分配項目會為垃圾收集器帶來最多工作。

執行緒資訊

建立執行緒的應用程式可能會遇到執行緒遭封鎖 (執行緒已建立但絕對不會實際執行),以及執行緒流失 (已建立的執行緒數量不斷增加) 的問題;前者是導致後者發生的其中一個可能原因。

爭用情況

在多執行緒程式中,等待共用資源存取權序列化可能會佔用大量時間。瞭解爭用行為可協助引導程式碼設計,並掌握可用於調整效能的資訊。

收集剖析資料

如要針對 Java 以外的所有語言,將 Stackdriver Profiler 與您的服務搭配使用,您將需要修改服務,使其在服務啟動時產生剖析代理程式執行個體。如果是 Java 應用程式,則需要修改服務的啟動方式。系統會針對應用程式的每個執行個體產生一個剖析代理程式執行個體。

代理程式的作用是從您的服務擷取剖析資料,然後使用 Profiler API 將這些資料傳輸至 Profiler 後端。每組剖析資料僅適用於單一服務執行個體,其中包含四個可識別其部署項目的欄位:

  • GCP 專案
  • 服務名稱
  • 服務區域
  • 服務版本

代理程式準備好開始擷取剖析資料時,會向 Profiler 後端發出 Profiler API 指令。後端會接收這個要求,然後 (在最簡單的情況下) 立即回覆代理程式。回覆內容會指定要擷取的剖析類型。接著代理程式便會擷取剖析資料並將其傳輸至後端。最後,Profiler 後端會將剖析資料與您的 GCP 專案建立關聯。然後,您便可以使用 Profiler UI 來查看和分析資料。

實際的握手序列比上一段內容所描述的更複雜。例如,當 Profiler 收到來自準備好收集剖析資料之代理程式的要求時,後端會檢查其資料庫,判斷先前是否曾收到該代理程式的要求。如果沒有,後端會將代理程式資訊新增至其資料庫中。如果該代理程式的部署項目欄位與任何其他已記錄之代理程式的部署項目欄位不相符,系統將會建立新的部署項目。

後端平均每分鐘會針對每個部署項目和每個剖析類型選取一個代理程式,並指示代理程式擷取剖析資料。例如,如果部署項目的代理程式支援堆積和實際時間剖析,則平均每分鐘會擷取 2 組剖析資料:

  • 對於所有剖析類型 (堆積使用量和執行緒使用量除外),一組剖析資料代表收集 10 秒的資料。

  • 對於堆積使用量和執行緒剖析資料,每組剖析資料都是即時收集的。

主要觀察結果是,在代理程式通知 Profiler 後端它已準備好擷取資料後,代理程式就會處於閒置狀態,直到它收到來自後端的回覆,指定要擷取的剖析類型為止。如果同一個部署項目中,有 10 個相同服務的執行個體正在運作,則要建立 10 個剖析代理程式。不過,這些代理程式大部分時間都會處於閒置狀態。在 10 分鐘的期間,您預期收會到 10 組剖析資料;針對每個剖析類型,每個代理程式平均會收到一個回覆。由於其中有些隨機作業,因此實際數量可能會有所不同。

Profiler 後端會使用 Profiler API 配額和剖析資料部署欄位來限制所擷取的剖析資料。如要瞭解如何查看和管理 Profiler 配額,請參閱配額與限制一文。

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Stackdriver Profiler