在 AKS 中監視微服務應用程式

Azure 監視器
Azure Kubernetes Service (AKS)

本文說明監視在 Azure Kubernetes Service (AKS) 上執行的微服務應用程式的最佳做法。 特定主題包括遙測收集、監視叢集的狀態、計量、記錄、結構化記錄和分散式追蹤。 下圖說明後者:

Diagram that shows the architecture of a drone delivery application.

下載此架構的 Visio 檔案

遙測集合

在任何複雜的應用程式中,在某些時候發生問題。 在微服務應用程式中,您需要追蹤數十項甚至數百項服務的情況。 若要瞭解發生的情況,您需要從應用程式收集遙測。 遙測可以分成下列類別: 記錄 追蹤 計量

記錄 是應用程式執行時所發生的事件文字型記錄。 它們包括應用程式記錄(追蹤語句)和 Web 服務器記錄等專案。 記錄主要用於鑒識和根本原因分析。

追蹤也稱為 作業 ,可跨微服務內的多個呼叫,連接單一要求的步驟。 它們可以在系統元件的互動中提供結構化的可觀察性。 追蹤可以在要求程式初期開始,例如在應用程式的 UI 內,而且可以透過處理要求的微服務網路透過網路服務傳播。

  • 範圍是追蹤內的工作單位。 每個範圍都與單一追蹤連接,而且可以與其他範圍巢狀。 它們通常會對應到跨服務作業中的個別 要求 ,但它們也可以在服務內的個別元件中定義工作。 Spans 也會追蹤從一個服務到另一個服務的輸出呼叫。 (有時範圍稱為 相依性記錄

計量是可分析的數值。 您可以使用它們來即時觀察系統(或接近即時),或分析一段時間的效能趨勢。 若要全面瞭解系統,您需要從實體基礎結構到應用程式,收集不同層級架構的計量,包括:

  • 節點層級 計量,包括 CPU、記憶體、網路、磁片和檔案系統使用量。 系統計量可協助您瞭解叢集中每個節點的資源配置,以及針對極端值進行疑難排解。

  • 容器 計量。 針對容器化應用程式,您必須在容器層級收集計量,而不只是在 VM 層級。

  • 應用程式 計量。 這些計量與瞭解服務的行為相關。 範例包括佇列輸入 HTTP 要求數目、要求延遲和訊息佇列長度。 應用程式也可以使用網域特定的自訂計量,例如每分鐘處理的商務交易數目。

  • 相依服務 計量。 服務有時會呼叫外部服務或端點,例如受控 PaaS 或 SaaS 服務。 協力廠商服務可能無法提供計量。 如果沒有,您必須依賴自己的應用程式計量來追蹤延遲和錯誤率的統計資料。

監視叢集狀態

使用 Azure 監視器 來監視叢集的健康情況。 下列螢幕擷取畫面顯示使用者部署 Pod 中發生嚴重錯誤的叢集:

Screenshot that shows the Monitor dashboard.

您可以從這裡進一步鑽研以找出問題。 例如,如果 Pod 狀態為 ImagePullBackoff ,Kubernetes 就無法從登錄提取容器映射。 此問題可能是因為從登錄提取期間發生不正確容器標記或驗證錯誤所造成。

如果容器當機,容器 StateWaiting 變成 ,且 具有 ReasonCrashLoopBackOff 的 。 針對一般案例,其中 Pod 是複本集的一部分,而重試原則是 Always ,此問題不會在叢集狀態中顯示為錯誤。 不過,您可以執行查詢或設定此條件的警示。 如需詳細資訊,請參閱 使用 Azure 監視器容器深入解析 瞭解 AKS 叢集效能。

AKS 資源的活頁簿窗格中有多個容器特定的活頁簿可供使用。 您可以使用這些活頁簿快速概觀、疑難排解、管理和深入解析。 下列螢幕擷取畫面顯示 AKS 工作負載預設可用的活頁簿清單。

Screenshot that shows the workbooks for an AKS resource.

計量

建議您使用 監視器 來收集及檢視 AKS 叢集和其他任何相依 Azure 服務的計量。

  • 針對叢集和容器計量,啟用 Azure 監視器容器深入解析 。 啟用此功能時,監視器會透過 Kubernetes 計量 API 從控制器、節點和容器收集記憶體和處理器計量。 如需容器深入解析中可用計量的詳細資訊,請參閱 使用 Azure 監視器容器深入解析 瞭解 AKS 叢集效能。

  • 使用 Application Insights 收集應用程式計量。 Application Insights 是可延伸的應用程式效能管理 (APM) 服務。 若要使用它,您可以在應用程式中安裝檢測套件。 此套件會監視應用程式,並將遙測資料傳送至 Application Insights。 它也可以從主機環境提取遙測資料。 然後,資料會傳送至監視器。 Application Insights 也提供內建的相互關聯和相依性追蹤。 (請參閱 本文稍後的分散式追蹤

Application Insights 的輸送量上限為每秒事件測量,如果資料速率超過限制,則會節流遙測。 如需詳細資訊,請參閱 Application Insights 限制 。 為每個環境建立不同的 Application Insights 實例,讓開發/測試環境不會與生產遙測競爭以取得配額。

單一作業可能會產生許多遙測事件,因此,如果應用程式遇到大量流量,其遙測擷取可能會受到節流。 若要減輕此問題,您可以執行取樣以減少遙測流量。 取捨是,除非您的檢測支援 預先匯總 ,否則計量會比較不精確。 在此情況下,疑難排解的追蹤範例會較少,但計量會維持正確性。 如需詳細資訊,請參閱 Application Insights 中的取樣。 您也可以藉由預先匯總計量來減少資料量。 也就是說,您可以計算統計值,例如平均值和標準差,並傳送這些值,而不是原始遙測。 此部落格文章說明大規模使用 Application Insights 的方法: 大規模 Azure 監視和分析

如果您的資料速率夠高,無法觸發節流,而且無法接受取樣或匯總,請考慮將計量匯出至時間序列資料庫,例如 Azure 資料總管、Prometheus 或 InfluxDB,在叢集中執行。

  • Azure 資料總 管是適用于記錄和遙測資料的 Azure 原生、高度可調整的資料探索服務。 它支援多種資料格式、豐富的查詢語言,以及在 Jupyter Notebook 和 Grafana 等 熱門工具中取用資料的連線。 Azure 資料總管有內建連接器,可透過Azure 事件中樞內嵌記錄和計量資料。 如需詳細資訊,請參閱 在 Azure 資料總 管中擷取和查詢監視資料。

  • InfluxDB 是以推送為基礎的系統。 代理程式需要推送計量。 您可以使用 TICK 堆疊 來設定 Kubernetes 的監視。 接下來,您可以使用 Telegraf 將計量推送至 InfluxDB ,這是收集及報告計量的代理程式。 您可以將 InfluxDB 用於不規則的事件和字串資料類型。

  • Prometheus 是以提取為基礎的系統。 它會定期從設定的位置擷取計量。 Prometheus 可以 擷取 Azure 監視器 或 kube-state-metrics 所產生的計量。 kube-state-metrics 是一項服務,可從 Kubernetes API 伺服器收集計量,並將其提供給 Prometheus(或與 Prometheus 用戶端端點相容的刮刀)。 針對系統計量,請使用 節點匯出工具 ,這是系統計量的 Prometheus 匯出工具。 Prometheus 支援浮點數據,但不支援字串資料,因此適用于系統計量,但不適用於記錄。 Kubernetes Metrics Server 是資源使用量資料的全叢集匯總工具。

Logging

以下是在微服務應用程式中記錄的一些一般挑戰:

  • 了解用戶端要求的端對端處理,其中可能會叫用多個服務來處理單一要求。
  • 將多個服務的記錄合併成單一匯總檢視。
  • 剖析來自使用自己記錄架構或沒有特定架構之多個來源的記錄。 記錄可能會由您不控制的協力廠商元件產生。
  • 微服務架構通常會產生比傳統整合型更大的記錄量,因為交易中有更多的服務、網路呼叫和步驟。 這表示記錄本身可能是應用程式的效能或資源瓶頸。

Kubernetes 架構有一些額外的挑戰:

  • 容器可能四處移動並重新排程。
  • Kubernetes 具有使用虛擬 IP 位址與連接埠對應的網路抽象概念。

在 Kubernetes 中,記錄的標準方法是讓容器將記錄寫入 stdout 和 stderr。 容器引擎會將這些資料流程重新導向至記錄驅動程式。 若要讓查詢變得更容易,並在節點停止回應時防止可能遺失記錄資料,通常的方法就是從每個節點收集記錄,並將其傳送至中央儲存位置。

Azure 監視器會與 AKS 整合,以支援此方法。 監視會收集容器記錄,並將其傳送至 Log Analytics 工作區。 您可以從該處使用 Kusto 查詢語言 ,跨匯總記錄寫入查詢。 例如,以下是 用來顯示指定 Pod 之容器記錄 的 Kusto 查詢:

ContainerLogV2
| where PodName == "podName" //update with target pod
| project TimeGenerated, Computer, ContainerId, LogMessage, LogSource

Azure 監視器是受控服務,而將 AKS 叢集設定為使用監視器,是 CLI 或 Azure Resource Manager 範本中的簡單組態變更。 (如需詳細資訊,請參閱 如何啟用 Azure 監視器容器深入解析 。使用 Azure 監視器的另一個優點是,它會將您的 AKS 記錄與其他 Azure 平臺記錄合併,以提供統一的監視體驗。

Azure 監視器會依擷取至服務的資料,以 GB 為單位計費。 (請參閱 Azure 監視器定價 。)在大量成本下,成本可能會成為考慮。 Kubernetes 生態系統有許多開放原始碼替代方案。 例如,許多組織都使用 Fluentd 搭配 Elasticsearch。 Fluentd 是開放原始碼資料收集器,Elasticsearch 是用於搜尋的檔資料庫。 這些選項的挑戰在於它們需要額外的設定和管理叢集。 針對生產工作負載,您可能需要實驗組態設定。 您也需要監視記錄基礎結構的效能。

OpenTelemetry

OpenTelemetry 是跨產業努力,透過標準化應用程式、程式庫、遙測和資料收集器之間的介面來改善追蹤。 當您使用以 OpenTelemetry 檢測的程式庫和架構時,傳統系統作業的大部分追蹤作業工作都會由基礎程式庫處理,其中包含下列常見案例:

  • 記錄基本要求作業,例如開始時間、結束時間和持續時間
  • 擲回的例外狀況
  • 內容傳播(例如跨 HTTP 呼叫界限傳送相互關聯識別碼)

相反地,處理這些作業的基底程式庫和架構會建立豐富的相互關聯範圍和追蹤資料結構,並跨內容傳播它們。 在 OpenTelemetry 之前,這些通常只是插入為特殊的記錄訊息,或作為建置監視工具之廠商專屬的專屬資料結構。 OpenTelemetry 也鼓勵比傳統記錄優先方法更豐富的檢測資料模型,而且記錄會更有用,因為記錄訊息會連結到產生追蹤和範圍。 這通常會讓尋找與特定作業或要求相關聯的記錄變得容易。

許多 Azure SDK 都已使用 OpenTelemetry 進行檢測,或正在實作它。

應用程式開發人員可以使用 OpenTelemetry SDK 來新增手動檢測,以執行下列活動:

  • 新增基礎程式庫未提供它的檢測。
  • 藉由新增範圍來公開應用程式特定工作單位來擴充追蹤內容(例如建立處理每個訂單行範圍的訂單迴圈)。
  • 使用實體索引鍵擴充現有的範圍,以方便追蹤。 (例如,將 OrderID 索引鍵/值新增至處理該訂單的要求。這些索引鍵會由監視工具呈現為結構化值來查詢、篩選和匯總(不需要剖析記錄訊息字串或尋找記錄消息序列的組合,就像記錄優先方法一樣常見)。
  • 藉由存取追蹤和範圍屬性、將 traceId 插入回應和承載,以及/或從傳入訊息讀取 traceId,以傳播追蹤內容,以建立要求和範圍。

在 OpenTelemetry 檔中 深入瞭解檢測和 OpenTelemetry SDK

Application Insights

Application Insights 會從 OpenTelemetry 及其檢測程式庫收集豐富資料,並在有效率的資料存放區中擷取它,以提供豐富的視覺效果和查詢支援。 Application Insights OpenTelemetry 型檢測程式庫 ,適用于 .NET、JAVA、Node.js 和 Python 等語言,可讓您輕鬆地將遙測資料傳送至 Application Insights。

如果您使用 .NET Core,建議您也考慮 Application Insights for Kubernetes 程式庫。 此程式庫會使用其他資訊擴充 Application Insights 追蹤,例如容器、節點、Pod、標籤和複本集。

Application Insights 會將 OpenTelemetry 內容對應至其內部資料模型:

  • 追蹤 - > 作業
  • 追蹤識別碼 - > 作業識別碼
  • Span - > 要求或相依性

將下列考慮納入考慮:

  • 如果資料速率超過上限,Application Insights 會節流遙測。 如需詳細資訊,請參閱 Application Insights 限制 。 單一作業可能會產生數個遙測事件,因此,如果應用程式遇到大量的流量,可能會進行節流。
  • 因為 Application Insights 會批次處理資料,因此如果進程失敗且發生未處理的例外狀況,您可能會遺失批次。
  • Application Insights 計費是以資料量為基礎。 如需詳細資訊,請參閱 管理 Application Insights 中的定價和資料量。

結構化記錄

若要讓記錄更容易剖析,請在您可以時使用結構化記錄。 當您使用結構化記錄時,應用程式會以結構化格式寫入記錄,例如 JSON,而不是輸出非結構化文字字串。 有許多結構化記錄程式庫可供使用。 例如,以下是使用 .NET Core Serilog 程式庫 的記錄語句:

public async Task<IActionResult> Put([FromBody]Delivery delivery, string id)
{
    logger.LogInformation("In Put action with delivery {Id}: {@DeliveryInfo}", id, delivery.ToLogInfo());

    ...
}

在這裡,呼叫 包含 LogInformationId 參數和 DeliveryInfo 參數。 當您使用結構化記錄時,這些值不會插入訊息字串中。 相反地,記錄輸出看起來會像這樣:

{"@t":"2019-06-13T00:57:09.9932697Z","@mt":"In Put action with delivery {Id}: {@DeliveryInfo}","Id":"36585f2d-c1fa-4a3d-9e06-a7f40b7d04ef","DeliveryInfo":{...

這是 JSON 字串,其中 @t 欄位是時間戳記、 @mt 是訊息字串,而其餘的索引鍵/值組是參數。 輸出 JSON 格式可讓您更輕鬆地以結構化的方式查詢資料。 例如,以 Kusto 查詢語言 撰寫 的下列 Log Analytics 查詢會搜尋來自所有名為 fabrikam-delivery 之容器的這個特定訊息實例:

traces
| where customDimensions.["Kubernetes.Container.Name"] == "fabrikam-delivery"
| where customDimensions.["{OriginalFormat}"] == "In Put action with delivery {Id}: {@DeliveryInfo}"
| project message, customDimensions["Id"], customDimensions["@DeliveryInfo"]

如果您在Azure 入口網站中檢視結果,您可以看到這是 DeliveryInfo 包含模型序列化表示的 DeliveryInfo 結構化記錄:

Screenshot that shows the Log Analytics workspace.

以下是此範例中的 JSON:

{
  "Id": "36585f2d-c1fa-4a3d-9e06-a7f40b7d04ef",
  "Owner": {
    "UserId": "user id for logging",
    "AccountId": "52dadf0c-0067-43e7-af76-86e32b48bc5e"
  },
  "Pickup": {
    "Altitude": 0.29295161612934972,
    "Latitude": 0.26815900219052985,
    "Longitude": 0.79841844309047727
  },
  "Dropoff": {
    "Altitude": 0.31507750848078986,
    "Latitude": 0.753494655598651,
    "Longitude": 0.89352830773849423
  },
  "Deadline": "string",
  "Expedited": true,
  "ConfirmationRequired": 0,
  "DroneId": "AssignedDroneId01ba4d0b-c01a-4369-ba75-51bde0e76cc9"
}

許多記錄訊息會標示工作單位的開始或結束,或將商務實體與一組訊息和作業連接,以便追蹤。 在許多情況下,擴充 OpenTelemetry 範圍和要求物件是比只記錄作業開始和結束更好的方法。 這麼做會將該內容新增至所有連接的追蹤和子作業,並將該資訊放在完整作業的範圍內。 各種語言的 OpenTelemetry SDK 支援在範圍上建立範圍或新增自訂屬性。 例如,下列程式碼 使用 Application Insights 支援的 JAVA OpenTelemetry SDK 。 現有的父範圍(例如,與 REST 控制器呼叫相關聯的要求範圍,並由正在使用的 Web 架構所建立)可以使用與其相關聯的實體識別碼進行擴充,如下所示:

import io.opentelemetry.api.trace.Span;

// ...

Span.current().setAttribute("A1234", deliveryId);

此程式碼會在目前的範圍上設定索引鍵或值,該值會連接到該範圍下發生的作業和記錄訊息。 此值會出現在 Application Insights 要求物件中,如下所示:

requests
| extend deliveryId = tostring(customDimensions.deliveryId)  // promote to column value (optional)
| where deliveryId == "A1234"
| project timestamp, name, url, success, resultCode, duration, operation_Id, deliveryId

當搭配記錄、篩選和標注具有跨範圍內容的記錄追蹤時,這項技術變得更強大,如下所示:

requests
| extend deliveryId = tostring(customDimensions.deliveryId)  // promote to column value (optional)
| where deliveryId == "A1234"
| project deliveryId, operation_Id, requestTimestamp = timestamp, requestDuration = duration  // keep some request info
| join kind=inner traces on operation_Id   // join logs only for this deliveryId
| project requestTimestamp, requestDuration, logTimestamp = timestamp, deliveryId, message

如果您使用已使用 OpenTelemetry 檢測的程式庫或架構,它會處理建立範圍和要求,但應用程式程式碼可能也會建立工作單位。 例如,對每個實體執行工作的實體陣列迴圈的方法,可能會為每個處理迴圈的反復專案建立範圍。 如需將檢測新增至應用程式和程式庫程式碼的資訊,請參閱 OpenTelemery 檢測檔

分散式追蹤

當您使用微服務時,其中一個挑戰是瞭解跨服務的事件流程。 單一交易可能牽涉到呼叫多個服務。

分散式追蹤的範例

此範例描述透過一組微服務的分散式交易路徑。 此範例是以無人機遞送應用程式 為基礎

Diagram that shows the architecture of a drone delivery application.

在此案例中,分散式交易包含下列步驟:

  1. 擷取服務會將訊息放在Azure 服務匯流排佇列上。
  2. 工作流程服務會從佇列提取訊息。
  3. 工作流程服務會呼叫三個後端服務來處理要求(無人機排程器、套件和傳遞)。

下列螢幕擷取畫面顯示 無人機遞送應用程式的應用程式對應 。 此對應會顯示對公用 API 端點的呼叫,該端點會產生涉及五個微服務的工作流程。

Screenshot that shows the application map for the drone delivery application.

fabrikam-workflow 和 到 fabrikam-ingestion 服務匯流排 佇列的箭號會顯示訊息的傳送和接收位置。 您無法從圖表中判斷哪個服務正在傳送訊息和接收訊息。 箭號只會顯示這兩個服務都在呼叫 服務匯流排。 但有關要傳送哪些服務以及接收哪些服務的相關資訊可在詳細資料中取得:

Screenshot that shows the application map details.

因為每個呼叫都包含作業識別碼,因此您也可以檢視單一交易的端對端步驟,包括計時資訊和每個步驟的 HTTP 呼叫。 以下是其中一個這類交易的視覺效果:

Screenshot that shows an end-to-end transaction.

此視覺效果顯示從擷取服務到佇列、從佇列到工作流程服務,以及從工作流程服務到其他後端服務的步驟。 最後一個步驟是將服務匯流排訊息標示為已完成的工作流程服務。

此範例顯示對失敗之後端服務的呼叫:

Screenshot that shows an application map with errors.

此地圖顯示對無人機排程器服務的呼叫在查詢期間失敗的一小部分(36%)。 端對端交易檢視會顯示 HTTP PUT 要求傳送至服務時,會發生例外狀況:

Screenshot of the end-to-end transaction. It shows that an exception occurs when an HTTP PUT request is sent to the service.

如果您進一步鑽研,您可以看到例外狀況是通訊端例外狀況:「沒有這類裝置或位址」。

Fabrikam.Workflow.Service.Services.BackendServiceCallFailedException: 
No such device or address 
---u003e System.Net.Http.HttpRequestException: No such device or address 
---u003e System.Net.Sockets.SocketException: No such device or address

此例外狀況表示無法連線到後端服務。 此時,您可以使用 kubectl 來檢視部署組態。 在此範例中,由於 Kubernetes 組態檔發生錯誤,因此無法解析服務主機名。 Kubernetes 檔中的偵錯服務 一文 有診斷這類錯誤的秘訣。

以下是一些常見的錯誤原因:

  • 程式碼錯誤。 這些 Bug 可能會顯示為:
    • 例外狀況。 查看 Application Insights 記錄以檢視例外狀況詳細資料。
    • 進程失敗。 查看容器和 Pod 狀態,以及檢視容器記錄或 Application Insights 追蹤。
    • HTTP 5 xx 錯誤。
  • 資源耗盡:
    • 尋找節流 (HTTP 429) 或要求逾時。
    • 檢查 CPU、記憶體和磁片的容器計量。
    • 查看容器和 Pod 資源限制的設定。
  • 服務探索。 檢查 Kubernetes 服務組態和埠對應。
  • API 不符。 尋找 HTTP 400 錯誤。 如果 API 已設定版本,請查看所呼叫的版本。
  • 提取容器映射時發生錯誤。 查看 Pod 規格。 也請確定叢集已獲授權從容器登錄提取。
  • RBAC 問題。

下一步

深入瞭解 Azure 監視器中支援在 AKS 上監視應用程式的功能: