Prometheus Remote-Write 2.0 仕様 [実験的]

  • バージョン: 2.0-rc.3
  • ステータス: 実験的
  • 日付: 2024年5月

Remote-Write 仕様は、一般的に Prometheus および Prometheus Remote-Write 互換送信者が Prometheus または Prometheus Remote-Write 互換受信者にデータを送信するための標準を文書化することを目的としています。

このドキュメントは、プロトコルとセマンティクスに軽微な変更を加えた Prometheus Remote-Write API の第 2 版を定義することを目的としています。第 2 版では、より多くのユースケースと、パフォーマンスとコスト削減のメリットを活かした広範な採用を可能にする新機能を備えた新しい Protobuf メッセージが追加されます。また、第 2 版では、1.0 Remote-Write 仕様の以前の Protobuf メッセージは非推奨となり、信頼性のために必須の X-Prometheus-Remote-Write-*-Written HTTP レスポンスヘッダーが追加されます。最後に、この仕様では、既存の基本的なコンテンツネゴシエーションリクエストヘッダーを使用して、互換性のある送信者と受信者(単一のエンドポイントでも)を実装する方法の概要を示します。必要に応じて、将来のマイナーバージョンで、より高度な自動コンテンツネゴシエーションメカニズムが導入される可能性があります。2.0 仕様の根拠については、正式な提案を参照してください。

このドキュメントでは、「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」、「OPTIONAL」というキーワードは、RFC 2119で説明されているとおりに解釈されます。

これは Remote-Write 2.0 仕様のリリース候補です。これは、この仕様が現在実験的な状態にあることを意味します。重大な変更は予想されませんが、初期導入者のフィードバックに基づいて必要に応じて互換性を壊す権利を留保します。潜在的なフィードバック、質問、提案は、オープンな提案の PRにコメントとして追加してください。

はじめに

背景

Remote-Write プロトコルは、送信者から受信者へ、損失なくリアルタイムでサンプルを確実に伝搬できるように設計されています。

Remote-Write プロトコルはステートレスになるように設計されています。メッセージ間の通信は厳密に行われません。そのため、このプロトコルは「ストリーミング」とは見なされません。ストリーミング効果を実現するには、HTTP/1.1 または HTTP/2 などの同じ接続を介して複数のメッセージを送信する必要があります。gRPC のような「高度な」テクノロジーも検討されましたが、当時はまだ広く採用されておらず、AWS EC2 ELB のようなロードバランサーの後ろで gRPC サービスをインターネットに公開するのは困難でした。

Remote-Write プロトコルには、バッチ処理の機会があります。例えば、単一のリクエストで異なるシリーズの複数のサンプルを送信するなどです。同じシリーズの複数のサンプルが同じリクエストで頻繁に送信されることは想定されていませんが、Protobuf メッセージにはそのサポートがあります。

テストスイートは https://github.com/prometheus/compliance/tree/main/remote_write_sender で見つけることができます。Remote Write 2.0 互換性のコンプライアンステストはまだ 進行中です。

用語集

このドキュメントでは、以下の定義に従います。

  • Remote-Write は、この Prometheus プロトコルの名前です。
  • Protocol は、クライアントとサーバーがメトリックを転送できるようにする通信仕様です。
  • Protobuf Message (または Proto Message) は、このプロトコルのデータ構造の コンテンツタイプ 定義を指します。仕様では Google Protocol Buffers ("protobuf") のみが使用されるため、スキーマは "proto" ファイル で定義され、単一の Protobuf "message" で表されます。
  • Wire Format は、ネットワーク上で転送されるデータの形式です。Remote-Write の場合、これは常に圧縮されたバイナリ protobuf フォーマットです。
  • Sender は、Remote-Write データを送信するものです。
  • Receiver は、Remote-Write データを受信(書き込み)するものです。Written の意味は Receiver 次第です。通常は受信したデータをデータベースに保存することを意味しますが、検証、分割、または拡張することもあります。
  • Written は、Receiver が受信し、受け入れたデータを指します。永続ストレージにインジェストしたか、WAL に書き込んだかなどは Receiver 次第です。唯一の違いは、Receiver が明示的にエラーレスポンスで拒否したのではなく、このデータを受け入れたということです。
  • Sample は、(タイムスタンプ、値) のペアです。
  • Histogram は、(タイムスタンプ、ヒストグラム値) のペアです。
  • Label は、(キー、値) のペアです。
  • Series は、一意のラベルセットによって識別されるサンプルのリストです。

定義

プロトコル

Remote-Write プロトコルは、リクエストボディを Google Protocol Buffers でシリアライズし、その後圧縮する RPC で構成されなければなりません。

protobuf シリアライゼーションは、以下のいずれかの Protobuf メッセージを使用しなければなりません。

  • Remote-Write 1.0 仕様で導入された prometheus.WriteRequest。2.0 時点では、このメッセージは非推奨です。互換性の理由でのみ使用されるべきです。送信者および受信者は prometheus.WriteRequest をサポートしない場合があります。
  • この仕様で導入され、下記で定義されている io.prometheus.write.v2.Request。送信者および受信者は、可能な場合はこのメッセージを使用すべきです。送信者および受信者は io.prometheus.write.v2.Request をサポートしなければなりません。

Protobuf Message はバイナリ Wire Format を使用しなければなりません。次に、Google の Snappy で圧縮しなければなりません。Snappy の ブロックフォーマット を使用しなければなりません - フレームフォーマット は使用してはなりません。

送信者は、シリアライズおよび圧縮された Protobuf Message を HTTP POST リクエストのボディに含め、Receiver に指定された URL パスで HTTP 経由で送信しなければなりません。Receiver は、メトリックを受信するための任意の HTTP URL パスを指定できます。

送信者は、HTTP リクエストと共に以下の予約済みヘッダーを送信しなければなりません。

  • Content-Encoding
  • Content-Type
  • X-Prometheus-Remote-Write-Version
  • User-Agent

送信者は、ユーザーがカスタム HTTP ヘッダーを追加できるようにしてもよいですが、予約済みヘッダーを送信するように設定できないようにしなければなりません。

Content-Encoding

Content-Encoding: <compression>

Content encoding リクエストヘッダーは、RFC 9110 に従わなければなりません。送信者は snappy 値を使用しなければなりません。受信者は snappy 圧縮をサポートしなければなりません。新しいオプションの圧縮アルゴリズムは、2.x 以降で提供される可能性があります。

Content-Type

Content-Type: application/x-protobuf
Content-Type: application/x-protobuf;proto=<fully qualified name>

Content type リクエストヘッダーは、RFC 9110 に従わなければなりません。送信者は、唯一のメディアタイプとして application/x-protobuf を使用しなければなりません。送信者は、上記の 2 つのいずれかに示された Protobuf Message の完全修飾名を示すために、ヘッダーの値に ;proto= パラメータを追加してもよいです。その結果、送信者は 3 つのサポートされているヘッダー値のいずれかを送信しなければなりません。

PRW 1.0 で導入され、prometheus.WriteRequest で識別される非推奨メッセージの場合

  • Content-Type: application/x-protobuf
  • Content-Type: application/x-protobuf;proto=prometheus.WriteRequest

PRW 2.0 で導入され、io.prometheus.write.v2.Request で識別されるメッセージの場合

  • Content-Type: application/x-protobuf;proto=io.prometheus.write.v2.Request

1.x 受信者と通信する場合、送信者は後方互換性のために Content-Type: application/x-protobuf を使用すべきです。それ以外の場合は、送信者は互換性のある最新の Remote-Write バージョン、例えば X-Prometheus-Remote-Write-Version: 2.0.0 を使用すべきです。より多くの Protobuf Message が 2.x 以降で提供される可能性があります。

受信者は、使用する Protobuf Message スキーマを識別するためにコンテンツタイプヘッダーを使用しなければなりません。誤ったスキーマの選択は、非決定論的な動作(例:破損)につながる可能性があります。

io.prometheus.write.v2.Request の予約フィールドのおかげで、Receiver が prometheus.WriteRequest で誤ったスキーマを誤って使用した場合、メッセージは空になります。これは一般的に、予期しないエラーを回避するための便宜のためですが、それに依存しないでください。将来の Protobuf Message ではこの機能がなくなる可能性があります。

X-Prometheus-Remote-Write-Version

X-Prometheus-Remote-Write-Version: <Remote-Write spec major and minor version>

1.x 受信者と通信する場合、送信者は後方互換性のために X-Prometheus-Remote-Write-Version: 0.1.0 を使用しなければなりません。それ以外の場合は、送信者は互換性のある最新の Remote-Write バージョン、例えば X-Prometheus-Remote-Write-Version: 2.0.0 を使用すべきです。

User-Agent

User-Agent: <name & version of the Sender>

送信者は、RFC 9110 User-Agent ヘッダーフォーマット に従うべきユーザーエージェントヘッダーを含めなければなりません。

レスポンス

受信したデータバッチを正常に書き込んだ Receiver は、成功した 2xx HTTP ステータスコード を返す必要があります。そのような成功の場合、Receiver からのレスポンスボディは空であるべきで、ステータスコードは 204 HTTP No Content であるべきです。送信者はレスポンスボディを無視しなければなりません。レスポンスボディは将来の使用のために予約されています。

Receiver が受信したデータの一部(例:Sample、Histogram、Exemplar)が正常に書き込まれなかった場合(部分書き込みまたは完全な書き込み拒否)、Receiver は 2xx HTTP ステータスコードを返してはなりません。そのような場合、Receiver はレスポンスボディに人間が読めるエラーメッセージを提供しなければなりません。Receiver のエラーは、拒否されたサンプルの量と理由に関する情報を含むべきです。送信者はエラーメッセージを解釈しようとしてはならず、そのままログに記録すべきです。

以下のサブセクションでは、ヘッダーとさまざまな書き込みエラーケースに関する Sender と Receiver のセマンティクスについて説明します。

必須の Written レスポンスヘッダー

コンテンツネゴシエーションが成功すると、Receiver は受信したデータバッチを処理(書き込み)します。各重要なデータ(現在 Sample、Histogram、Exemplar)について完了(成功または失敗)した後、Receiver は専用の HTTP X-Prometheus-Remote-Write-*-Written レスポンスヘッダーを、正常に書き込まれた要素の正確な数と共に送信しなければなりません。

各ヘッダー値は 64 ビット整数でなければなりません。ヘッダー名は以下の通りです。

X-Prometheus-Remote-Write-Samples-Written <count of all successfully written Samples>
X-Prometheus-Remote-Write-Histograms-Written <count of all successfully written Histogram samples>
X-Prometheus-Remote-Write-Exemplars-Written <count of all successfully written Exemplars>

2xx または 4xx ステータスコードを受信した場合、送信者は、欠落している X-Prometheus-Remote-Write-*-Written レスポンスヘッダーは、このカテゴリ(例:Sample)の要素が Receiver によって書き込まれなかった(カウント 0)ことを意味すると想定できます。送信者は、非推奨の prometheus.WriteRequest Protobuf Message を使用する際には、この機能を持たない 1.0 Receiver に当たるリスクがあるため、同じことを想定してはなりません。

送信者は、これらのヘッダーを使用して、データの一部が Receiver によって正常に書き込まれたかを確認できます。一般的なユースケース:

  • 部分書き込み失敗状況のより良い処理: 送信者は、より正確なクライアントインスツルメンテーションとエラー処理のためにこれらのヘッダーを使用できます。
  • 壊れた 1.0 Receiver 実装の検出: 送信者は、io.prometheus.write.v2.Request リクエストを使用してデータを送信し、2xx HTTP ステータスコードを受け取るが、Receiver からの X-Prometheus-Remote-Write-*-Written レスポンスヘッダーが none の場合に、415 HTTP Unsupported Media Type ステータスコードを想定すべきです。これは、Content-Type リクエストヘッダーをチェックしない 1.0 Receiver では一般的な問題です。io.prometheus.write.v2.Request ペイロードが prometheus.WriteRequest スキーマで誤ってデコードされると、結果は空になり、デコードエラーは発生しません。
  • その他の壊れた実装または問題の検出: 送信者は、これらのヘッダーを使用して、壊れた Sender および Receiver 実装またはその他の問題を検出できます。

送信者は、Remote Write レスポンスヘッダーから Receiver がどの Remote Write 仕様バージョンを実装しているかを想定してはなりません。

将来、より多くのエンティティまたはフィールドが追加され、確認する価値がある場合、さらに(オプションの)ヘッダーが追加される可能性があります。

部分書き込み

送信者は、単一のリクエストで複数のシリーズのサンプルを送信するために Remote-Write を使用すべきです。その結果、Receiver は、無効またはその他の理由で書き込まれなかったサンプルを含む書き込みリクエスト内で有効なサンプルを書き込む場合があります。これは部分書き込みケースを表します。そのような場合、Receiver は 無効なサンプル部分書き込み時のリトライ のセクションに従って、2xx 以外のステータスコードを返さなければなりません。

サポートされていないリクエストコンテンツ

Receiver が Sender から提供されたコンテンツタイプまたはエンコーディングをサポートしていない場合、Receiver は 415 HTTP Unsupported Media Type ステータスコードを返さなければなりません。

Sender は、後方互換性のために、上記理由から 1.x Receiver から 400 HTTP Bad Request を期待すべきです。

無効なサンプル

Receiver は、特定のメトリックタイプまたはサンプルをサポートしない場合があります(例:メタデータタイプが指定されていない、または作成タイムスタンプがないサンプルを拒否する Receiver もあれば、そのようなサンプルを受け入れる Receiver もあります)。どのサンプルが無効と見なされるかは Receiver 次第です。Receiver は、400 HTTP Bad Request ステータスコードを、部分的にリトライ可能な書き込みが発生しない限り、無効なサンプルを含む書き込みリクエストに対して返さなければなりません。

送信元は、書き込み操作が成功せず、再試行すべきでないことを受信元に示すために使用される 429 HTTP ステータスコード(429を除く)で再試行してはなりません。送信元は、受信元がサポートしているか確認するために、異なるコンテンツタイプまたはエンコーディングで 415 HTTP ステータスコードを再試行してもかまいません。

再試行とバックオフ

受信元は、サーバーが過負荷の状態を示すために、429 HTTP Too Many Requests ステータスコードを返すことができます。受信元は、次の書き込み試行の時刻を示すために、Retry-After ヘッダーを返すことができます。受信元は、内部サーバーエラーを表す 5xx HTTP ステータスコードを返すことができます。

送信元は 429 HTTP ステータスコードで再試行してもかまいません。送信元は 5xx HTTP で書き込み要求を再試行しなければなりません。送信元は、サーバーに過負荷をかけないように、バックオフアルゴリズムを使用しなければなりません。送信元は、次の再試行時間を推定するために、Retry-After レスポンスヘッダー を処理してもかまいません。

429 と 5xx の処理の違いは、受信元がリクエストボリュームに対処できない場合に送信元が「遅れ」をとる可能性のある状況、または受信元が可用性を保護するために送信元をレート制限することを選択する可能性があるためです。その結果、送信元は 429 で再試行しないオプションがあり、送信元側のエラー(例: トラフィックが多すぎる)が発生した場合に進捗を可能にしますが、受信元側のエラー(5xx)が発生した場合にデータが失われることはありません。

部分書き込みの再試行

受信元は、部分的な書き込み、または部分的に無効なサンプルの場合に、送信元がリクエスト全体を再試行することを期待して、5xx HTTP または 429 HTTP ステータスコードを返すことができます。その場合、受信元は冪等性をサポートしなければなりません。なぜなら送信元は同じリクエストで再試行する可能性があるからです。

下位互換性と上位互換性

このプロトコルはセマンティックバージョニング2.0に従います: 2.x 互換の受信元は、2.x 互換の送信元を読み取ることができる必要があります。同様に、その逆も同様です。破壊的または下位互換性のない変更は、仕様の 3.x バージョンにつながります。

Protobuf メッセージ(ワイヤフォーマット)自体は、いくつかの点で順次互換性があります。

  • Protobuf メッセージからフィールドを削除するには、メジャーバージョンの更新が必要です。
  • (オプションの)フィールドを追加するには、マイナーバージョンの更新で対応できます。

言い換えれば、将来の 2.x のマイナーバージョンでは、下位互換性がある限り(例: 受信元と送信元の両方にとってオプション)、io.prometheus.write.v2.Request に新しいオプションフィールド、新しい圧縮方式、Protobuf メッセージ、およびネゴシエーションメカニズムを追加する可能性があります。

2.x と 1.x の互換性

2.x プロトコルは、新しい必須の io.prometheus.write.v2.Request Protobuf メッセージを導入し、prometheus.WriteRequest を非推奨にすることで、1.x との互換性を壊しています。

2.x 送信元は、ユーザーが送信元が使用すべきコンテンツタイプを設定できるようにすることで、1.x 受信元をサポートしてもかまいません。2.x 送信元は、受信元が 415 HTTP ステータスコードを返した場合、異なるコンテンツタイプに自動的にフォールバックしてもかまいません。

Protobuf メッセージ

io.prometheus.write.v2.Request

io.prometheus.write.v2.Request は、Remote-Write 1.0 の prometheus.WriteRequest メッセージを置き換えて非推奨にする新しい Protobuf メッセージを参照します。

完全なスキーマと真実の源は、Prometheus リポジトリの prompb/io/prometheus/write/v2/types.proto にあります。gogo 依存関係とオプションは無視できます(最終的に削除される予定です)。これらはシリアル化された形式に影響しないため、仕様の一部ではありません。

新しい io.prometheus.write.v2.Request の簡略化されたバージョンを以下に示します。

// Request represents a request to write the given timeseries to a remote destination.
message Request {
  // Since Request supersedes 1.0 spec's prometheus.WriteRequest, we reserve the top-down message
  // for the deterministic interop between those two.
  // Generally it's not needed, because Receivers must use the Content-Type header, but we want to
  // be sympathetic to adopters with mistaken implementations and have deterministic error (empty
  // message if you use the wrong proto schema).
  reserved 1 to 3;

  // symbols contains a de-duplicated array of string elements used for various
  // items in a Request message, like labels and metadata items. For the sender's convenience
  // around empty values for optional fields like unit_ref, symbols array MUST start with
  // empty string.
  //
  // To decode each of the symbolized strings, referenced, by "ref(s)" suffix, you
  // need to lookup the actual string by index from symbols array. The order of
  // strings is up to the sender. The receiver should not assume any particular encoding.
  repeated string symbols = 4;
  // timeseries represents an array of distinct series with 0 or more samples.
  repeated TimeSeries timeseries = 5;
}

// TimeSeries represents a single series.
message TimeSeries {
  // labels_refs is a list of label name-value pair references, encoded
  // as indices to the Request.symbols array. This list's length is always
  // a multiple of two, and the underlying labels should be sorted lexicographically.
  //
  // Note that there might be multiple TimeSeries objects in the same
  // Requests with the same labels e.g. for different exemplars, metadata
  // or created timestamp.
  repeated uint32 labels_refs = 1;

  // Timeseries messages can either specify samples or (native) histogram samples
  // (histogram field), but not both. For a typical sender (real-time metric
  // streaming), in healthy cases, there will be only one sample or histogram.
  //
  // Samples and histograms are sorted by timestamp (older first).
  repeated Sample samples = 2;
  repeated Histogram histograms = 3;

  // exemplars represents an optional set of exemplars attached to this series' samples.
  repeated Exemplar exemplars = 4;

  // metadata represents the metadata associated with the given series' samples.
  Metadata metadata = 5;

  // created_timestamp represents an optional created timestamp associated with
  // this series' samples in ms format, typically for counter or histogram type
  // metrics. Created timestamp represents the time when the counter started
  // counting (sometimes referred to as start timestamp), which can increase
  // the accuracy of query results.
  //
  // Note that some receivers might require this and in return fail to
  // write such samples within the Request.
  //
  // For Go, see github.com/prometheus/prometheus/model/timestamp/timestamp.go
  // for conversion from/to time.Time to Prometheus timestamp.
  //
  // Note that the "optional" keyword is omitted due to
  // https://cloud.google.com/apis/design/design_patterns.md#optional_primitive_fields
  // Zero value means value not set. If you need to use exactly zero value for
  // the timestamp, use 1 millisecond before or after.
  int64 created_timestamp = 6;
}

// Exemplar represents additional information attached to some series' samples.
message Exemplar {
  // labels_refs is an optional list of label name-value pair references, encoded
  // as indices to the Request.symbols array. This list's len is always
  // a multiple of 2, and the underlying labels should be sorted lexicographically.
  // If the exemplar references a trace it should use the `trace_id` label name, as a best practice.
  repeated uint32 labels_refs = 1;
  // value represents an exact example value. This can be useful when the exemplar
  // is attached to a histogram, which only gives an estimated value through buckets.
  double value = 2;
  // timestamp represents the timestamp of the exemplar in ms.
  // For Go, see github.com/prometheus/prometheus/model/timestamp/timestamp.go
  // for conversion from/to time.Time to Prometheus timestamp.
  int64 timestamp = 3;
}

// Sample represents series sample.
message Sample {
  // value of the sample.
  double value = 1;
  // timestamp represents timestamp of the sample in ms.
  int64 timestamp = 2;
}

// Metadata represents the metadata associated with the given series' samples.
message Metadata {
  enum MetricType {
    METRIC_TYPE_UNSPECIFIED    = 0;
    METRIC_TYPE_COUNTER        = 1;
    METRIC_TYPE_GAUGE          = 2;
    METRIC_TYPE_HISTOGRAM      = 3;
    METRIC_TYPE_GAUGEHISTOGRAM = 4;
    METRIC_TYPE_SUMMARY        = 5;
    METRIC_TYPE_INFO           = 6;
    METRIC_TYPE_STATESET       = 7;
  }
  MetricType type = 1;
  // help_ref is a reference to the Request.symbols array representing help
  // text for the metric. Help is optional, reference should point to an empty string in
  // such a case.
  uint32 help_ref = 3;
  // unit_ref is a reference to the Request.symbols array representing a unit
  // for the metric. Unit is optional, reference should point to an empty string in
  // such a case.
  uint32 unit_ref = 4;
}

// A native histogram, also known as a sparse histogram.
// See https://github.com/prometheus/prometheus/blob/remote-write-2.0/prompb/io/prometheus/write/v2/types.proto#L142
// for a full message that follows the native histogram spec for both sparse
// and exponential, as well as, custom bucketing.
message Histogram { ... }

すべてのタイムスタンプは、Unix エポックからのミリ秒単位の int64 としてカウントされなければなりません。サンプル値は float64 でなければなりません。

TimeSeries メッセージについて

  • labels_refs を提供しなければなりません。
  • samples または histograms のいずれかに少なくとも 1 つの要素を提供しなければなりません。TimeSeriessampleshistograms の両方を含んではなりません。float と histogram のサンプルを(まれに)混在させるシリーズの場合は、別の TimeSeries メッセージを使用しなければなりません。
  • metadata のサブフィールドは提供されるべきです。受信元は、指定されていない Metadata.type を持つシリーズを拒否する場合があります。
  • Exemplars は、シリーズに存在する場合、提供されるべきです。
  • created_timestamp は、カウンターセマンティクス(例: カウンターとヒストグラム)に従うメトリックに対して提供されるべきです。受信元は、created_timestamp が設定されていないこれらのシリーズを拒否する場合があります。

以下のサブセクションで、スキーマ要素の詳細を定義します。

シンボル

io.prometheus.write.v2.Request Protobuf メッセージは、標準の圧縮に加えて、明白な追加の圧縮とメモリ効率の向上を実現するために、すべての文字列をインターンするように設計されています。

symbols テーブルを提供しなければならず、シリーズ、exemplar ラベル、およびメタデータ文字列で使用される重複排除された文字列を含まなければなりません。symbols テーブルの最初の要素は空文字列でなければなりません。これは、Metadata.unit_ref または Metadata.help_ref が提供されていない場合のように、空または未指定の値を示すために使用されます。参照は、symbols 文字列配列の既存のインデックスを指さなければなりません。

シリーズラベル

ラベルの完全なセットは、各 Sample または Histogram サンプルとともに送信しなければなりません。さらに、サンプルに関連付けられたラベルセットは

  • __name__ ラベルを含んでいるべきです。
  • 繰り返されるラベル名を含んではなりません。
  • 辞書順でソートされたラベル名を持たなければなりません。
  • 空のラベル名または値を含んではなりません。

メトリック名、ラベル名、およびラベル値は、UTF-8 文字の任意のシーケンスでなければなりません。

メトリック名は、正規表現 [a-zA-Z_:]([a-zA-Z0-9_:])* に従うべきです。

ラベル名は、正規表現 [a-zA-Z_]([a-zA-Z0-9_])* に従うべきです。

上記に従わない名前は、PromQL ユーザーにとって使用が困難になる可能性があります(詳細については、UTF-8 提案 を参照してください)。

「__」で始まるラベル名は、システム使用のために予約されており、使用すべきではありません。詳細は Prometheus データモデル を参照してください。

受信元は、ラベルの数と長さに制限を設けることもできますが、これは受信元固有であり、このドキュメントの範囲外です。

サンプルとヒストグラムサンプル

送信元は、指定された TimeSeries に対して、タイムスタンプ順に samples(または histograms)を送信しなければなりません。送信元は、異なるシリーズに対して複数のリクエストを並行して送信してもかまいません。

送信元は、時系列がこれ以上追加されなくなる場合に、一時的なマーカーを送信すべきです。送信元は、時系列の中断が検出可能な場合、一時的なマーカーを送信しなければなりません。たとえば、

  • プッシュされた(スクレイプされた)シリーズで、明示的なタイムスタンプが使用されなかった場合。
  • レコーディングルール評価の結果として生成されたシリーズの場合。

一般的に、中断されたシリーズに対して一時的なマーカーを送信しないと、受信元で無意味なクエリタイムアラインメントの問題が発生する可能性があります。

一時的なマーカーは、特別な NaN 値 0x7ff0000000000002 によってシグナルされなければなりません。この値は、それ以外の場合に使用してはなりません。

通常、送信元は、以下の技術を使用して、時系列がそれ以上追加されなくなる時期を検出できます。

  1. サービスディスカバリを使用して、シリーズを公開しているターゲットがなくなったことを検出する。
  2. successive scrape の間で、ターゲットが時系列を公開しなくなったことに気づく。
  3. 元の時系列を公開していたターゲットのスクレイプに失敗する。
  4. レコーディングおよびアラートルールの設定と評価を追跡する。
  5. メトリックの非スクレイプソース(例: k6 で、ベンチマークがベンチマークごとにシリーズを終了した場合、一時的なマーカーを放出する可能性がある)の中断を追跡する。

メタデータ

メタデータは、TypeHelp に関する公式 Prometheus ガイドラインに従うべきです。

メタデータは、Unit に関する公式 OpenMetrics ガイドラインに従うことができます。

Exemplars

各 exemplar が TimeSeries に添付されている場合、

  • 値を含まなければなりません。
  • ラベル(例: トレースまたはリクエスト ID を参照)を含んでもかまいません。exemplar がトレースを参照する場合、ベストプラクティスとして trace_id ラベル名を使用すべきです。
  • タイムスタンプを含まなければなりません。exemplar タイムスタンプは Prometheus/Open Metrics のエクスポーズフォーマットではオプションですが、サンプルスクレイプにタイムスタンプが割り当てられるのと同じ方法で、スクレイプ時にタイムスタンプが割り当てられるという想定があります。受信元は、受信した exemplar を確実に処理するため(例: 重複排除)、exemplar タイムスタンプを必要とします。

範囲外

1.0 と同じです。

今後の計画

このセクションには、まだプロトコル仕様の一部とは見なされていない投機的な計画が含まれていますが、完全性のためにここに記載されています。なお、2.0 仕様は、1.0 の 3 つの将来計画のうち 2 つ を完了しました。

  • トランザクション性 2.0 仕様では、まだトランザクション性は定義されていません。これは主に、スケーラブルな送信元実装を困難にするためです。Prometheus 送信元は「トランザクション的」であることを目指しています。つまり、部分的にスクレイプされたターゲットをクエリに公開しないようにします。Remote-Write でも同様のことを行う予定です。たとえば、将来的に Remote-Write をスクレイプと「アライン」させたいと考えています。これにより、単一のスクレイプのすべてのサンプル、メタデータ、および exemplar が単一の Remote-Write リクエストで送信されるようになる可能性があります。

    しかし、Remote-Write 2.0 仕様は、従来のヒストグラムバケット の重要なトランザクション性問題を解決します。これは、io.prometheus.write.v2.Request ワイヤフォーマットで可能なカスタムバケットをサポートするネイティブヒストグラムのおかげです。送信元は、すべての従来のヒストグラムをこの方法でネイティブヒストグラムに変換するかもしれませんが、これはこの仕様では義務付けられていません。ただし、この理由により、受信元は特定のメトリックタイプ(例: 従来のヒストグラム)を無視してもかまいません。

  • 代替ワイヤフォーマット。OpenTelemetry コミュニティは、OTLP プロトコルを使用して、Apache Arrow(およびその他の列指向フォーマットの可能性)をワイヤ上のデータ転送に有効であることを示しています。同様のフォーマットを Prometheus のデータモデルと互換性があるか確認するための実験を行い、リソース使用量の変更のベンチマークを含める予定です。長期的に protobuf と列指向フォーマットの両方を互換性のために維持し、コンテンツネゴシエーションを使用して、この目的のために異なる Protobuf メッセージを追加する可能性があります。

  • グローバルシンボル。インターン化のための事前定義された文字列辞書。プロトコルは、共通と見なされる文字列(例: 「namespace」、「le」、「job」、「seconds」、「bytes」など)を含む ref->symbol の静的辞書を事前定義できます。送信元は、リクエストのシンボルテーブルに含める必要なしに、これらを参照できます。この辞書は、このプロトコルのマイナーバージョンリリースで段階的に拡張される可能性があります。

FAQ

なぜ gRPC を使用しなかったのですか? 1.0 プロトコルは gRPC を使用しないため、それを壊すと導入の際の摩擦が増加します。1.0 の理由を参照してください。

protobuf メッセージをストリーミングしないのはなぜですか? 永続的な HTTP/1.1 接続を使用する場合、これらはストリーミングに非常に近いです。もちろん、ヘッダーは再送信する必要がありますが、新しい TCP セットアップよりもコストは低くなります。

なぜサンプルを順序どおりに送信するのですか? 順序制約は、Prometheus で時系列データをエンコードする方法に由来します。その実装は、追記専用ワークロードに最適化されています。ただし、この要件は、エコシステムの多くの他のデータベースやベンダーとも共有されています。実際、OOO 機能を有効にした Prometheus は順不同書き込みを許可しますが、パフォーマンスのペナルティがあるため、まれなイベントに予約されています。要約すると、受信元は順不同書き込みをサポートする場合がありますが、仕様では許可されていません。将来、たとえば 2.x 仕様バージョンでは、必要に応じて、順不同書き込みをネゴシエートするためにコンテンツタイプを拡張できます。

順序制約でリクエストを並列化するにはどうすればよいですか? サンプルは、*特定のシリーズ*に対して順序どおりである必要があります。ただし、受信元が順不同書き込みをサポートしていない場合でも、異なるシリーズのリクエストであれば、Remote-Write リクエストは並列に送信できます。Prometheus は、ラベルによってサンプルを個別のキューにシャードし、次に各キューで書き込みが順次行われます。これにより、同じシリーズのサンプルは順序どおりに配信されることが保証されますが、異なるシリーズのサンプルは並列に送信され、潜在的に異なるシリーズ間で「順不同」になる可能性があります。

Remote-Write 2.0 と OpenTelemetry の OTLP プロトコルの違いは何ですか? OpenTelemetry OTLP は、テレメトリソース、中間ノード、およびテレメトリバックエンド間でテレメトリデータ(メトリック、ログ、トレース、プロファイルなど)を転送するためのプロトコルです。推奨される転送は gRPC と protobuf を使用しますが、protobuf または JSON を使用する HTTP も記述されています。さまざまなオブザーバビリティシグナル、データ型、および追加情報をサポートすることを目的として、ゼロから設計されました。メトリックについては、追加の非識別ラベル、フラグ、時間集計タイプ、リソースまたはスコープ付きメトリック、スキーマ URL などがあります。OTLP はセマンティック規約の使用も要求します。

Remote-Write は、シンプルさ、効率性、および有機的な成長のために設計されました。最初のバージョンは 2023 年に正式にリリースされ、すでにCNCF エコシステムで何十もの実証済みの採用者が長年このプロトコルを使用していました。Remote-Write 2.0 は、いくつかの新しい要素(メタデータ、exemplars、作成タイムスタンプ、ネイティブヒストグラム)と文字列インターン化を追加することで、以前のプロトコルを改良しています。Remote-Write 2.0 は常にステートレスであり、メトリックのみに焦点を当て、意見が分かれています。そのため、Prometheus コミュニティが堅牢なメトリックソリューションに必要だと考えている要素に限定されています。その意図は、Remote-Write をオブザーバビリティエコシステムにおける代替手段よりも安価で導入・使用しやすい安定したプロトコルにすることです。

このページの内容