.NET 分散式追蹤概念

分散式追蹤是一種診斷技術,可協助工程師將應用程式內的失敗和效能問題當地語系化,特別是針對可能分散於多部電腦或處理序的失敗和效能問題。 如需適合分散式追蹤適用情境的一般資訊以及可著手開始使用的範例程式碼,請參閱分散式追蹤概觀

追蹤和活動

應用程式每次收到新的要求時,都可以與追蹤產生關聯。 在以 .NET 撰寫的應用程式元件中,追蹤內的工作單位,由 System.Diagnostics.Activity 執行個體表示,而整個追蹤會形成這些活動的樹狀結構,有可能跨越多個不同的處理序。 為新要求所建立的第一個活動,會成為追蹤樹狀結構的根,同時也會追蹤整個持續時間以及處理要求的成功或失敗。 您可以選擇性地建立子活動,將工作再細分為可個別追蹤的不同步驟。 例如,假設有一個活動會追蹤網頁伺服器中特定的輸入 HTTP 要求,就可以建立一些子活動,追蹤完成要求所需的每個資料庫查詢。 如此可以讓每個查詢的持續時間和成功,能各自獨立記錄。 活動可以記錄每個工作單位的其他資訊,例如 OperationName、稱為 Tags 的成對名稱和數值,以及 Events。 名稱代表目前正執行的工作類型、標籤可以記錄工作的描述性參數,而事件是一種簡單的記錄機制,可記錄有時間戳記的診斷訊息。

注意

工作單位在分散式追蹤中的另一個常見業界名稱,是「跨度」(Span)。 .NET 在很多年前就採用了「活動」這個術語,當時「跨度」這個名稱還沒有為這個概念確立。

活動識別碼

分散式追蹤樹狀結構中,各活動之間的父子關聯性,使用唯一識別碼所建立。 .NET 所實作的分散式追蹤,支援兩種識別碼結構描述: W3C 標準 TraceContext,此為 .NET 5+ 的預設值,以及一個可用於回溯相容性名爲「階層式」的較舊 .NET 慣例。 Activity.DefaultIdFormat 可控制要使用哪一個識別碼配置。 在 W3C TraceCoNtext 標準中,會為每個追蹤指派一個全域唯一的 16 位元組追蹤識別碼 (Activity.TraceId),而追蹤內的每個活動,也指派有唯一的 8 位元組跨度識別碼 (Activity.SpanId)。 每個活動都會記錄追蹤識別碼、其本身的跨度識別碼,以及其父代的跨度識別碼 (Activity.ParentSpanId)。 因為分散式追蹤可以跨處理序界限進行工作的追蹤,所以父活動和子活動不一定會在相同的處理序中。 追蹤識別碼和父跨度識別碼相組合,即可在全域範圍內找到該獨特的父活動,無論其位於哪個處理序中皆然。

Activity.DefaultIdFormat 可控制用於關始新追蹤的識別碼格式,但根據預設,將新的活動新增至現有追蹤,會使用父活動所用的任何格式。 將 Activity.ForceDefaultIdFormat 設定為 true,可覆寫此行為,並使用 DefaultIdFormat 建立所有新的活動,即使父系使用不同的識別碼格式也一樣。

開始和停止活動

處理序中的每個執行緒,都有對應的活動物件,可以追蹤該執行緒上所發生的工作,並可透過 Activity.Current 進行存取。 目前的活動會自動順著執行緒上的所有同步呼叫進行,同時會追蹤不同執行緒上所處理的非同步呼叫。 如果活動 A 是執行緒上目前的活動,而且程式碼會開始新的活動 B,則 B 會成為該執行緒上新的目前活動。 根據預設,活動 B 也會將活動 A 視為其父系。 活動 B 稍後停止時,活動 A 將會再還原成為執行緒上的目前活動。 當活動開始時,活動會擷取目前的時間做為 Activity.StartTimeUtc。 停止時,會計算目前時間與開始時間之間差異的 Activity.Duration

跨處理序界限協調

若要追蹤跨處理序界限的工作,必須透過網路傳輸活動父識別碼,以便接收處理序可以建立參考它們的活動。 使用 W3C TraceCoNtext 識別碼格式時,.NET 也會使用由標準 所建議的 HTTP 標頭,傳輸這項資訊。 使用 Hierarchical 識別碼格式時,.NET 會使用自訂要求識別碼 HTTP 標頭,來傳輸識別碼。 與許多其他語言執行階段不同的是,.NET 內附的程式庫 (例如 ASP.NET 網頁伺服器和 System.Net.Http),原生了解如何解碼及編碼 HTTP 訊息上的活動識別碼。 該執行階段也了解如何透過同步和非同步呼叫,來傳遞識別碼。 這表示接收和發出 HTTP 訊息的 .NET 應用程式,會自動參與流動分散式追蹤識別碼,不需要應用程式開發人員或協力廠商程式庫相依性的任何特殊編碼。 協力廠商程式庫可能已新增了支援,可透過非 HTTP 訊息通訊協定傳輸識別碼,或支援 HTTP 的自訂編碼慣例。

收集追蹤

經過檢測的程式碼可以建立 Activity 物件,作為分散式追蹤的一部分,但是這些物件中的資訊,必須在集中的永續性存放區中傳輸和序列化,以便稍後能有效地檢閱整個追蹤。 有數個遙測收集程式庫可執行此工作,例如 Application InsightsOpenTelemetry (英文) 或由協力廠商遙測或 APM 廠商所提供的程式庫。 或者,開發人員可以使用 System.Diagnostics.ActivityListenerSystem.Diagnostics.DiagnosticListener,撰寫自己的自訂活動遙測收集。 無論開發人員對其是否有任何事先的了解,ActivityListener 都支援觀察任一活動。 這讓 ActivityListener 成為簡單且具彈性的一般用途解決方案。 相比之下,使用 DiagnosticListener 會是較為複雜的情況,其需要叫用 DiagnosticSource.StartActivity,選擇使用檢測的程式碼,同時用來收集的程式庫必須確實知道啟動檢測程式碼時,所使用的確切命名資訊。 建立者和接聽程式可使用 DiagnosticSource 和 DiagnosticListener,交換任意的 .NET 物件,並建立自訂的資訊傳遞慣例。

取樣

為提升高輸送量應用程式的效能,.NET 上的分散式追蹤支援僅取樣一部分的追蹤,而非記錄所有追蹤。 對於以建議的 ActivitySource.StartActivity API 所建立的活動來說,遙測收集程式庫可以使用 ActivityListener.Sample 回呼,來控制取樣。 記錄程式庫可以選擇完全不建立活動、以散佈分散式追蹤識別碼所需的最少資訊來建立活動,或是對其填入完整的診斷資訊。 這些選擇在加強診斷公用程式能力的同時,承擔了強化效能方面的額外負荷。 使用舊版叫用模式 Activity.ActivityDiagnosticSource.StartActivity 所開始的活動,也可以先呼叫 DiagnosticSource.IsEnabled,來支援 DiagnosticListener 的取樣。 即使要擷取完整的診斷資訊,.NET 的實作也能相當快速 - 加上有效率的收集器,只要大約一微秒,即可在新式硬體上建立、填入及傳輸活動。 取樣可將未記錄之每個活動的檢測成本,降低到小於 100 奈秒。

下一步

如需在 .NET 應用程式中開始使用分散式追蹤的範例程式碼,請參閱分散式追蹤檢測