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

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

リモート書き込み仕様は、一般的に、PrometheusおよびPrometheusリモート書き込み互換の送信者がPrometheusまたはPrometheusリモート書き込み互換の受信者にデータを送信する方法の標準を文書化することを目的としています。

このドキュメントは、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にコメントとして追加してください。

はじめに

背景

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

リモート書き込みプロトコルはステートレスであるように設計されており、メッセージ間の通信は一切ありません。そのため、このプロトコルは「ストリーミング」とはみなされません。ストリーミング効果を実現するには、HTTP/1.1やHTTP/2などを使用して、同じ接続で複数のメッセージを送信する必要があります。gRPCのような「高度な」技術も検討されましたが、当時は広く採用されておらず、AWS EC2 ELBのようなロードバランサーの背後でgRPCサービスをインターネットに公開することは困難でした。

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

テストスイートはhttps://github.com/prometheus/compliance/tree/main/remote_write_senderにあります。リモート書き込み2.0互換性に関する適合性テストは、まだ進行中です。

用語集

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

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

定義

プロトコル

リモート書き込みプロトコルは、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メッセージはバイナリワイヤーフォーマットを使用しなければなりません。その後、GoogleのSnappyで圧縮しなければなりません。Snappyのブロックフォーマットを使用しなければなりません。フレームフォーマットは使用してはなりません。

送信者は、シリアル化および圧縮されたProtobufメッセージをHTTP POSTリクエストのボディに含め、提供されたHTTP URLパスを介して受信者に送信しなければなりません。受信者は、メトリックを受信するための任意の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を使用しなければなりません。送信者は、使用されたProtobufメッセージの完全修飾名を上記2つのうちから示すために、ヘッダの値に;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を使用すべきです。それ以外の場合、送信者はContent-Type: application/x-protobuf;proto=io.prometheus.write.v2.Requestを使用すべきです。さらに多くのProtobufメッセージが2.x以降で提供される可能性があります。

受信者は、Content-Typeヘッダを使用して、使用するProtobufメッセージスキーマを識別しなければなりません。誤ったスキーマを選択すると、非決定的な動作(例:破損)が発生する可能性があります。

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

User-Agent

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

送信者は、RFC 9110のUser-Agentヘッダ形式に従うUser-Agentヘッダを含まなければなりません。

応答

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

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

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

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

コンテンツネゴシエーションが成功すると、受信者は受信したデータのバッチを処理(書き込み)します。各重要なデータ(現在、サンプル、ヒストグラム、エグゼンプラ)について完了(成功または失敗)すると、受信者は正常に書き込まれた要素の正確な数を示す専用の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レスポンスヘッダーが欠落している場合、そのカテゴリ(例:サンプル)からの要素が受信者によって書き込まれなかった(カウントが0)と仮定してもよいです。この機能がない1.0受信者と遭遇するリスクがあるため、非推奨のprometheus.WriteRequestProtobufメッセージを使用する場合は、送信者は同じことを仮定してはなりません。

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

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

送信者は、リモート書き込み応答ヘッダーから受信者が実装しているリモート書き込み仕様のバージョンを推測してはなりません。

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

部分書き込み

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

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

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

送信者は、下位互換性のために、上記の理由で1.xの受信者から400 HTTP Bad Requestを期待すべきです。

無効なサンプル

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

送信者は、4xx HTTPステータスコード(429以外)では再試行してはなりません。4xxは、受信者が書き込み操作が成功する見込みがなく、再試行すべきではないことを示すために使用しなければなりません。送信者は、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つの要素が提供されなければなりません。TimeSeriesは、sampleshistogramsの両方を含んではなりません。floatとヒストグラムサンプルを(まれに)混在させる系列の場合、別のTimeSeriesメッセージを使用しなければなりません。
  • metadataのサブフィールドは提供されるべきです。レシーバーは、指定されていないMetadata.typeを持つ系列を拒否する場合があります。
  • Exemplarsは、系列に存在する場合、提供されるべきです。
  • created_timestampは、カウンターセマンティクス(例:カウンターとヒストグラム)に従うメトリックに対して提供されるべきです。レシーバーは、created_timestampが設定されていないこれらの系列を拒否する場合があります。

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

シンボル

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

symbolsテーブルは提供されなければならず、系列、エグゼンプララベル、およびメタデータ文字列で使用される重複しない文字列を含まなければなりません。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. 連続したスクレイプ間でターゲットが時系列を公開しなくなったことに気づく。
  3. 元々時系列を公開していたターゲットのスクレイプに失敗する。
  4. 記録ルールとアラートルールの構成と評価を追跡する。
  5. スクレイプ以外のメトリックソースのメトリックの廃止を追跡する(例:k6でベンチマークごとにシリーズのベンチマークが終了した場合、陳腐化マーカーを発行する可能性がある)。

メタデータ

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

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

Exemplars

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

  • 値を含まなければなりません。
  • ラベルを含む場合があります。例えば、トレースIDやリクエストIDを参照する場合などです。エグゼンプラがトレースを参照する場合、ベストプラクティスとしてtrace_idラベル名を使用すべきです。
  • タイムスタンプを含まなければなりません。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ワイヤフォーマットでカスタムバケットをサポートするネイティブヒストグラムのおかげで実現されます。送信者は、すべての従来のヒストグラムをこの方法でネイティブヒストグラムに変換する可能性がありますが、これを義務付けることはこの仕様の範囲外です。ただし、この理由から、レシーバーは特定のメトリックタイプ(例:従来のヒストグラム)を無視する場合があります。

  • 代替のワイヤー形式。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ですが、HTTPとprotobufまたはJSONも説明されています。これは、さまざまなオブザーバビリティ信号、データ型、および追加情報をサポートすることを目的としてゼロから設計されました。メトリクスの場合、これは追加の非識別ラベル、フラグ、時間集計タイプ、リソースまたはスコープ付きメトリクス、スキーマURLなどを意味します。OTLPはセマンティック規約の使用も要求します。

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

このページの内容