etcd API
このドキュメントでは、etcd v3 APIの中心となる設計の概要を説明します。 etcd v3.5で非推奨となったetcd v2 APIとは異なることに注意してください。 すべてを網羅するものではなく、使用頻度の低いAPI呼び出しに話を広げずに、etcdを理解するために必要な基本的な考え方に焦点を当てます。 etcdのすべてのAPIは、etcdサーバーが処理するリモートプロシージャコール(RPC)を分類したgRPCサービス で定義されています。 etcdのすべてのRPCの完全な一覧は、gRPC API一覧 にMarkdown形式で記載されています。
gRPCサービス
etcdサーバーに送信するすべてのAPIリクエストは、gRPCのリモートプロシージャコールです。etcdのRPCは、機能に基づいてサービスに分類されます。
etcdのキー空間を扱う主要なサービスは、次のとおりです。
- KV - キー・バリューペアを作成、更新、取得、削除します。
- Watch - キーの変更を監視します。
- Lease - クライアントのキープアライブメッセージを処理するプリミティブを提供します。
クラスター自体を管理するサービスは、次のとおりです。
- Auth - ユーザーを認証するための、ロールに基づく認証機構です。
- Cluster - メンバーシップ情報と構成機能を提供します。
- Maintenance - リカバリー用スナップショットの作成、ストアのデフラグメンテーション、メンバーごとの状態情報の取得を行います。
リクエストとレスポンス
etcdのすべてのRPCは同じ形式に従います。各RPCは、NameRequestを引数に取り、NameResponseをレスポンスとして返す関数Nameを持ちます。たとえば、Range RPCの定義は次のとおりです。
レスポンスヘッダー
etcd APIのすべてのレスポンスには、そのレスポンスに関するクラスターのメタデータを含むヘッダーが付属します。
- Cluster_ID - レスポンスを生成したクラスターのIDです。
- Member_ID - レスポンスを生成したメンバーのIDです。
- Revision - レスポンス生成時のキー・バリューストアのリビジョンです。
- Raft_Term - レスポンス生成時のメンバーのRaftの任期です。
アプリケーションは、Cluster_IDまたはMember_IDフィールドを読み取り、意図したクラスター(メンバー)と通信していることを確認できます。
Revisionフィールドから、キー・バリューストアの最新のリビジョンを取得できます。これは、過去のリビジョンを指定してtime travel queryを実行し、リクエスト時点での最新のリビジョンを知りたい場合に特に役立ちます。
Raft_Termを使うと、クラスターが新しいリーダー選挙を完了したことを検出できます。
Key-Value API
Key-Value APIは、etcd内に保存されたキー・バリューペアを操作します。通常、etcdに対するリクエストの大半はキー・バリューのリクエストです。
システムのプリミティブ
キー・バリューペア
キー・バリューペアは、キー・バリューAPIで操作できる最小単位です。各キー・バリューペアは、protobuf形式 で定義された複数のフィールドを持ちます。
- Key - バイト列で表したキーです。空のキーは許可されません。
- Value - バイト列で表した値です。
- Version - キーのバージョンです。削除するとバージョンはゼロにリセットされ、キーを変更するたびにバージョンが増加します。
- Create_Revision - キーが最後に作成されたリビジョンです。
- Mod_Revision - キーが最後に変更されたリビジョンです。
- Lease - キーに関連付けられたリースのIDです。leaseが0の場合、キーにリースは関連付けられていません。
etcdは、キーと値に加え、キーのメッセージの一部としてリビジョンのメタデータも付与します。このリビジョン情報は、作成時刻と変更時刻によってキーに順序を付け、分散同期のための並行処理制御に役立ちます。etcdクライアントの分散共有ロック は、作成リビジョンを使ってロックの所有権を待ちます。同様に、変更リビジョンは、ソフトウェアトランザクショナルメモリー の読み取り集合の競合の検出や、リーダー選挙 の更新の待機に使用します。
リビジョン
etcdは、キー空間が変更されるたびに増加する、クラスター全体の64ビットカウンターであるストアリビジョンを保持します。リビジョンはグローバルな論理時計として機能し、ストアへのすべての更新を順序付けます。新しいリビジョンが表す変更は差分です。リビジョンに関連付けられるデータは、ストアを変更したデータです。内部的には、新しいリビジョンとは、増加したリビジョンをキーとして、バックエンドのB+treeに変更を書き込むことを意味します。
etcdの多版型同時実行制御 バックエンドを考えると、リビジョンの有用性がさらに分かります。MVCCモデルでは、過去のキーのリビジョンを保持するため、キー・バリューストアを過去のリビジョンの状態で参照できます。クラスター管理者は、この履歴の保持ポリシーを設定して、ストレージを細かく管理できます。通常、etcdはタイマーによってキーの古いリビジョンを破棄します。一般的なetcdクラスターは、更新によって古くなったキーのデータを数時間保持します。これにより、一時的なネットワーク障害だけでなく、クライアントの長時間の切断にも確実に対処できます。ウォッチャーは、最後に観測した過去のリビジョンから再開するだけです。同様に、特定の時点のストアを読み取るには、読み取りリクエストにリビジョンを指定すると、そのリビジョンがコミットされた時点のキー空間の状態からキーを返せます。
キー範囲
etcdのデータモデルは、平坦なバイナリーキー空間上のすべてのキーにインデックスを付けます。これは、キーをディレクトリにまとめる階層構造を使う他のキー・バリューストアとは異なります。キーはディレクトリ単位ではなく、キーの区間[a, b)で列挙します。
etcdでは、この区間を「範囲」と呼ぶことがよくあります。範囲に対する操作は、ディレクトリに対する操作より表現力があります。階層型ストアと同様に、[a, a+1)による単一キーの検索(例:[‘a’, ‘a\x00’)は’a’を検索)や、ディレクトリの深さに従ってキーをエンコードすることによるディレクトリ検索をサポートします。さらに、区間では接頭辞も表せます。たとえば、区間['a', 'b')は、文字列’a’を接頭辞に持つすべてのキーを検索します。
慣例として、リクエストの範囲はkeyとrange_endフィールドで表します。keyフィールドは範囲の最初のキーで、空にしないでください。range_endは、範囲の最後のキーの次のキーです。range_endが指定されていないか空の場合、範囲にはkey引数だけが含まれます。range_endがkeyに1を加えたもの(例:“aa”+1 == “ab”、“a\xff”+1 == “b”)の場合、その範囲はkeyを接頭辞に持つすべてのキーを表します。keyとrange_endの両方が’\0’の場合、その範囲はすべてのキーを表します。range_endが’\0’の場合、その範囲はkey引数以上のすべてのキーを表します。
Range
RangeRequestを受け取るRange API呼び出しで、キー・バリューストアからキーを取得します。
- Key, Range_End - 取得するキー範囲です。
- Limit - リクエストで返すキーの最大数です。limitを0に設定すると、上限なしとして扱います。
- Revision - 範囲の取得に使用するキー・バリューストアの時点です。revisionがゼロ以下の場合、最新のキー・バリューストアを対象とします。リビジョンがすでにコンパクションされている場合、レスポンスとしてErrCompactedを返します。
- Sort_Order - ソートするリクエストの順序です。
- Sort_Target - ソート対象のキー・バリューのフィールドです。
- Serializable - 範囲リクエストで、メンバーローカルの直列化可能読み取りを使用するように設定します。Rangeはデフォルトで線形化可能であり、クラスターの現在のコンセンサスを反映します。性能と可用性を高めるため、直列化可能な範囲リクエストは、古いデータを読み取る可能性と引き換えに、クラスター内の他のノードとのコンセンサスを必要とせず、ローカルに処理されます。
- Keys_Only - 値を返さず、キーだけを返します。
- Count_Only - 範囲内のキーの数だけを返します。
- Min_Mod_Revision - キーの変更リビジョンの下限です。それより小さい変更リビジョンを除外します。
- Max_Mod_Revision - キーの変更リビジョンの上限です。それより大きい変更リビジョンを除外します。
- Min_Create_Revision - キーの作成リビジョンの下限です。それより小さい作成リビジョンを除外します。
- Max_Create_Revision - キーの作成リビジョンの上限です。それより大きい作成リビジョンを除外します。
クライアントは、Range呼び出しからRangeResponseメッセージを受信します。
- Kvs - 範囲リクエストに一致するキー・バリューペアの一覧です。
Count_Onlyを設定すると、Kvsは空になります。 - More -
limitが設定されている場合、要求した範囲内に返すべきキーがまだあるかどうかを示します。 - Count - 範囲リクエストを満たすキーの総数です。
キー範囲が大きく、レスポンス全体をバッファーに保持したくない場合は、RangeStream を参照してください。
RangeStream
RangeStreamはRangeと同じ結果セットを返しますが、サーバーがレスポンスを一連のチャンクに分割し、クライアントへストリーミングします。これにより、サーバーとクライアントのどちらも、大きな範囲全体をメモリーに保持する必要がなくなります。RangeStreamは、Rangeと同じRangeRequestを受け付けます。
クライアントは、RangeStream呼び出しからRangeStreamResponseメッセージのストリームを受信します。
各チャンクのフィールドは、次のように設定されます。
- Kvs - 各チャンクは、結果の重複しない一部分を保持します。すべてのチャンクの
kvsを到着順に連結すると、1回のRange呼び出しと同じキー集合が得られます。 - Header, More, Count - ストリームがエラーなく完了した場合に限り、最後のチャンクにだけ設定されます。それより前のチャンクでは、これらのフィールドはゼロ値のままです。各チャンクの
range_responseにproto.Mergeを適用すると、Rangeが返すものと同等のRangeResponseが得られます。
ストリームがエラーで終了した場合、有効なheader、more、countを持つチャンクはありません。
ストリーム内のすべてのチャンクは、同じリビジョンを対象に処理されます。リクエストにRevisionが設定されていない場合、サーバーはストリームの開始時に最新のコミット済みリビジョンを取得し、残りのストリームでも同じリビジョンを使います。
RangeStreamは、独自のソート順序やリビジョンフィルター(min_mod_revision、max_mod_revision、min_create_revision、max_create_revision)をサポートしません。どちらかを使用したリクエストは、Unimplementedを返します。etcdのgRPCプロキシもRangeStreamをサポートしません。
RangeStreamを処理する一般的な方法は、次の2つです。
- 各チャンクを個別に処理する。 結果全体を集める前に、キーが届くたびにデコードして処理したい、高い性能が求められる場面に適しています。クライアントはチャンクを順に読み、各チャンクの
kvsを処理します。ストリームが正常に終了した後、最後のチャンクからheader、more、countを読み取ります。 - 単一のレスポンスにまとめる。 単項の
Rangeと同等の結果が必要な場合に適しています。クライアントは、各チャンクのrange_responseを、たとえばproto.Mergeで1つのRangeResponseにマージします。マージ後の結果には、すべてのkvsと、最後のチャンクのheader、more、countが含まれます。Goクライアントは、この処理を補助するclientv3.GetStreamToGetResponseを提供します。
Put
PutRequestを受け取るPut呼び出しで、キー・バリューストアにキーを保存します。
- Key - キー・バリューストアに格納するキーの名前です。
- Value - キー・バリューストア内のキーに関連付ける、バイト列の値です。
- Lease - キー・バリューストア内のキーに関連付けるリースIDです。leaseが0の場合、リースがないことを示します。
- Prev_Kv - 設定されている場合、この
Putリクエストによる更新前のキー・バリューペアのデータを返します。 - Ignore_Value - 設定されている場合、現在の値を変更せずにキーを更新します。キーが存在しない場合はエラーを返します。
- Ignore_Lease - 設定されている場合、現在のリースを変更せずにキーを更新します。キーが存在しない場合はエラーを返します。
クライアントは、Put呼び出しからPutResponseメッセージを受信します。
- Prev_Kv -
PutRequestでPrev_Kvを設定していた場合、Putによって上書きされたキー・バリューペアです。
範囲の削除
DeleteRangeRequestを受け取るDeleteRange呼び出しで、キーの範囲を削除します。
- Key, Range_End - 削除するキー範囲です。
- Prev_Kv - 設定されている場合、削除したキー・バリューペアの内容を返します。
クライアントは、DeleteRange呼び出しからDeleteRangeResponseメッセージを受信します。
- Deleted - 削除したキーの数です。
- Prev_Kv -
DeleteRange操作で削除したすべてのキー・バリューペアの一覧です。
トランザクション
トランザクションは、キー・バリューストア上のアトミックなIf/Then/Else構造です。リクエストをアトミックなブロック(then/else)にまとめ、キー・バリューストアの内容に基づいて実行条件(if)を設定するプリミティブを提供します。トランザクションは、意図しない並行更新からキーを保護すること、比較交換操作を構築すること、より高度な並行処理制御を開発することに使用できます。
トランザクションは、1つのリクエスト内で複数のリクエストをアトミックに処理できます。キー・バリューストアの変更では、そのトランザクションによってストアのリビジョンが増加するのは1回だけで、生成されるすべてのイベントが同じリビジョンを持つことを意味します。ただし、1つのトランザクション内で同じキーを複数回変更することは禁止されています。
すべてのトランザクションには、If文のように、複数の比較の論理積による実行条件があります。各比較は、ストア内の1つのキーを検査します。値の有無、指定した値との比較、キーのリビジョンやバージョンを確認できます。異なる2つの比較は、同じキーにも異なるキーにも適用できます。すべての比較はアトミックに適用されます。すべてがtrueの場合、トランザクションは成功とされ、etcdはthen / successリクエストブロックを適用します。それ以外は失敗とされ、else / failureリクエストブロックを適用します。
各比較は、Compareメッセージとしてエンコードされます。
- Result - 論理比較演算の種類です(等しい、より小さい、など)。
- Target - 比較するキー・バリューのフィールドです。キーのバージョン、作成リビジョン、変更リビジョン、値のいずれかです。
- Key - 比較対象のキーです。
- Target_Union - 比較のためにユーザーが指定するデータです。
比較ブロックを処理した後、トランザクションはリクエストのブロックを適用します。ブロックは、RequestOpメッセージのリストです。
- Request_Range -
RangeRequestです。 - Request_Put -
PutRequestです。キーは一意でなければなりません。他のPutsやDeletesとキーが重複してはいけません。 - Request_Delete_Range -
DeleteRangeRequestです。PutsやDeletesのリクエストとキーが重複してはいけません。
以上をまとめ、TxnRequestを受け取るTxn API呼び出しでトランザクションを発行します。
- Compare - トランザクションの実行条件となる、条件の論理積を表す述語のリストです。
- Success - すべての比較の評価結果がtrueの場合に処理するリクエストのリストです。
- Failure - いずれかの比較の評価結果がfalseの場合に処理するリクエストのリストです。
クライアントは、Txn呼び出しからTxnResponseメッセージを受信します。
- Succeeded -
Compareの評価結果がtrueかfalseかを示します。 - Responses - succeededがtrueの場合は
Successブロック、falseの場合はFailureを適用した結果に対応するレスポンスのリストです。
Responsesリストは、適用したRequestOpリストの結果に対応し、各レスポンスはResponseOpとしてエンコードされます。
内部の各レスポンスに含まれるResponseHeaderは、どのような用途でも解釈しないでください。
最新のリビジョンを取得する必要がある場合、クライアントは常にTxnResponseの最上位のResponseHeaderを確認してください。
Watch API
Watch APIは、キーの変更を非同期に監視する、イベントに基づくインターフェースを提供します。etcdの監視は、現在または過去の指定したリビジョンから継続的に監視してキーの変更を待ち、キーの更新をクライアントへストリーミングします。
イベント
すべてのキーの各変更は、Eventメッセージで表されます。Eventメッセージは、更新データと更新の種類を提供します。
- Type - イベントの種類です。PUTは、キーに新しいデータが保存されたことを示します。DELETEは、キーが削除されたことを示します。
- KV - イベントに関連付けられたKeyValueです。PUTイベントは現在のkvペアを含みます。kv.Version=1のPUTイベントは、キーが作成されたことを示します。DELETEイベントは、変更リビジョンが削除時のリビジョンに設定された、削除済みのキーを含みます。
- Prev_KV - イベント直前のリビジョンにおける、そのキーのキー・バリューペアです。帯域幅を節約するため、監視で明示的に有効にした場合にだけ設定されます。
監視ストリーム
監視は長時間継続するリクエストであり、gRPCストリームでイベントデータをストリーミングします。監視ストリームは双方向です。クライアントはストリームに書き込んで監視を設定し、ストリームから読み取って監視イベントを受信します。イベントに監視ごとの識別子を付けることで、1つの監視ストリームに多数の異なる監視を多重化できます。この多重化によって、中核のetcdクラスターのメモリー使用量と接続の負担を減らせます。
監視イベントに関する保証については、etcd APIの保証 を参照してください。
クライアントは、Watchが返したストリームでWatchCreateRequestを送信して、監視を作成します。
- Key, Range_End - 監視するキー範囲です。
- Start_Revision - 監視を開始するリビジョン(そのリビジョンを含む)で、省略可能です。指定しない場合、監視作成レスポンスのヘッダーにあるリビジョンの次からイベントをストリーミングします。最後のコンパクションリビジョンから、利用可能なイベント履歴全体を監視できます。
- Progress_Notify - 設定されている場合、最近のイベントがなければ、監視はイベントを含まないWatchResponseを定期的に受信します。これは、切断されたウォッチャーを、最近の既知のリビジョンから復旧したい場合に役立ちます。通知の送信頻度は、etcdサーバーが現在の負荷に基づいて決定します。
- Filters - サーバー側で除外するイベントの種類のリストです。
- Prev_Kv - 設定されている場合、監視はイベント発生前のキー・バリューデータを受信します。上書きされたデータの確認に役立ちます。
クライアントは、WatchCreateRequestへの応答として、または既存の監視で新しいイベントが発生した場合に、WatchResponseを受信します。
- Watch_ID - レスポンスに対応する監視のIDです。
- Created - 監視作成リクエストへのレスポンスである場合にtrueに設定されます。クライアントはIDを保存し、そのストリームで監視イベントを受信するようにしてください。作成したウォッチャーへ送信されるすべてのイベントは、同じwatch_idを持ちます。
- Canceled - 監視キャンセルリクエストへのレスポンスである場合にtrueに設定されます。キャンセルされたウォッチャーには、それ以降のイベントは送信されません。
- Compact_Revision - ウォッチャーがコンパクション済みリビジョンで監視しようとすると、etcdで利用可能な最小の過去のリビジョンに設定されます。これは、コンパクション済みリビジョンでウォッチャーを作成した場合や、ウォッチャーがキー・バリューストアの進行に追いつけない場合に発生します。ウォッチャーはキャンセルされます。同じstart_revisionで新しい監視を作成しても失敗します。
- Events - 指定した監視IDに対応する、新しいイベントを順に並べたリストです。
クライアントが監視イベントの受信を停止するには、WatchCancelRequestを発行します。
- Watch_ID - これ以上イベントを送信しないようキャンセルする監視のIDです。
Lease API
リースは、クライアントの生存を検出する仕組みです。クラスターは、生存時間付きのリースを付与します。指定したTTL期間内にetcdクラスターがkeepAliveを受信しなければ、リースは期限切れになります。
リースとキー・バリューストアを結び付けるため、各キーには最大1つのリースを関連付けられます。リースが期限切れになるか取り消されると、そのリースに関連付けられたすべてのキーが削除されます。期限切れになった各キーは、イベント履歴に削除イベントを生成します。
リースの取得
LeaseGrantRequestを受け取るLeaseGrant API呼び出しで、リースを取得します。
- TTL - 秒単位の希望する生存時間です。
- ID - リースに要求するIDです。IDを0に設定すると、etcdがIDを選択します。
クライアントは、LeaseGrant呼び出しからLeaseGrantResponseを受信します。
- ID - 付与されたリースのIDです。
- TTL - サーバーが選択した、秒単位のリースの生存時間です。
- ID - 取り消すリースのIDです。リースを取り消すと、関連付けられたすべてのキーが削除されます。
キープアライブ
リースは、LeaseKeepAlive API呼び出しで作成した双方向ストリームで更新します。クライアントがリースを更新するときは、ストリームでLeaseKeepAliveRequestを送信します。
- ID - 維持するリースのIDです。
キープアライブストリームは、LeaseKeepAliveResponseで応答します。
- ID - 新しいTTLで更新されたリースです。
- TTL - リースに残された、秒単位の新しい生存時間です。