XNUMX 人の孊生ず XNUMX ぀の分散 Key-Value ストア

たたは、ZooKeeper、etcd、Consul KV 甚のクラむアント C++ ラむブラリをどのように䜜成したか

分散システムの䞖界では、クラスタヌの構成に関する情報の保存、ノヌド構成の管理、障害のあるノヌドの怜出、リヌダヌの遞択などの兞型的なタスクが倚数ありたす。 その他。 これらの問題を解決するために、特別な分散システム、぀たり調敎サヌビスが䜜成されたした。 ここで、そのうちの XNUMX ぀、ZooKeeper、etcd、Consul に興味を持ちたす。 Consul の豊富な機胜のうち、Consul KV に焊点を圓おたす。

XNUMX 人の孊生ず XNUMX ぀の分散 Key-Value ストア

本質的に、これらすべおのシステムはフォヌルトトレラントで線圢化可胜なキヌ/倀ストアです。 䞡者のデヌタ モデルには倧きな違いがありたすが、これに぀いおは埌ほど説明したすが、実際䞊は同じ問題を解決したす。 明らかに、調敎サヌビスを䜿甚する各アプリケヌションはいずれかのアプリケヌションに関連付けられおいるため、異なるアプリケヌションで同じ問題を解決する耇数のシステムを XNUMX ぀のデヌタ センタヌでサポヌトする必芁が生じる可胜性がありたす。

この問題を解決するずいうアむデアはオヌストラリアのコンサルティング䌚瀟から生たれ、それを実行するのは私たち孊生の小さなチヌムでした。それがこれからお話しするこずです。

私たちは、ZooKeeper、etcd、Consul KV を操䜜するための共通むンタヌフェむスを提䟛するラむブラリを䜜成するこずができたした。 このラむブラリは C++ で曞かれおいたすが、他の蚀語に移怍する蚈画もありたす。

デヌタモデル

XNUMX ぀の異なるシステムに共通のむンタヌフェむスを開発するには、それらのシステムの共通点ず盞違点を理解する必芁がありたす。 それを理解したしょう。

飌育係

XNUMX 人の孊生ず XNUMX ぀の分散 Key-Value ストア

キヌはツリヌに線成され、ノヌドず呌ばれたす。 したがっお、ノヌドに぀いおは、その子のリストを取埗できたす。 znode の䜜成 (create) ず倀の倉曎 (setData) の操䜜は分離されおおり、既存のキヌのみを読み取り、倉曎できたす。 りォッチは、ノヌドの存圚の確認、倀の読み取り、および子の取埗の操䜜にアタッチできたす。 Watch は、サヌバヌ䞊の察応するデヌタのバヌゞョンが倉曎されたずきに起動される XNUMX 回限りのトリガヌです。 䞀時ノヌドは障害を怜出するために䜿甚されたす。 これらは、それらを䜜成したクラむアントのセッションに関連付けられたす。 クラむアントがセッションを閉じるか、ZooKeeper ぞの存圚の通知を停止するず、これらのノヌドは自動的に削陀されたす。 単玔なトランザクションがサポヌトされおいたす。これは、すべおが成功するか、少なくずも XNUMX ぀が䞍可胜な堎合は倱敗する䞀連の操䜜です。

etcd

XNUMX 人の孊生ず XNUMX ぀の分散 Key-Value ストア

このシステムの開発者は明らかに ZooKeeper に觊発されおおり、したがっおすべおが異なる方法で行われたした。 キヌには階局はありたせんが、蟞曞順に䞊べられたセットを圢成したす。 特定の範囲に属するすべおのキヌを取埗たたは削陀できたす。 この構造は奇劙に芋えるかもしれたせんが、実際には非垞に衚珟力豊かで、階局ビュヌをそれを通じお簡単に゚ミュレヌトできたす。

etcd には暙準の比范および蚭定操䜜はありたせんが、トランザクションずいう優れた操䜜がありたす。 もちろん、これらは 3.3 ぀のシステムすべおに存圚したすが、etcd トランザクションは特に優れおいたす。 これらは、チェック、成功、倱敗の XNUMX ぀のブロックで構成されたす。 最初のブロックには䞀連の条件が含たれ、XNUMX 番目ず XNUMX 番目のブロックには操䜜が含たれたす。 トランザクションはアトミックに実行されたす。 すべおの条件が true の堎合は成功ブロックが実行され、それ以倖の堎合は倱敗ブロックが実行されたす。 API XNUMX では、成功ブロックず倱敗ブロックにネストされたトランザクションを含めるこずができたす。 ぀たり、ほが任意の入れ子レベルの条件構造をアトミックに実行するこずが可胜です。 どのようなチェックず操䜜が存圚するかに぀いお詳しくは、 ドキュメンテヌション.

ここにも時蚈が存圚したすが、少し耇雑で再利甚可胜です。 ぀たり、キヌ範囲にりォッチをむンストヌルした埌は、最初のアップデヌトだけでなく、りォッチをキャンセルするたで、この範囲内のすべおのアップデヌトを受信したす。 etcd では、ZooKeeper クラむアント セッションに盞圓するものはリヌスです。

領事K.V.

ここにも厳密な階局構造はありたせんが、Consul は階局構造が存圚するように芋せるこずができたす。぀たり、指定されたプレフィックスを持぀すべおのキヌを取埗および削陀できたす。぀たり、キヌの「サブツリヌ」を操䜜できたす。 このようなク゚リは再垰的ず呌ばれたす。 さらに、Consul は、接頭蟞の埌に指定された文字を含たないキヌのみを遞択できたす。これは、盎接の「子」を取埗するこずに盞圓したす。 しかし、これはたさに階局構造の倖芳であるこずを芚えおおく䟡倀がありたす。芪が存圚しない堎合にキヌを䜜成したり、子がシステムに保存され続けおいる間に子を持぀キヌを削陀したりするこずは十分に可胜です。

XNUMX 人の孊生ず XNUMX ぀の分散 Key-Value ストア
Consul は監芖の代わりに、HTTP リク゚ストをブロックしたす。 本質的に、これらはデヌタ読み取りメ゜ッドぞの通垞の呌び出しであり、他のパラメヌタヌずずもに、デヌタの既知の最埌のバヌゞョンが瀺されたす。 サヌバヌ䞊の察応するデヌタの珟圚のバヌゞョンが指定されたバヌゞョンよりも倧きい堎合は、応答がすぐに返されたす。それ以倖の堎合は、倀が倉曎されたずきに応答が返されたす。 い぀でもキヌにアタッチできるセッションもありたす。 セッションを削陀するず関連付けられたキヌも削陀される etcd や ZooKeeper ずは異なり、セッションを単玔にキヌからリンク解陀するモヌドがあるこずに泚意しおください。 利甚可胜 トランザクション、分岐はありたせんが、あらゆる皮類のチェックがありたす。

すべおを䞀緒に入れお

ZooKeeper には最も厳密なデヌタ モデルがありたす。 etcd で䜿甚できる衚珟力豊かな範囲ク゚リは、ZooKeeper や Consul では効果的に゚ミュレヌトできたせん。 すべおのサヌビスの最良のものを組み蟌もうずした結果、次の重芁な䟋倖を陀いお、ZooKeeper むンタヌフェむスずほが同等のむンタヌフェむスが完成したした。

  • シヌケンス、コンテナ、TTL ノヌド サポヌトされおいたせん
  • ACLはサポヌトされおいたせん
  • set メ゜ッドは、キヌが存圚しない堎合にキヌを䜜成したす (ZK では、この堎合 setData ぱラヌを返したす)。
  • set メ゜ッドず cas メ゜ッドは分離されおいたす (ZK では本質的に同じものです)
  • Erase メ゜ッドは、ノヌドをそのサブツリヌずずもに削陀したす (ZK では、ノヌドに子がある堎合、delete ぱラヌを返したす)。
  • 各キヌにはバヌゞョンが XNUMX ぀だけありたす - 倀バヌゞョン (ZK では それらのXNUMX぀がありたす)

シヌケンシャル ノヌドが拒吊されるのは、etcd ず Consul にシヌケンシャル ノヌドのサポヌトが組み蟌たれおおらず、結果ずしお埗られるラむブラリ むンタヌフェむス䞊にナヌザヌが簡単に実装できるためです。

頂点を削陀するずきに ZooKeeper ず同様の動䜜を実装するには、etcd ず Consul でキヌごずに個別の子カりンタヌを維持する必芁がありたす。 メタ情報の保存を避けようずしたため、サブツリヌ党䜓を削陀するこずにしたした。

実装の埮劙な点

さたざたなシステムでのラむブラリ むンタヌフェむスの実装のいく぀かの偎面を詳しく芋おみたしょう。

etcd の階局

etcd で階局ビュヌを維持するこずは、最も興味深いタスクの XNUMX ぀であるこずが刀明したした。 範囲ク゚リを䜿甚するず、指定されたプレフィックスを持぀キヌのリストを簡単に取埗できたす。 たずえば、で始たるすべおのものが必芁な堎合、 "/foo"、範囲を求めおいたす ["/foo", "/fop")。 ただし、これではキヌのサブツリヌ党䜓が返されるため、サブツリヌが倧きい堎合には受け入れられない可胜性がありたす。 圓初はキヌ倉換メカニズムを䜿甚する予定でしたが、 zetcdで実装。 これには、キヌの先頭に、ツリヌ内のノヌドの深さに等しい XNUMX バむトが远加されたす。 䟋を挙げおみたしょう。

"/foo" -> "u01/foo"
"/foo/bar" -> "u02/foo/bar"

次に、キヌの盎接の子をすべお取埗したす "/foo" 範囲をリク゚ストするこずで可胜 ["u02/foo/", "u02/foo0")。 はい、ASCII で "0" 盎埌に立぀ "/".

しかし、この堎合、頂点の削陀をどのように実装すればよいでしょうか? 型のすべおの範囲を削陀する必芁があるこずがわかりたした。 ["uXX/foo/", "uXX/foo0") XXの堎合は01からFFたで。 そしお、私たちは遭遇したした 操䜜回数制限 XNUMX 回のトランザクション内で。

その結果、単玔なキヌ倉換システムが発明され、キヌの削陀ず子のリストの取埗の䞡方を効果的に実装できるようになりたした。 最埌のトヌクンの前に特殊文字を远加するだけで十分です。 䟋えば

"/very" -> "/u00very"
"/very/long" -> "/very/u00long"
"/very/long/path" -> "/very/long/u00path"

次にキヌを削陀したす "/very" 削陀に倉わりたす "/u00very" そしお範囲 ["/very/", "/very0")、およびすべおの子を取埗したす - 範囲からのキヌのリク゚ストで ["/very/u00", "/very/u01").

ZooKeeper でのキヌの削陀

すでに述べたように、ZooKeeper では、ノヌドに子がある堎合はノヌドを削陀できたせん。 キヌをサブツリヌずずもに削陀したいず考えおいたす。 どうすればいいですか 私たちはこれを楜芳的に行っおいたす。 たず、サブツリヌを再垰的に走査し、個別のク゚リで各頂点の子を取埗したす。 次に、サブツリヌのすべおのノヌドを正しい順序で削陀しようずするトランザクションを構築したす。 もちろん、サブツリヌの読み取りず削陀の間に倉曎が発生する可胜性がありたす。 この堎合、トランザクションは倱敗したす。 さらに、サブツリヌは読み取りプロセス䞭に倉曎される可胜性がありたす。 たずえば、このノヌドがすでに削陀されおいる堎合、次のノヌドの子に察するリク゚ストぱラヌを返す可胜性がありたす。 どちらの堎合も、プロセス党䜓をもう䞀床繰り返したす。

このアプロヌチでは、キヌに子がある堎合、キヌの削陀は非垞に効果的ではなくなりたす。たた、アプリケヌションがキヌの削陀ず䜜成を行っおサブツリヌを操䜜し続ける堎合は、さらに効果が䜎くなりたす。 ただし、これにより、etcd および Consul での他のメ゜ッドの実装が耇雑になるこずを回避できたした。

ZooKeeper に蚭定

ZooKeeper には、ツリヌ構造を操䜜するメ゜ッド (create、delete、getChildren) ず、ノヌド内のデヌタを操䜜するメ゜ッド (setData、getData) が別々にありたす。さらに、すべおのメ゜ッドには厳密な前提条件がありたす。ノヌドがすでに䜜成されおいる堎合、create ぱラヌを返したす。デヌタがただ存圚しない堎合は、䜜成、削陀、たたは setData したす。 キヌの存圚を意識せずに呌び出せる set メ゜ッドが必芁でした。

XNUMX ぀のオプションは、削陀ず同様に楜芳的なアプロヌチを取るこずです。 ノヌドが存圚するかどうかを確認したす。 存圚する堎合は setData を呌び出し、存圚しない堎合は䜜成したす。 最埌のメ゜ッドで゚ラヌが返された堎合は、もう䞀床最初から繰り返したす。 たず泚意すべきこずは、存圚テストは無意味であるずいうこずです。 すぐに create を呌び出すこずができたす。 正垞に完了した堎合は、ノヌドが存圚せずに䜜成されたこずを意味したす。 それ以倖の堎合、create は適切な゚ラヌを返したす。その埌、setData を呌び出す必芁がありたす。 もちろん、呌び出しの間に、競合する呌び出しによっお頂点が削陀される可胜性があり、setData も゚ラヌを返したす。 この堎合、最初からやり盎すこずもできたすが、それだけの䟡倀はありたすか?

䞡方のメ゜ッドが゚ラヌを返した堎合、競合する削陀が行われたこずが確実にわかりたす。 set を呌び出した埌にこの削陀が行われたず想像しおみたしょう。 そのずき、私たちが確立しようずしおいる意味はすでに消去されおいたす。 これは、実際には䜕も曞き蟌たれおいなくおも、set が正垞に実行されたず想定できるこずを意味したす。

技術的な詳现

このセクションでは、分散システムから離れお、コヌディングに぀いお説明したす。
お客様の䞻な芁件の XNUMX ぀はクロスプラットフォヌムでした。぀たり、サヌビスの少なくずも XNUMX ぀が Linux、MacOS、および Windows でサポヌトされおいる必芁がありたす。 圓初は Linux 向けにのみ開発し、その埌他のシステムでもテストを開始したした。 これにより倚くの問題が発生したしたが、しばらくの間、どのように察凊すればよいのかたったくわかりたせんでした。 その結果、XNUMX ぀の調敎サヌビスはすべお Linux および MacOS でサポヌトされるようになりたしたが、Windows では Consul KV のみがサポヌトされおいたす。

私たちは最初から、サヌビスにアクセスするために既補のラむブラリを䜿甚しようずしたした。 ZooKeeper の堎合、遞択は次のずおりでした。 ズヌキヌパヌ C++、最終的には Windows でコンパむルできたせんでした。 ただし、これは驚くべきこずではありたせん。このラむブラリは Linux 専甚ずしお䜍眮付けられおいたす。 領事にずっお唯䞀の遞択肢は ppconsul。 サポヌトを远加する必芁がありたした セッション О トランザクション。 etcd の堎合、最新バヌゞョンのプロトコルをサポヌトする本栌的なラむブラリが芋぀からなかったため、単に 生成された grpc クラむアント.

ZooKeeper C++ ラむブラリの非同期むンタヌフェむスからむンスピレヌションを埗お、非同期むンタヌフェむスも実装するこずにしたした。 ZooKeeper C++ は、これに future/promise プリミティブを䜿甚したす。 残念ながら、STL では、これらは非垞に控えめに実装されおいたす。 たずえば、いいえ その埌メ゜ッド、枡された関数を将来の結果が䜿甚可胜になったずきに適甚したす。 私たちの堎合、そのようなメ゜ッドは結果をラむブラリの圢匏に倉換するために必芁です。 この問題を回避するには、顧客の芁求により Boost などの重いサヌドパヌティ ラむブラリを䜿甚できなかったため、独自の単玔なスレッド プヌルを実装する必芁がありたした。

then の実装は次のように機胜したす。 呌び出されるず、远加の Promise/Future ペアが䜜成されたす。 新しい Future が返され、枡された Future は、察応する関数および远加の Promise ずずもにキュヌに配眮されたす。 プヌルのスレッドはキュヌからいく぀かの先物を遞択し、wait_for を䜿甚しおそれらをポヌリングしたす。 結果が利甚可胜になるず、察応する関数が呌び出され、その戻り倀が Promise に枡されたす。

etcd ず Consul ぞのク゚リを実行するために同じスレッド プヌルを䜿甚したした。 これは、基瀎ずなるラむブラリが耇数の異なるスレッドからアクセスできるこずを意味したす。 ppconsul はスレッドセヌフではないため、ppconsul ぞの呌び出しはロックによっお保護されたす。
grpc は耇数のスレッドから操䜜できたすが、埮劙な点がありたす。 etcd では、監芖は grpc ストリヌム経由で実装されたす。 これらは、特定の皮類のメッセヌゞ甚の双方向チャネルです。 ラむブラリは、すべおの監芖に察しお XNUMX ぀のスレッドず、受信メッセヌゞを凊理する XNUMX ぀のスレッドを䜜成したす。 したがっお、grpc はストリヌムぞの䞊列曞き蟌みを犁止したす。 ぀たり、りォッチを初期化たたは削陀する堎合は、前のリク゚ストの送信が完了するたで埅っおから、次のリク゚ストを送信する必芁がありたす。 同期に䜿甚したす 条件倉数.

合蚈

自分自身を参照しおください liboffkv.

私たちのチヌム レむド・ロマノフ, むワン・グルシェンコフ, ドミトリヌ・カマルディノフ, ノィクトル・クラピベンスキヌ, ノィタリヌ・むワニン.

出所 habr.com

コメントを远加したす