Prometheus Remote-Write仕様

  • バージョン: 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メッセージ)とは、このプロトコルにおけるデータ構造のコンテンツタイプ定義を指します。この仕様では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で構成されなければなりません(MUST)。

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

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

ProtobufメッセージはバイナリWire Formatを使用しなければなりません(MUST)。その後、GoogleのSnappyで圧縮しなければなりません(MUST)。Snappyのブロックフォーマットを使用しなければならず(MUST)、フレーミングフォーマットは使用してはなりません(MUST NOT)。

送信者は、シリアライズされ圧縮されたProtobufメッセージをHTTP POSTリクエストのボディに含めて、提供されたURLパスでHTTP経由で受信者に送信しなければなりません(MUST)。受信者は、メトリックを受信する任意のHTTP URLパスを指定してもよいです(MAY)。

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

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

送信者は、ユーザーがカスタムHTTPヘッダーを追加することを許可してもよいです(MAY)。ただし、予約済みヘッダーを送信するような方法でユーザーが設定することを許可してはなりません(MUST NOT)。

Content-Encoding

Content-Encoding: <compression>

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

Content-Type

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

コンテンツタイプリクエストヘッダーはRFC 9110に従わなければなりません(MUST)。送信者は唯一のメディアタイプとしてapplication/x-protobufを使用しなければなりません(MUST)。送信者はヘッダーの値に;proto=パラメータを追加して、上記2つのProtobufメッセージのうち、使用されたメッセージの完全修飾名を示すことができます(MAY)。結果として、送信者は以下の3つのサポートされているヘッダー値のいずれかを送信しなければなりません(MUST)。

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を使用すべきです(SHOULD)。それ以外の場合、送信者はContent-Type: application/x-protobuf;proto=io.prometheus.write.v2.Requestを使用すべきです(SHOULD)。さらなるProtobufメッセージは2.x以降で導入される可能性があります。

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

注: io.prometheus.write.v2.Requestの予約済みフィールドのおかげで、受信者が誤ってprometheus.WriteRequestで間違ったスキーマを使用した場合、空のメッセージになります。これは通常、予期せぬエラーを避けるための便宜的なものですが、これに依存しないでください。将来のProtobufメッセージにはこの機能がない可能性があります。

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を使用しなければなりません(MUST)。それ以外の場合、送信者は互換性のある最新のRemote-Writeバージョン(例: X-Prometheus-Remote-Write-Version: 2.0.0)を使用すべきです(SHOULD)。

User-Agent

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

送信者は、RFC 9110のUser-Agentヘッダー形式に従うべき(SHOULD)ユーザーエージェントヘッダーを含まなければなりません(MUST)。

レスポンス

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

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

以下のサブセクションでは、ヘッダーおよび異なる書き込みエラーケースに関する送信者と受信者のセマンティクスを詳述します。

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

コンテンツネゴシエーションが成功すると、受信者は受信したデータのバッチを処理(書き込み)します。各重要なデータ(現在、サンプル、ヒストグラム、エグゼンプラー)の処理が完了(成功または失敗)した後、受信者は、正常に書き込まれた要素の正確な数を示す専用のHTTP X-Prometheus-Remote-Write-*-Writtenレスポンスヘッダーを送信しなければなりません(MUST)。

各ヘッダー値は単一の64ビット整数でなければなりません(MUST)。ヘッダー名は以下のとおりでなければなりません(MUST)。

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レスポンスヘッダーが欠落している場合、このカテゴリ(例: サンプル)の要素が受信者によって書き込まれなかった(カウントが0)と仮定できます(CAN)。送信者は、非推奨のprometheus.WriteRequest Protobufメッセージを使用する場合、この機能を持たない1.0受信者に遭遇するリスクがあるため、同じことを仮定してはなりません(MUST NOT)。

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

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

送信者は、リモートライトレスポンスヘッダーから受信者が実装しているRemote Write仕様のバージョンを想定してはなりません(MUST NOT)。

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

部分書き込み

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

未サポートのリクエストコンテンツ

受信者は、送信者によって提供された特定のコンテンツタイプまたはエンコーディングをサポートしない場合、415 HTTP Unsupported Media Typeステータスコードを返さなければなりません(MUST)。

後方互換性のため、送信者は1.x受信者からの上記の理由による400 HTTP Bad Requestを想定すべきです(SHOULD)。

無効なサンプル

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

送信者は、4xx HTTPステータスコード(429を除く)に対してリトライしてはなりません(MUST NOT)。これは、書き込み操作が成功することはなく、リトライすべきではないことを示すために受信者が使用しなければならない(MUST)ものです。送信者は、415 HTTPステータスコードに対して、受信者がそれをサポートしているかどうかを確認するために、異なるコンテンツタイプまたはエンコーディングでリトライしてもよいです(MAY)。

リトライ & バックオフ

受信者は、サーバーの過負荷状況を示すために429 HTTP Too Many Requestsステータスコードを返してもよいです(MAY)。受信者は、次の書き込み試行までの時間を示すためにRetry-Afterヘッダーを返してもよいです(MAY)。受信者は、内部サーバーエラーを示すために5xx HTTPステータスコードを返してもよいです(MAY)。

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

429と5xxの処理の違いは、受信者がリクエスト量についていけない場合に送信者が「遅延する」可能性のある状況、または受信者がその可用性を保護するために送信者をレート制限することを選択する状況に起因します。結果として、送信者側でエラー(例: トラフィックが多すぎる)が発生した場合でも進捗が可能である一方、受信者側でエラー(5xx)が発生した場合でもデータが失われないように、送信者は429に対してリトライしないという選択肢を持っています。

部分書き込み時のリトライ

受信者は、部分書き込みまたは部分的に無効なサンプルケースにおいて、送信者がリクエスト全体をリトライすることを期待する場合、5xx HTTPまたは429 HTTPステータスコードを返してもよいです(MAY)。その場合、送信者は同じリクエストでリトライする可能性があるため、受信者はべき等性をサポートしなければなりません(MUST)。

後方・前方互換性

このプロトコルはセマンティックバージョニング 2.0に従います。つまり、2.x互換の受信者は、2.x互換の送信者から読み取ることができなければならず(MUST)、その逆も同様です。破壊的変更または後方非互換の変更は、仕様の3.xバージョンにつながります。

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

  • Protobufメッセージからフィールドを削除するには、メジャーバージョンを上げる必要があります。
  • (オプションの)フィールドの追加は、マイナーバージョンを上げることで可能です。

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

2.x 対 1.x 互換性

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

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

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の依存関係とオプションは無視できます(CAN)(最終的には削除されます)。これらはシリアライズされた形式に影響を与えないため、仕様の一部ではありません。

新しい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でなければなりません(MUST)。サンプルの値はfloat64でなければなりません(MUST)。

すべてのTimeSeriesメッセージについて

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

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

シンボル

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

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

シリーズラベル

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

  • __name__ラベルを含むべきです(SHOULD)。
  • 重複するラベル名を含んではなりません(MUST NOT)。
  • ラベル名は辞書順にソートされていなければなりません(MUST)。
  • 空のラベル名や値を含んではなりません(MUST NOT)。

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

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

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

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

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

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

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

送信者は、任意のTimeSeriessamples(またはhistograms)をタイムスタンプ順に送信しなければなりません(MUST)。送信者は、異なるシリーズに対して複数のリクエストを並行して送信してもよいです(MAY)。

送信者は、時系列がこれ以上追加されない場合に、陳腐化マーカーを送信すべきです(SHOULD)。送信者は、時系列の廃止が検出可能な場合(例として)は陳腐化マーカーを送信しなければなりません(MUST)。

  • (スクレイプで)プルされたシリーズの場合、明示的なタイムスタンプが使用されていない限り。
  • 記録ルール評価によって生成されたシリーズの場合。

一般的に、廃止されたシリーズに対して陳腐化マーカーを送信しないと、受信者側で自明ではないクエリ時間のずれの問題が発生する可能性があります。

陳腐化マーカーは、特別なNaN値0x7ff0000000000002によって通知されなければなりません(MUST)。この値はそれ以外の場合に使用してはなりません(MUST NOT)。

通常、送信者は以下の手法を使用して、時系列がこれ以上追加されない時期を検出できます。

  1. サービスディスカバリを使用して、シリーズを公開しているターゲットがなくなったことを検出する。
  2. 連続するスクレイプ間でターゲットが時系列を公開しなくなったことに気づく。
  3. 元々時系列を公開していたターゲットをスクレイプできない。
  4. 記録ルールとアラートルールの設定と評価を追跡する。
  5. スクレイプ以外のメトリックソース(例: k6でベンチマークごとのシリーズのベンチマークが完了した際、陳腐化マーカーを発行できる)のメトリックの廃止を追跡する。

メタデータ

メタデータは、ヘルプに関する公式Prometheusガイドラインに従うべきです(SHOULD)。

メタデータは、単位に関する公式OpenMetricsガイドラインに従ってもよいです(MAY)。

エグゼンプラー

各エグゼンプラーは、TimeSeriesにアタッチされている場合、

  • 値を含まなければなりません(MUST)。
  • ラベル(例: トレースまたはリクエストIDを参照するもの)を含んでもよいです(MAY)。エグゼンプラーがトレースを参照する場合、ベストプラクティスとしてtrace_idラベル名を使用すべきです(SHOULD)。
  • タイムスタンプを含まなければなりません(MUST)。Prometheus/Open Metricsの公開形式ではエグゼンプラーのタイムスタンプはオプションですが、スクレイプサンプルにタイムスタンプが割り当てられるのと同じ方法で、スクレイプ時にタイムスタンプが割り当てられるという前提があります。受信者は、受信するエグゼンプラーを確実に処理(例: 重複排除)するために、エグゼンプラーのタイムスタンプを必要とします。

範囲外

1.0と同じです。

今後の計画

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

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

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

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

  • グローバルシンボル。インターンのための事前定義された文字列辞書。プロトコルは、"namespace"、"le"、"job"、"seconds"、"bytes"など、一般的と見なされる文字列を含むref->シンボルの静的辞書を事前に定義することができます。送信者は、これらの文字列をリクエストのシンボルテーブルに含める必要なく参照できます。この辞書は、このプロトコルのマイナーバージョンリリースとともに段階的に成長する可能性があります。

よくある質問

なぜ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は、テレメトリーソース、中間ノード、テレメトリーバックエンド間でテレメトリーデータ(メトリック、ログ、トレース、プロファイルなど)を転送するためのプロトコルです。推奨される転送はProtobufを使用したgRPCですが、ProtobufまたはJSONを使用したHTTPも記述されています。これは、さまざまなオブザーバビリティシグナル、データタイプ、追加情報をサポートすることを目的としてゼロから設計されました。メトリックの場合、これは追加の非識別ラベル、フラグ、時間的集約タイプ、リソースまたはスコープ付きメトリック、スキーマURLなどを意味します。OTLPはまた、セマンティック規約の使用を要求します。

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

このドキュメントはオープンソースです。問題の報告やプルリクエストの送信により、改善にご協力ください。