2022 年 9 月 5 日

使用 OpenTelemetry 與 Prisma 追蹤監控您的伺服器

追蹤是一個強大的工具,可讓您分析應用程式的效能並找出瓶頸。本教學課程將教您追蹤的核心概念,以及如何使用 OpenTelemetryPrisma 的追蹤功能將追蹤整合到您的應用程式中。

Monitor Your Server with Tracing Using OpenTelemetry & Prisma

目錄

簡介

在本教學課程中,您將學習如何將追蹤整合到使用 Prisma 和 Express 建立的現有 Web 應用程式中。您將使用 OpenTelemetry 實作追蹤,OpenTelemetry 是一個供應商中立的標準,用於收集追蹤和其他遙測資料(例如,日誌、指標等)。

一開始,您將為 HTTP 端點建立手動追蹤並將其列印到主控台。然後,您將學習如何使用 Jaeger 可視化您的追蹤。您還將學習如何使用 Prisma 的追蹤功能自動產生資料庫查詢的追蹤。最後,您將了解自動檢測以及使用追蹤時的效能考量。

什麼是追蹤?

追蹤是一個可觀察性工具,用於記錄請求在應用程式中傳播時所採取的路徑。追蹤可協助您連結系統為回應任何特定請求而執行的活動。追蹤還提供有關這些活動的時序資訊(例如,開始時間、持續時間等)。

單一追蹤可讓您了解使用者或應用程式發出請求時發生的情況。每個追蹤由一個或多個 span 組成,其中包含有關請求期間發生的單一步驟或任務的資訊。

使用追蹤工具(例如 Jaeger),追蹤可以視覺化為如下所示的圖表

Visualization of a single trace

單一 span 可以有多個子 span,代表父 span 期間發生的子任務。例如,在上圖中,PRISMA QUERY span 有一個名為 PRISMA ENGINE 的子 span。最上層的 span 稱為根 span,代表從開始到結束的整個追蹤。在上圖中,GET /ENDPOINT 是根 span。

追蹤是更深入了解和可見系統的絕佳方法。它可讓您精確地找出影響應用程式的錯誤和效能瓶頸。追蹤對於偵錯分散式系統特別有用,在分散式系統中,每個請求都可能涉及多個服務,並且特定問題可能難以在本地重現。

注意: 追蹤通常與指標結合使用,以獲得更好的系統可觀察性。若要深入了解指標,請查看我們的指標教學課程

您將使用的技術

在本教學課程中,您將使用下列工具

先決條件

假設知識

這是一個適合初學者的教學課程。但是,本教學課程假設

  • JavaScript 或 TypeScript 的基本知識(較佳)
  • 後端 Web 開發的基本知識

注意:本教學課程假設您事先不具備有關追蹤和可觀察性的知識。

開發環境

若要遵循本教學課程,您需要

  • ... 安裝 Node.js
  • ... 安裝 DockerDocker Compose
  • ... 選擇性安裝 Prisma VS Code 擴充功能。Prisma VS Code 擴充功能為 Prisma 新增了一些非常棒的 IntelliSense 和語法醒目提示。
  • ... 選擇性存取 Unix shell(例如 Linux 和 macOS 中的終端機/shell)以執行本系列中提供的命令。

如果您沒有 Unix shell(例如,您使用的是 Windows 機器),您仍然可以繼續操作,但 shell 命令可能需要針對您的機器進行修改。

複製儲存庫

您將需要一個 Web 應用程式來示範追蹤。您可以使用我們為本教學課程建置的現有 Express Web 應用程式。

若要開始使用,請執行下列動作

  1. 複製儲存庫
  1. 導覽至複製的目錄
  1. 安裝依賴項
  1. prisma/migrations 目錄套用資料庫遷移

注意:此命令也會產生 Prisma Client 並為資料庫植入種子資料。

  1. 啟動專案

注意:您應該在開發應用程式時保持伺服器執行。每當程式碼發生變更時,dev 指令碼都應該重新啟動伺服器。

應用程式只有一個端點:https://127.0.0.1:4000/users/random。此端點將從資料庫傳回 10 個使用者的隨機樣本。透過前往上述 URL 或執行下列命令來測試端點

專案結構與檔案

您複製的儲存庫具有下列結構

此儲存庫中值得注意的檔案和目錄包括

  • prisma
    • schema.prisma:定義資料庫結構描述。
    • migrations:包含資料庫遷移歷程記錄。
    • seed.ts:包含用於為開發資料庫植入虛擬資料的指令碼。
    • dev.db:儲存 SQLite 資料庫的狀態。
  • server.ts:具有 GET /users/random 端點的 Express 伺服器。
  • tsconfig.json & package.json:組態檔。

將追蹤整合到您的應用程式中

您的 Express 應用程式已實作所有核心「業務邏輯」(即傳回 10 個隨機使用者)。為了衡量效能並改善應用程式的可觀察性,您將整合追蹤。

在本節中,您將學習如何初始化追蹤並手動建立追蹤。

初始化追蹤

您將使用 OpenTelemetry 追蹤實作追蹤。OpenTelemetry 提供跨各種平台和語言相容的開放原始碼實作。此外,它還隨附用於實作追蹤的程式庫和 SDK。

首先安裝下列 OpenTelemetry 套件以開始追蹤

這些套件包含 OpenTelemetry 追蹤的 Node.js 實作。

現在,建立新的 tracing.ts 檔案以初始化追蹤

tracing.ts 內,如下所示初始化追蹤

initializeTracing 函數執行幾項操作

  1. 它初始化一個 追蹤器提供者,用於建立 追蹤器。追蹤器會在您的應用程式內建立追蹤/span。
  2. 它定義一個 追蹤匯出器,並將其新增至您的提供者。追蹤匯出器會將追蹤傳送至各種目的地。在此案例中,ConsoleSpanExporter 會將追蹤列印到主控台。
  3. 它透過呼叫 .register() 函數來註冊提供者,以便與 OpenTelemetry API 搭配使用。
  4. 最後,它會建立並傳回一個追蹤器,其名稱會以引數形式傳遞至函數。

現在,在現有的 server.ts 中匯入並呼叫 initializeTracing

現在您可以開始建立您的第一個追蹤了!

建立您的第一個追蹤

在上一節中,您初始化了追蹤並將追蹤器匯入到您的伺服器。現在,您可以使用 tracer 物件在伺服器內建立 span。首先,您將建立一個封裝 GET /users/random 請求的追蹤。如下所示更新請求處理常式定義

在這裡,您正在使用 startActiveSpan() 建立新的 span,並將所有請求處理常式邏輯封閉在它提供的回呼函數內。回呼函數隨附 span 物件的參考,您已將其命名為 requestSpan。您可以使用它來修改 span 或將屬性新增至 span。在此程式碼中,您根據請求的結果,將名為 http.status 的屬性設定為 span。最後,在請求處理完成後,您會結束 span。

若要查看您新建立的 span,請前往 https://127.0.0.1:4000/users/random。或者,您可以在終端機內執行下列命令

前往正在執行 Express 伺服器的終端機視窗。您應該會看到類似於下列物件列印到主控台

此物件代表您剛建立的 span。這裡一些值得注意的屬性包括

  • id 代表此特定 span 的唯一識別碼。
  • traceId 代表特定追蹤的唯一識別碼。特定追蹤中的所有 span 都將具有相同的 traceId。目前,您的追蹤僅包含單一 span。
  • parentId 是父 span 的 id。在此案例中,它是 undefined,因為根 span 沒有父 span。
  • name 代表 span 的名稱。您在建立 span 時指定了此名稱。
  • timestamp 是代表 span 建立時間的 UNIX 時間戳記。
  • duration 是 span 的持續時間,以微秒為單位。

使用 Jaeger 可視化追蹤

目前,您正在主控台中檢視追蹤。雖然這對於單一追蹤來說尚可管理,但對於大量追蹤來說並不是非常有用。若要更了解您的追蹤,您將需要一些可以視覺化追蹤的追蹤解決方案。在本教學課程中,您將使用 Jaeger 來達到此目的。

設定 Jaeger

您可以使用兩種方式設定 Jaeger

在本教學課程中,您將使用 Docker Compose 來執行 Jaeger 的 Docker 映像。首先,建立新的 docker-compose.yml 檔案

在檔案內定義下列服務

執行此映像將在 Docker 容器內設定並初始化 Jaeger 的所有必要元件。若要執行 Jaeger,請開啟新的終端機視窗,並在專案的主要資料夾中執行下列命令

注意:如果您關閉執行 Docker 容器的終端機視窗,也會停止容器。如果您在命令結尾新增 -d 選項,即可避免這種情況,例如:docker-compose up -d

如果一切順利,您應該能夠在 https://127.0.0.1:16686 存取 Jaeger。

Jaeger user interface

由於您的應用程式尚未將追蹤傳送至 Jaeger,因此 Jaeger UI 將會是空的。

新增 Jaeger 追蹤匯出器

若要在 Jaeger 中查看您的追蹤,您需要設定新的追蹤匯出器,將追蹤從您的應用程式傳送至 Jaeger(而不是僅將其列印到主控台)。

首先,在您的專案中安裝匯出器套件

現在將匯出器新增至 tracing.ts

在這裡,您初始化了新的 JaegerExporter 並將其新增至您的追蹤器提供者。JaegerExporter 建構函式中的 endpoint 屬性指向 Jaeger 正在接聽追蹤資料的位置。您也移除了主控台匯出器,因為不再需要它。

您現在應該能夠在 Jaeger 中看到您的追蹤了。若要查看您的第一個追蹤

  1. 再次查詢 GET /users/random 端點 (curl https://127.0.0.1:4000/users/random)。
  2. 前往 https://127.0.0.1:16686
  3. 在左側的搜尋標籤中,在服務下拉式清單中,選取express-server
  4. 搜尋標籤的底部附近,按一下尋找追蹤
  5. 您現在應該會看到追蹤清單。按一下清單中的第一個追蹤。
  6. 您將看到追蹤的詳細視圖。應該會有一個名為 GET /users/random 的單一 span。按一下 span 以取得更多資訊。
  7. 您應該能夠看到有關追蹤的各種資訊,例如持續時間開始時間。您也應該會看到多個標籤,其中一個是您手動設定的 (http.status)。

Viewing traces inside Jaeger

為您的 Prisma 查詢新增追蹤

在本節中,您將學習如何追蹤您的資料庫查詢。一開始,您將透過自行建立 span 來手動執行此操作。即使使用 Prisma 已不再需要手動追蹤,但實作手動追蹤將讓您更了解追蹤的運作方式。

然後,您將使用 Prisma 中的新追蹤功能來自動執行相同的操作。

手動追蹤您的 Prisma 查詢

若要手動追蹤您的 Prisma 查詢,您必須將每個查詢包裝在 span 中。您可以透過將下列程式碼新增至您的 server.ts 檔案來執行此操作

您已為 Prisma 查詢建立一個名為 prisma.user.findmany 的新 span。您也對 users 變數的宣告方式進行了一些變更,使其與其餘程式碼保持一致。

再次查詢 GET /users/random 端點 (curl https://127.0.0.1:4000/users/random) 並檢視 Jaeger 中新產生的追蹤,以測試新的 span。

Child span visualized in Jaeger

您應該會看到產生的追蹤具有一個名為 prisma.user.findmany 的新子 span,巢狀在父 GET /users/random span 下方。現在,您可以查看請求中花費在執行 Prisma 查詢的時間長度。

手動與自動檢測

到目前為止,您已學習如何設定追蹤,以及如何為您的應用程式手動產生追蹤和 span。像這樣手動定義 span 稱為手動檢測。手動檢測讓您可以完全控制應用程式的追蹤方式,但是,它有一些缺點

  • 手動追蹤您的應用程式非常耗時,尤其是當您的應用程式很大時。
  • 並非總是能夠正確地手動檢測協力廠商程式庫。例如,無法使用手動檢測來追蹤 Prisma 內部元件的執行。
  • 它可能會導致錯誤和問題(例如,不正確的錯誤處理、損壞的 span 等),因為它涉及手動撰寫大量程式碼。

幸運的是,許多框架和程式庫都提供自動檢測,可讓您自動產生這些元件的追蹤。自動檢測幾乎不需要變更程式碼,設定速度非常快,並且可以提供現成的基本遙測。

請務必注意,自動和手動檢測並非互斥。同時使用這兩種技術可能很有益。自動檢測可以提供良好的基準遙測,並在高覆蓋率下涵蓋所有端點。然後可以新增手動檢測,以進行特定的細微追蹤和自訂指標/中繼資料。

設定 Prisma 的自動檢測

本節將教您如何使用新的追蹤功能設定 Prisma 的自動檢測。若要開始使用,請在 schema.prisma 檔案的產生器區塊中啟用追蹤功能標幟

注意:追蹤目前是預覽功能。這就是為什麼您必須先新增 tracing 功能標幟才能使用追蹤。

現在,重新產生 Prisma Client

若要執行自動檢測,您還需要使用 npm 安裝兩個新套件

需要這些套件的原因如下

  • 需要 @opentelemetry/instrumentation 才能設定自動檢測。
  • @prisma/instrumentation 為 Prisma Client 提供自動檢測。

根據 OpenTelemetry 術語,受檢測程式庫是收集追蹤的程式庫或套件。另一方面,檢測程式庫是為特定受檢測程式庫產生追蹤的程式庫。在此案例中,Prisma Client 是受檢測程式庫,而 @prisma/instrumentation 是檢測程式庫。

現在您需要向 OpenTelemetry 註冊 Prisma 檢測。若要執行此操作,請將下列程式碼新增至您的 tracing.ts 檔案

registerInstrumentations 呼叫採用兩個引數

  • instrumentations 接受您要註冊的所有檢測程式庫的陣列。
  • tracerProvider 接受您的追蹤器的追蹤器提供者。

由於您正在設定自動檢測,因此不再需要手動為 Prisma 查詢建立 span。透過移除 Prisma 查詢的手動 span 來更新 server.ts

使用自動檢測時,初始化追蹤的順序很重要。您需要在匯入受檢測程式庫之前設定追蹤並註冊檢測。在此案例中,initializeTracing 呼叫必須在 PrismaClientimport 陳述式之前。

再次向 GET /users/random 端點發出請求,並查看 Jaeger 中產生的追蹤。

Visualization of automatic instrumentation with Prisma

這次,相同的 Prisma 查詢會產生多個 span,提供有關查詢的更精細資訊。啟用自動檢測後,您新增至應用程式的任何其他查詢也會自動產生追蹤。

注意: 若要深入了解 Prisma 產生的 span,請參閱追蹤文件的追蹤輸出章節

設定 Express 的自動檢測

目前,您正在透過手動建立 span 來追蹤您的端點。就像 Prisma 查詢一樣,隨著端點數量的增加,手動追蹤將變得難以管理。若要解決此問題,您也可以設定 Express 的自動檢測。

首先安裝下列檢測程式庫

tracing.ts 內註冊這兩個新的檢測程式庫

最後,移除 server.tsGET /users/random 端點的手動 span

GET /users/random 端點發出請求,並查看 Jaeger 中產生的追蹤。

Visualization of automatic instrumentation with Express and Prisma

您應該會看到更精細的 span,顯示請求通過程式碼的不同步驟。特別是,您應該會看到由 ExpressInstrumentation 程式庫產生新的 span,這些 span 顯示請求通過各種 Express 中介軟體和 GET /users/random 請求處理常式。

注意:如需可用檢測程式庫的清單,請查看OpenTelemetry 登錄檔

減少追蹤的效能影響

如果您的應用程式將大量 span 傳送至收集器(例如 Jaeger),則可能會對應用程式的效能產生重大影響。這在您的開發環境中通常不是問題,但在生產環境中可能會是問題。您可以採取一些步驟來減輕此問題。

批量傳送追蹤

目前,您正在使用 SimpleSpanProcessor 傳送追蹤。這效率很低,因為它一次傳送一個 span。您可以改為使用 BatchSpanProcessor 批量傳送 span。

在您的 tracing.ts 檔案中進行下列變更,以在生產環境中使用 BatchSpanProcessor

請注意,您仍然在開發環境中使用 SimpleSpanProcessor,在開發環境中,最佳化效能不是主要考量。這可確保追蹤在開發環境中產生後立即顯示。

透過取樣傳送更少的 span

機率取樣是一種技術,可讓 OpenTelemetry 追蹤使用者透過使用隨機取樣技術來降低 span 收集效能成本。使用此技術,您可以減少傳送至收集器的 span 數量,同時仍然可以很好地表示應用程式中發生的情況。

更新 tracing.ts 以使用機率取樣

就像批次處理一樣,您僅在生產環境中加入機率取樣。

摘要與結論

恭喜!🎉

在本教學課程中,您學習了

  • 什麼是追蹤,以及為什麼您應該使用它。
  • 什麼是 OpenTelemetry,以及它與追蹤有何關係。
  • 如何使用 Jaeger 可視化追蹤。
  • 如何將追蹤整合到現有的 Web 應用程式中。
  • 如何使用自動檢測程式庫來改善程式碼可觀察性。
  • 如何在生產環境中減少追蹤的效能影響。

您可以在 GitHub 上找到此專案的原始程式碼。如果您發現問題,請隨時在儲存庫中提出問題或提交 PR。您也可以直接透過 Twitter 與我聯繫。

不要錯過下一篇文章!

訂閱 Prisma 電子報