質問
設定エクスポートのために、etcd から数百万件のプレフィックス付きキーを読み取る必要があります。サーバーとクライアントのメモリピークを抑え、一貫した結果を維持し、エラーから復旧し、サポートされていないクエリオプションを処理するために、RangeStream をどのように使用しますか?
コンテキストと境界
etcd v3.7 は2026年7月8日にリリースされ、RangeStream が追加されました。公式プロジェクトによれば、大規模な範囲結果をチャンクに分割するため、サーバーもクライアントもレスポンス全体をバッファリングする必要がありません。この質問は有限の大規模結果の読み取りに関するものであり、Watch に関するものではなく、RangeStream がソート、リビジョンフィルタ、または etcd gRPC プロキシをサポートしていることを前提としていません。
最初に確認すべき点:エクスポートには1つの一貫したビューが必要ですか?コンシューマーはチャンクが到着するたびに処理できますか?障害発生後、完全な再試行で問題ありませんか、それとも進捗を記録する必要がありますか?クライアントは etcd に直接接続しますか、それとも gRPC プロキシ経由で接続しますか?
面接官が見ているポイント
面接官は、あなたがストリーミング RPC セマンティクスを理解しているかどうかをテストしています。チャンクを段階的に消費すること、末尾のメタデータを認識すること、エラー時に不完全な出力を破棄すること、同一リビジョンの境界を維持すること、サポートされていないソートやフィルタリングに対する代替策を設計できるかどうかです。
30秒の回答
まず一貫性とリカバリの要件を確認します。RangeStream のチャンクを消費し、メモリ内に蓄積する代わりに一時ファイルまたはダウンストリームにキーを書き込みます。header、more、count は、正常に完了した後の最終チャンクからのみ読み取ります。範囲、リビジョン、チャンク数を記録し、ストリーム障害時には不完全な出力を破棄して再試行します。ソートまたはリビジョンフィルタリングが必要な場合は、サポートされていないオプションを渡すのではなく、制御されたアプリケーション側での処理を使用するか、タスクを分割します。
ステップバイステップの詳細解説
- API の選択:RangeStream は Range と同じ RangeRequest を受け入れますが、複数の
RangeStreamResponseメッセージを返します。これは大規模な結果セット向けであり、変更のサブスクリプションではありません。 - 一貫性:リクエストでリビジョンが設定されていない場合、サーバーはストリームの開始時に最新のコミット済みリビジョンを取得し、そのリビジョンからすべてのチャンクを提供します。監査可能性のためにそれを記録します。
- 段階的な消費:各チャンクには
kvsの重複しないスライスが含まれます。チャンクを到着順に一時ファイル、オブジェクトストレージ、またはダウンストリームプロセッサに書き込みます。バックプレッシャーによってメモリスパイクが再発しないように、バイト数、レコード数、処理時間を制限します。 - 末尾メタデータ:
header、more、countは、ストリームが正常に完了したときの最終チャンクにのみ設定されます。それ以前のチャンクではゼロ値のままになるため、早い段階で合計値を取得することはできません。 - エラーリカバリ:ストリームエラーが発生した場合、有効な
header、more、countを保持するチャンクはありません。一時出力を無効とマークし、同じリビジョンと範囲で再試行し、成功した後にのみエクスポートをアトミックに公開します。 - 機能の境界:RangeStream はカスタムの順序付け、リビジョンフィルタ、または etcd gRPC プロキシをサポートしていません。互換性のある直接エンドポイントを使用するか、範囲を狭めるか、制御されたアプリケーション側のソートとバージョンチェックを適用します。
- アップグレードポリシー:v3.6 から v3.7 に移行する前に、少なくとも v3.6.11 を実行し、サポートされている隣接マイナーバージョンのアップグレードパスに従い、クライアント、プロキシ、エクスポートジョブをカナリアリリースします。
模範回答
私なら、エクスポートを固定リビジョンを持つ復旧可能なバッチにします。etcd v3.7 の RangeStream は Range 結果をチャンク化するため、サーバーもクライアントも結果全体をバッファリングしません。リクエスト開始時に、プレフィックス、制限、要求されたリビジョン、ジョブ ID を記録します。コンシューマーは、すべての kvs をリストに保持するのではなく、一時ストレージにチャンクを書き込みます。
各チャンクは自身の kvs のみを処理します。header、more、count を末尾メタデータとして扱い、ストリームが正常に終了して最終チャンクからそれらが提供された場合にのみ、一時ストレージを完了としてマークします。接続が失敗した場合は、一時出力を破棄または隔離し、同じリビジョンと範囲で再試行することで、不完全なエクスポートがダウンストリームのコンシューマーに届かないようにします。
request:
prefix: /tenant/config/
revision: 0
stream: true
consumer:
process_each_chunk: true
persist_to: temporary_object
publish_only_after_clean_eof: true
max_chunk_bytes: 8388608
failure:
discard_incomplete_output: true
retry_same_revision: true要件に順序付け、リビジョンフィルタ、または gRPC プロキシが含まれている場合、RangeStream がそれらをサポートしているかのように振る舞うことはしません。明示的なメモリと時間の予算を設定してアプリケーション側にその機能を移すか、互換性のある直接エンドポイントを使用するか、クエリを分割します。アップグレードの前に、3.6.11 以降から開始し、障害ドメインごとに1つずつカナリアリリースを行い、エクスポート出力、クライアントの動作、ロールバックを検証します。
よくある間違い
- RangeStream を Watch として扱い、有限の Range 結果ストリームであることを無視する。
- 最初のチャンクから
countまたはheaderを読み取り、誤ったメタデータを報告する。 - ストリーム障害の前に書き込まれた部分的なファイルを公開する。
- RangeStream が順序付け、リビジョンフィルタ、および gRPC プロキシをサポートしていると仮定する。
- クライアントのバージョン、順序、リカバリジョブを検証せずにサーバーをアップグレードする。
優れた回答は、リビジョン境界、チャンクのライフサイクル、末尾メタデータ、障害復旧、API の制限を説明します。「メモリを減らすためにバッチで読み取る」だけでは正しさを証明できません。
フォローアップの質問と回答
各チャンクの count を加算できないのはなぜですか?
公式セマンティクスでは、count は最終チャンクにのみ設定されます。それ以前の値はゼロ値であり、最終値がリクエスト全体を記述します。進捗を把握するには、消費されたキーとバイト数を独自にカウントし、正常完了後に最終メタデータと照合します。
ストリーム障害の前にオブジェクトストレージに書き込まれたデータはどうなりますか?
ジョブ ID と一時プレフィックスの下に書き込みます。正常な EOF と最終メタデータの検証後にのみ、不変バージョンを公開します。失敗したオブジェクトにはクリーンアップまたは調査用のマークを付けます。通常の読み取りパスがそれらを発見してはなりません。
キーによるソートの要件はどのように処理しますか?
RangeStream はカスタムの順序付けをサポートしていません。自然なキー順序で消費し、明示的なメモリ、ディスク、時間の予算を設定して外部マージソートを実行します。サーバー側の順序付けが必須である場合は、偽のオプションを送信するのではなく、それをサポートするクエリパスを使用します。
etcd のアップグレード中にサポートされていないバージョンのスキップを回避するにはどうすればよいですか?
公式ポリシーに従います。パッチのアップグレードはマイナーバージョン内にとどまり、マイナーのアップグレードは1バージョンずつ進めます。3.6 から 3.7 に移行する前に、3.6.11 以降に到達し、クライアントとリカバリジョブのカナリアリリースを行います。