Prometheus 遠端寫入 1.0 規範

  • 版本: 1.0
  • 狀態: 已釋出
  • 日期: 2023 年 4 月

本文件旨在定義和標準化現有已廣泛且自然採納的協議的 API、資料格式、協議和語義,而非提出任何新內容。

遠端寫入規範旨在記錄 Prometheus 和相容 Prometheus 遠端寫入的代理如何向 Prometheus 或相容 Prometheus 遠端寫入的接收器傳送資料的標準。

本文件中的關鍵詞“必須 (MUST)”、“不得 (MUST NOT)”、“要求 (REQUIRED)”、“應當 (SHALL)”、“不應當 (SHALL NOT)”、“應該 (SHOULD)”、“不應該 (SHOULD NOT)”、“推薦 (RECOMMENDED)”、“可以 (MAY)”和“可選 (OPTIONAL)”應按照 RFC 2119  中的描述進行解釋。

注意本規範有一個 2.0 版本可用,請參見此處

簡介

背景

遠端寫入協議旨在實現樣本從傳送方到接收方的即時可靠傳播,而不會丟失。

遠端寫入協議被設計為無狀態的;嚴格來說,訊息之間沒有通訊。因此,該協議不被認為是“流式傳輸”。為了實現流式傳輸效果,應該使用例如 HTTP/1.1 或 HTTP/2 透過同一連線傳送多個訊息。曾考慮過 gRPC 等“花哨”技術,但當時它們並未被廣泛採用,而且將 gRPC 服務暴露在 AWS EC2 ELB 等負載均衡器後面透過網際網路訪問也頗具挑戰。

遠端寫入協議支援批次處理,例如在單個請求中傳送不同序列的多個樣本。不期望同一序列的多個樣本通常會在同一請求中傳送,儘管協議支援這一點。

遠端寫入協議不旨在用於應用程式向相容 Prometheus 遠端寫入的接收器推送指標。它旨在由相容 Prometheus 遠端寫入的傳送器抓取已埋點應用程式或匯出器,並將遠端寫入訊息傳送到伺服器。

測試套件位於 https://github.com/prometheus/compliance/tree/main/remotewrite/sender 

術語表

為本文件之目的,必須遵循以下定義:

  • “傳送方 (Sender)”指傳送 Prometheus 遠端寫入資料的一方。
  • “接收方 (Receiver)”指接收 Prometheus 遠端寫入資料的一方。
  • “樣本 (Sample)”是 (時間戳, 值) 對。
  • “標籤 (Label)”是 (鍵, 值) 對。
  • “時間序列 (Series)”是一系列樣本,由一組唯一的標籤標識。

定義

協議

遠端寫入協議必須由具有以下簽名的 RPC 組成

func Send(WriteRequest)

message WriteRequest {
  repeated TimeSeries timeseries = 1;
  // Cortex uses this field to determine the source of the write request.
  // We reserve it to avoid any compatibility issues.
  reserved  2;

  // Prometheus uses this field to send metadata, but this is
  // omitted from v1 of the spec as it is experimental.
  reserved  3;
}

message TimeSeries {
  repeated Label labels   = 1;
  repeated Sample samples = 2;
}

message Label {
  string name  = 1;
  string value = 2;
}

message Sample {
  double value    = 1;
  int64 timestamp = 2;
}

遠端寫入傳送方必須將寫入請求編碼在 HTTP POST 請求體中,並透過 HTTP 在提供的 URL 路徑上將其傳送給接收方。接收方可以指定任何 HTTP URL 路徑來接收指標。

時間戳必須是自 Unix 紀元以來的毫秒數,型別為 int64。值必須是 float64。

HTTP 請求必須傳送以下頭部:

  • Content-Encoding: snappy
  • Content-Type: application/x-protobuf
  • User-Agent: <傳送方名稱與版本>
  • X-Prometheus-Remote-Write-Version: 0.1.0

客戶端可以允許使用者傳送自定義 HTTP 頭部;它們不得允許使用者以傳送保留頭部的方式進行配置。更多資訊請參見 https://github.com/prometheus/prometheus/pull/8416 

HTTP POST 請求體中的遠端寫入請求必須使用 Google 的 Snappy  進行壓縮。必須使用塊格式——不得使用幀格式。

遠端寫入請求必須使用 Google Protobuf 3 編碼,並且必須使用上述定義的 schema。請注意,Prometheus 實現  使用 gogoproto 最佳化 ——對於非 Golang 編寫的接收器,gogoproto 型別可以替換為行級等效型別。

遠端寫入接收器的響應體應該為空;客戶端必須忽略響應體。響應體保留供將來使用。

向後和向前相容性

該協議遵循 語義化版本控制 2.0 :任何 1.x 相容的接收器必須能夠讀取任何 1.x 相容的傳送器,依此類推。破壞性/向後不相容的更改將導致規範的 2.x 版本。

Proto 格式本身在某些方面是向前/向後相容的

  • 從 proto 中移除欄位將意味著主版本號的提升。
  • 新增(可選)欄位將是次版本號的提升。

協商

  • 傳送方必須在頭部中傳送版本號。
  • 接收方可以在響應頭部中返回它們支援的最高版本號("X-Prometheus-Remote-Write-Version")。
  • 希望以 >1.x 格式傳送的傳送方必須首先發送一個空的 1.x 請求,並檢視響應是否表明接收方支援其他版本。傳送方可以使用任何受支援的版本。如果響應中沒有版本頭部,傳送方必須假定僅支援 1.x 相容性。

標籤

每個樣本必須附帶完整的標籤集。此外,與樣本關聯的標籤集:

  • 應該包含一個 `__name__` 標籤。
  • 不得包含重複的標籤名稱。
  • 標籤名稱必須按字典序排序。
  • 不得包含任何空標籤名稱或值。

傳送方必須只發送有效的指標名稱、標籤名稱和標籤值

  • 指標名稱必須符合正則表示式 `[a-zA-Z_:]([a-zA-Z0-9_:])*`。
  • 標籤名稱必須符合正則表示式 `[a-zA-Z_]([a-zA-Z0-9_])*`。
  • 標籤值可以是任何 UTF-8 字元序列。

接收方可以對標籤的數量和長度施加限制,但這將是接收方特定的,並且超出本文件的範圍。

以 "__" 開頭的標籤名稱保留用於系統使用,不應該使用,請參閱 Prometheus 資料模型

遠端寫入接收器可以接收包含無效樣本的寫入請求中的有效樣本。對於包含任何無效樣本的寫入請求,接收器必須返回 HTTP 400 狀態碼("Bad Request")。接收器應該在響應體中提供人類可讀的錯誤訊息。傳送方不得嘗試解釋錯誤訊息,並且應該按原樣記錄。

排序

相容 Prometheus 遠端寫入的傳送方必須按時間戳順序傳送任何給定時間序列的樣本。相容 Prometheus 遠端寫入的傳送方可以並行傳送不同時間序列的多個請求。

重試與退避

相容 Prometheus 遠端寫入的傳送方必須在收到 HTTP 5xx 響應時重試寫入請求,並且必須使用退避演算法以防止伺服器過載。除了 429 之外,它們不得在 HTTP 2xx 和 4xx 響應時重試寫入請求。它們可以重試 HTTP 429 響應,如果伺服器無法跟上,這可能導致傳送方“落後”。這樣做是為了確保在伺服器端錯誤時資料不會丟失,並在客戶端錯誤時仍能取得進展。

相容 Prometheus 遠端寫入的接收器在寫入成功時必須返回 HTTP 2xx 狀態碼。當寫入失敗且應該重試時,它們必須返回 HTTP 5xx 狀態碼。當請求無效、永遠無法成功且不應重試時,它們必須返回 HTTP 4xx 狀態碼。

過期標記

相容 Prometheus 遠端寫入的傳送方必須在時間序列不再追加時傳送過期標記。

過期標記必須由特殊的 NaN 值 0x7ff0000000000002 表示。此值不得用於其他情況。

通常,傳送方可以使用以下技術檢測何時不再向時間序列追加資料:

  1. 透過服務發現,檢測到暴露該序列的目標已消失
  2. 注意到在連續抓取之間目標不再暴露該時間序列
  3. 未能抓取最初暴露時間序列的目標
  4. 跟蹤記錄規則和告警規則的配置和評估

超出範圍

本文件不打算解釋一個完全相容 Prometheus 的監控系統所需的所有功能。特別是,以下領域超出了本規範第一個版本的範圍:

“up”指標 “up”指標的定義和語義超出了遠端寫入協議的範圍,應單獨記錄。

HTTP 路徑 HTTP 處理程式的路徑可以是任何內容——並且必須由傳送方提供。通常我們期望在配置中指定完整的 URL。

永續性 建議相容 Prometheus 遠端寫入的傳送方在接收器發生中斷時應持久化緩衝樣本資料。

認證與加密 由於遠端寫入使用 HTTP,我們認為認證與加密是傳輸層問題。傳送方和接收方應該支援所有常見的認證方式(基本認證、TLS 等),並且可以自由新增潛在的自定義認證選項。不應假定 Prometheus 遠端寫入傳送方和最終代理支援自定義認證,但我們將努力在可行的情況下支援常見和廣泛使用的認證協議。

遠端讀取 這是一個獨立的介面,已經經歷了一些迭代,並且使用範圍較小。

分片 Prometheus 中用於遠端寫入並行化的當前分片方案很大程度上是實現細節,不屬於規範的一部分。當傳送方確實實現並行化時,它們必須保留每個時間序列的樣本順序。

回填 規範沒有限制可推送的時間序列的“年齡”,但伺服器/實現可能會存在特定約束。

限制 標籤的數量和長度、批次大小等的限制超出了本文件的範圍,但預計實現會施加合理的限制。

基於推送的 Prometheus 應用程式向相容 Prometheus 遠端寫入的接收器推送指標並非本系統的設計目標,應在單獨的文件中探討。

標籤 每個時間序列可以包含“job”和/或“instance”標籤,因為這些通常由傳送方中的服務發現新增。這些並非強制性的。

未來計劃

本節包含一些推測性的計劃,它們不被認為是協議規範的一部分,但為了完整性在此提及。

事務性 Prometheus 旨在實現“事務性”——即永不將部分抓取的目標暴露給查詢。我們打算在遠端寫入方面也這樣做——例如,未來我們希望“對齊”遠端寫入與抓取,也許透過在一個遠端寫入請求中傳送單個抓取的所有樣本、元資料和例項。這尚待設計。

元資料和例項 與上述一致,我們還隨抓取的樣本傳送元資料(型別資訊、幫助文字)和例項。我們計劃將其打包在一個遠端寫入請求中——未來的規範版本可能會堅持這一點。Prometheus 目前對傳送元資料和例項有實驗性支援。

最佳化 我們希望研究各種最佳化措施,透過消除標籤名稱和值的重複來減小訊息大小。

相容的傳送方和接收方

本規範旨在描述以下元件如何互動(截至 2023 年 4 月):

常見問題

為什麼不使用 gRPC? 有趣的是,我們最初使用了 gRPC,但在 2016 年,由於很難讓它們透過 ELB,我們轉而使用基於 HTTP 的 Protobuf:https://github.com/prometheus/prometheus/issues/1982 

為什麼不流式傳輸 Protobuf 訊息? 如果使用持久的 HTTP/1.1 連線,它們非常接近流式傳輸……當然,頭部必須重新發送,但這確實比新的 TCP 設定成本更低。

為什麼我們按順序傳送樣本? 順序約束來自於我們在 Prometheus 中用於時間序列資料的編碼,其實現是僅追加的。可以透過緩衝樣本並在編碼前重新排序等方式來消除此約束。我們可以在協議的未來版本中進行研究。

如何在有順序約束的情況下並行化請求? 樣本必須針對給定的時間序列按順序排列。只要是針對不同的時間序列,遠端寫入請求就可以並行傳送。在 Prometheus 中,我們透過標籤將樣本分片到獨立的佇列中,然後每個佇列中的寫入按順序進行。這保證了同一時間序列的樣本按順序傳遞,但不同時間序列的樣本並行傳送——並且不同時間序列之間可能會“亂序”。

我們認為這是必要的,因為即使接收方能夠支援亂序樣本,我們也不能讓代理亂序傳送,因為那樣它們將無法傳送到 Prometheus、Cortex 和 Thanos。我們這樣做是為了確保生態系統的完整性,並防止社群因“能夠寫入 Prometheus 的 Prometheus 代理”和“不能寫入的代理”而產生混淆/分歧。

本頁內容