リレーとリージョン
エージェントの隣にコレクターを置き、リージョン間の区間は再試行付きで渡ります。
リレーとは
mcpd relay は、同じバイナリを、自分では何も保存しない
コレクターとして動かします。デーモンが受け付ける HTTP の取り込み
リクエストをすべて受け付け、リクエストをディスク上のスプールに書き、
送信元に応答してから、--upstream が示すデーモンへその
リクエストを送ります。ストアは開きません。
エージェントが動く各リージョンに 1 つずつ置いてください。送信元は数ミリ秒 先のコレクターと話すことになり、リージョン間の区間は、各エージェントが それぞれ渡るのではなく、リレーが再試行付きで渡ります。
上流が 2 つあるエッジのリレー
mcpd relay \
--ingest-key $INGEST_KEY \
--upstream http://mcpd.eu.internal:4317 \
--upstream http://mcpd.us.internal:4317 $ MCPD_UPSTREAMS=http://mcpd.eu.internal:4317,http://mcpd.us.internal:4317 mcpd --data /data/mcpd.db config | grep ^relayrelay 2 upstream(s) in order, http://mcpd.eu.internal:4317, http://mcpd.us.internal:4317; each sender's key passed on; spool at /data/mcpd.spool/relay, 1024 MiB$ curl -s -D - -o /dev/null localhost:4317/v1/ingest -H "content-type: application/json" -d @batch.json | grep -e ^HTTP -e mcpd-relayHTTP/1.1 202 Acceptedmcpd-relay: spooled$ curl -s localhost:4317/v1/ingest -H "content-type: application/json" -d @batch.json{"accepted":0,"duplicate":0,"rejected":0} 何を応答するか
プローブ以外のパスなら、どのパスへの POST も受け付けます。OTLP のパス
/v1/traces、/v1/logs、/v1/metrics
は、OTLP の partialSuccess とともに 200 を返します。
OpenTelemetry のエクスポーターが期待する応答です。それ以外のパスは、
ヘッダー mcpd-relay: spooled と本文
{"accepted":0,"duplicate":0,"rejected":0} とともに
202 を返します。リクエストは預かられ、届けられます。本当の件数はまだ
それを見ていない上流のものです。どの SDK も、2xx はすべて成功として読みます。
リレーは何かを書く前に --ingest-key を自分で確かめ、
--max-body-bytes と --request-timeout-seconds を
デーモンと同じように適用します。応答を送る前に、リクエストはスプール
<spool-dir>/relay に入っています。
配送とフェイルオーバー
4 つのワーカーがスプールを送ります。各リクエストは、--upstream
の順で、待機中でない最初の上流に送られます。再試行できる失敗があると、
その上流はバックオフとジッターで、または Retry-After が示す
あいだ待機に入り、リクエストはすぐに次の上流へ送られます。待機が終わると
再び第一の上流が先に試されるので、トラフィックはひとりでにそこへ戻ります。
400 のような最終的な拒否は、次の上流には送られません。次の上流も同じ
バイト列を拒否するからです。リクエストはスプールディレクトリーの
dead/ に移され、数えられます。
二重に数えない
配送は少なくとも 1 回で、再送は 1 回だけ保存されます。どのリクエストも
Idempotency-Key ヘッダーを持ちます。送信元が送ったならその
キー、そうでなければ relay- の後にパス、コンテンツエンコー
ディング、本文のダイジェストを続けたものです。デーモンの取り込み口は
どれもこのヘッダーを尊重し、ネイティブのバッチ本文にあるキーはヘッダーより
優先されます。タイムアウトの後にリレーが再送したリクエストや、第一の上流が
受け取ったのに応答が失われ、第二の上流へ送ったリクエストは、重複として
認識され、そう報告されます。
キー
--upstream-key があれば、リレーはそのキーを Bearer トークン
として、すべての上流に提示します。なければ、送信元の
Authorization または x-mcpd-key ヘッダーが、
リレーのユーザーだけが読めるファイルに、スプールしたリクエストとともに
保たれ、そのまま渡されます。後者の形なら、各送信元のプロジェクトと
スコープが、上流からもそのまま見えます。
背圧と準備状態
スプールの大きさは --spool-max-bytes で制限され、設定しな
ければリレーは 1 GiB です。いっぱいになると、リクエストは 503 と
Retry-After: 5 で拒否されます。どの SDK も OpenTelemetry の
エクスポーターもこれを再試行するので、リレーがデータを捨てるのではなく、
送信元がデータを持ち続けます。
/healthz は常に 200 を返します。/readyz の
応答は次のとおりです。
- 上流に届くあいだは 200
ok。 -
直近 30 秒に、どの上流も
/readyzに応答せず、配送も受け 取っていなければ、detail付きの 200degraded。 上流は 5 秒ごとに確かめられます。 - スプールがいっぱいのとき、またはどの上流にも届かずスプールが 80% 以上 埋まっているときは 503。
そのため、ロードバランサーはバッファーしているリレーには送り続け、もう 受け取れないリレーからはトラフィックを移します。
リレーのメトリクス
| メトリクス | 種類 | 意味 |
|---|---|---|
mcpd_relay_accepted_total | counter | スプールに書かれたリクエスト |
mcpd_relay_refused_full_total | counter | スプールがいっぱいで、503 で拒否されたリクエスト |
mcpd_relay_failovers_total | counter | 最初以外の上流に届けられたリクエスト |
mcpd_relay_dead_letter_total | counter | 上流が最終的に拒否し、dead/ に移されたリクエスト |
mcpd_relay_spool_entries | gauge | スプールで待っているリクエスト |
mcpd_relay_spool_bytes | gauge | スプールが持っているバイト数 |
mcpd_relay_spool_oldest_seconds | gauge | 待っている最も古いリクエストの経過時間、なければ 0 |
mcpd_relay_delivered_total | counter | 上流が受け付けたリクエスト。ラベルは upstream と order |
mcpd_relay_failed_attempts_total | counter | 上流が受け付けなかった試行。ラベルは同じです |
mcpd_relay_upstream_up | gauge | 上流が直近 30 秒に応答していれば 1、そうでなければ 0 |
mcpd_uptime_seconds | gauge | このプロセスが起動してからの秒数 |
mcpd_relay_failovers_total が増えているなら、第一の上流が
失敗していて、第二の上流がそのトラフィックを運んでいます。
mcpd_relay_spool_oldest_seconds は、配送がどれだけ遅れて
いるかを示します。
複数のリージョン
1 つまたは複数のリージョンで、複数のデーモンのレプリカを 1 つの Postgres
か ClickHouse のストアに向けて動かします。実行は Postgres に置く
(--runs-data postgres://...)か、オフにします。組み込みの実行
ストアは 1 つのプロセスに属するからです。各レプリカの
/readyz は、ストアに届くかどうかをすでに反映しています。各
リージョンでその前にリレーを置き、--upstream には最も近い
デーモンを最初に、別のリージョンのデーモンを 2 番目に並べてください。
レプリカが 2 つ以上になると、4 つの設定のふるまいが変わります。
- 冪等性キーは共有ストアに置かれるので、別のレプリカに届いた再送も認識 されます。Postgres は、バッチと同じトランザクションでキーを記録します。
- 1 分あたりのクォータの上限は、レプリカごとに数えられます。望む上限を レプリカの数で割ってください。
- ライブ採点、テールサンプリング、モニターのアラートは、一度に 1 つの レプリカで動きます。レプリカは共有ストアのリースで交代します。持ち主は 処理のたびにリースを更新し、停止するときに手放します。持ち主が止まれば、 3 回の処理のうちに別のレプリカが引き継ぎます。どのレプリカも自分の モニターと目標を評価するので、どれもモニター API に答えますが、webhook を 送るのは持ち主だけです。すべてのレプリカで同じように設定してください。
- 観点の分析は、それを設定したすべてのレプリカで動きます。1 つのレプリカに 設定してください。
デプロイの例
deploy/docker/docker-compose.multi-region.yml は、1 台の
マシンで Postgres、2 つのデーモン、1 つのリレーを起動します。構成全体を
試せる形にしたものです。
Helm チャートは mode: relay を受け付けます。
deploy/helm/examples/ にある 3 つの values ファイルは、それぞれ
1 つのリージョンを表します。region-core.yaml、
region-standby.yaml、region-edge-relay.yaml で、
最後のものはリレーだけを動かすリージョン用です。