etcdと分散ロックに関する記事

etcdと分散ロックに関する記事

[[400328]]

1. 分散ロックを実装するためのコンポーネント

分散システムでは、分散ロックを実装するために一般的に使用されるコンポーネントは、Redis、Zookeeper、etcd です。それぞれの特徴を比較すると次のようになります。

上の図は3つのコンポーネントの特性を示しています。その中でも、分散ロックにとって最も重要な点は CP 要件です。ただし、Redis クラスターは CP をサポートしていませんが、AP をサポートしています。公式の redlock ソリューションも提供されていますが、複数のインスタンスの展開 (インスタンスの半分以上が成功と見なされる) が必要なため、展開とメンテナンスが比較的複雑です。したがって、一貫性要件が高いビジネス シナリオ (電子商取引、銀行支払い) では、通常、zookeeper または etcd が選択されます。パフォーマンス、同時実行性、メンテナンスコストを考慮して、Zookeeper と etcd を比較します。 etcd は Go 言語で開発されているため、バイナリ実行ファイルに直接コンパイルされ、他のものに依存しないという利点があります。この記事では、etcd を取り上げ、特定の観点について説明します。

2. APが分散ロックに適さない理由

CAP 理論では、分散システムにおけるマルチノード通信は必然的にネットワーク遅延、パケット損失などの問題につながるため、ネットワーク パーティションが必然的に発生します。ネットワーク分割が発生した場合、通常は CP または AP の 2 つのオプションがあります。

① 分散ロックを実装するために AP モデルを選択した場合、クライアントはクラスターマスターノードのロックに成功した後、すぐにロック成功のフィードバックを受け取ります。このとき、マスター ノードがスレーブ ノードにデータを同期する前にダウンした場合、システムはスレーブ ノードからノードを新しいマスター ノードとして選択します。新しいマスター ノードには古いマスター ノードに対応するロック データがないため、他のクライアントが新しいマスター ノードで同じロックを取得できるようになります。このとき、複数のプロセス/スレッド/コルーチンが同じ重要なリソース データを操作するため、データの不整合などの問題が発生します。

②分散ロックを実装するためにCPモデルを選択します。マスター ノードがデータをスレーブ ノードの半分以上に同期した後にのみ、ロックが成功したと見なされます。このとき、何らかの理由でマスターノードがダウンした場合、システムはデータ損失などの問題を回避するために、スレーブノードからより新しいデータを持つスレーブノードを新しいマスターノードとして選択します。

したがって、分散ロックの場合、データに強力な一貫性要件が課されるシナリオでは、AP モデルは適切な選択ではありません。少量のデータ損失を許容できる場合は、メンテナンス コストなどの理由から、AP モデルの Redis が優先される場合があります。

3. 分散ロックの特徴と動作

分散ロックの場合、操作には次のものが含まれます。

  1. ロックを取得
  2. ロックを解除
  3. ビジネス処理中に、ロックを更新するために別のスレッド/コルーチンが開始されます。

4. etcdについて

公式ドキュメントは常に最高の学習教材です。 etcd の公式紹介には次のように書かれています:

  • 分散システムでは、構成管理、サービス検出、分散作業の調整のための一貫したキー値ストアとして etcd を使用します。多くの組織では、コンテナ スケジューラ、サービス検出サービス、分散データ ストアなどの運用システムを実装するために etcd を使用しています。 etcd を使用する一般的な分散パターンには、リーダー選出、分散ロック、マシン アクティビティの監視などがあります。
  • 分散システムでは、構成管理、サービス検出、分散作業の調整のための一貫したキー値ストアとして etcd を使用します。多くの組織では、コンテナ スケジューラ、サービス検出サービス、分散データ ストレージなどの実稼働システムを実装するために etcd を使用しています。 etcd を使用する一般的な分散パターンには、リーダー選出、分散ロック、マシンの活性状態の監視などがあります。
  • https://etcd.io/docs/v3.4/learning/why/

分散ロックは、etcd が実現できる多くの機能のうちの 1 つにすぎません。サービス登録と検出は、etcd でより多く使用されます。

当局者はまた、多くのコンポーネントを比較し、次のように分類しました。

比較してみると、それぞれの特徴が分かります。どちらを選択するかについては、あなた自身の心の中に答えがあるかもしれません。

5. etcdは分散ロックの関連インターフェースを実装する

分散ロックの場合、etcd の対応する追加、削除、更新インターフェースが主に使用されます。

  1. // KV: キー値関連の操作
  2. タイプKVインターフェース{
  3. // ストレージ。
  4. Put(ctx context.Context、 key 、val string、opts ...OpOption) (*PutResponse、error)
  5. // 得る。
  6. Get(ctx context.Context、キー文字列、opts ...OpOption) (*GetResponse、エラー)
  7. // 消去。
  8. 削除(ctx context.Context、キー文字列、opts ...OpOption) (*DeleteResponse、エラー)
  9. // rev で指定されたバージョンより前の履歴データを圧縮します。
  10. Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error)
  11. // 操作セットを走査するために使用できる一般的な操作実行コマンド。 Put/Get/ Deleteも Do に基づいています。
  12. Do(ctx context.Context, op Op) (OpResponse, error)
  13. // トランザクションを作成します。If/ Then / Else / Commit操作のみをサポートします。
  14. Txn(ctx コンテキスト.コンテキスト) Txn
  15. }
  16.  
  17.  
  18. // リース: リース関連の操作
  19. リースインターフェース型{
  20. // リースを割り当てます。
  21. 許可(ctx context.Context、ttl int64) (*LeaseGrantResponse、エラー)
  22. // リースを解放します。
  23. 取り消し(ctx context.Context、id LeaseID) (*LeaseRevokeResponse、エラー)
  24. // 残りの TTL 時間を取得します。
  25. TimeToLive(ctx context.Context、id LeaseID、opts ...LeaseOption) (*LeaseTimeToLiveResponse、エラー)
  26. // すべてのリースを取得します。
  27. リース(ctx context.Context) (*LeaseLeasesResponse, エラー)
  28. // 更新は引き続き有効です。
  29. KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error)
  30. // アクティベーションを 1 回だけ更新します。
  31. KeepAliveOnce(ctx context.Context、id LeaseID) (*LeaseKeepAliveResponse、エラー)
  32. // 更新アクティベーション機能を無効にします。
  33. 閉じる()エラー
  34. }

6. etcd分散ロックコードの例

  1. パッケージメイン
  2.  
  3. 輸入 (
  4. "コンテクスト"  
  5. 「fmt」  
  6. 「go.etcd.io/etcd/clientv3」  
  7. "時間"  
  8.  
  9. var conf clientv3.Config
  10.  
  11. // ロック構造
  12. EtcdMutex 構造体型 {
  13. Ttl int64 //リース時間
  14.  
  15. Conf clientv3.Config //etcd クラスター構成
  16. キー文字列//etcdキー 
  17. キャンセルcontext.CancelFunc //更新関数を閉じる
  18.  
  19. txn クライアントv3.Txn
  20. リースクライアントv3.リース
  21. リースID クライアントv3.リースID
  22. }
  23.  
  24. // ロックを初期化する
  25. func (em *EtcdMutex) init() エラー {
  26. var err エラー
  27. var ctx コンテキスト.コンテキスト
  28.  
  29. クライアント、エラー:= clientv3.New(em.Conf)
  30. err != nil の場合 {
  31. エラーを返す
  32. }
  33.  
  34. em.txn = clientv3.NewKV(クライアント).Txn(コンテキスト.TODO())
  35. em.lease = clientv3.NewLease(クライアント)
  36. リース応答、エラー := em.lease.Grant (context.TODO()、em.Ttl)
  37.  
  38. err != nil の場合 {
  39. エラーを返す
  40. }
  41.  
  42. ctx、em.cancel = context.WithCancel(context.TODO())
  43. em.leaseID = リース応答ID
  44. _, エラー = em.lease.KeepAlive(ctx, em.leaseID)
  45.  
  46. エラーを返す
  47. }
  48.  
  49. // ロックを取得する
  50. func (em *EtcdMutex) Lock() エラー {
  51. エラー:= em.init()
  52. err != nil の場合 {
  53. エラーを返す
  54. }
  55.  
  56. // ロック
  57. em.txn.If(clientv3.Compare(clientv3.CreateRevision( em.Key ), "=" , 0))。
  58. 次に、 (clientv3.OpPut(em.Key , " " , clientv3.WithLease(em.leaseID))) を実行します。それ以外()
  59.  
  60. txnResp、エラー:= em.txn。専念()
  61. err != nil の場合 {
  62. エラーを返す
  63. }
  64.  
  65. // txn.if 条件が真かどうかを判定する
  66. !txnResp.Succeeded の場合 {
  67. return fmt.Errorf( "ロックを取得できませんでした" )
  68. }
  69.  
  70. ゼロを返す
  71. }
  72.  
  73. //ロックを解除する
  74. func (em *EtcdMutex) UnLock() {
  75. // リースは自動的にすぐに期限切れになります
  76. // cancel は更新をキャンセルし、 revoke即時に期限切れになります
  77. em.キャンセル()
  78. リース。取り消し(context.TODO()、em.leaseID)
  79.  
  80. fmt.Println( "ロックが解除されました" )
  81. }
  82.  
  83. // グラウチン1
  84. try2lock1()関数{
  85. eMutex1 := &EtcdMutex{
  86. 会議: 会議、
  87. 合計: 10,
  88. キー 「ロック」
  89. }
  90.  
  91. エラー:= eMutex1.Lock()
  92. err != nil の場合 {
  93. fmt.Println( "groutine1 はロックを取得できませんでした" )
  94. 戻る 
  95. }
  96. eMutex1.UnLock() を延期する
  97.  
  98. fmt.Println( "groutine1 はロックを正常に取得しました" )
  99. 時間.スリープ(10 *時間.)
  100. }
  101.  
  102. // グルーティン2
  103. try2lock2()関数{
  104. eMutex2 := &EtcdMutex{
  105. 会議: 会議、
  106. 合計: 10,
  107. キー 「ロック」
  108. }
  109.  
  110. エラー:= eMutex2.Lock()
  111. err != nil の場合 {
  112. fmt.Println( "groutine2 はロックを取得できませんでした" )
  113. 戻る 
  114. }
  115.  
  116. eMutex2.UnLock() を延期する
  117. fmt.Println( "groutine2 はロックを正常に取得しました" )
  118. }
  119.  
  120. // テストコード
  121. EtcdRunTester()関数 {
  122. conf = クライアントv3.Config{
  123. エンドポイント: []string{ "127.0.0.1:2379" },
  124. ダイヤルタイムアウト: 5 *時間 2番
  125. }
  126.  
  127. // ロックを競うために2つのコルーチンを開始する
  128. try2lock1() を実行する
  129. try2lock2() を実行する
  130.  
  131. 時間.スリープ(300 *時間.)
  132. }

要約する

分散ロック機能を提供できるコンポーネントは多数ありますが、それぞれに独自の性質と個性があります。どのコンポーネントを選択するかは、ビジネスにとってのデータの重要性に応じて異なります。データに強力な一貫性が必要な場合は、CP をサポートする etcd と zookeeper が推奨されます。少量のデータ損失が許容され、強力な一貫性が要求されない場合は、AP をサポートする Redis が推奨されます。

<<:  Centos8にVDOをインストールして設定し、ストレージスペースを最適化する

>>:  フランスは、GoogleとMicrosoftのクラウドサービスが機密データを処理できると述べている

推薦する

ウェブサイトを作ることにはまだ未来があるのでしょうか?個人ウェブサイト所有者の将来の道筋は何でしょうか?

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービスウェブサイトの構築を始め...

クラウドコンピューティングとデータサイエンスの違い

クラウド コンピューティングとデータ サイエンスは複雑に関連し、クラウド プラットフォームはデータの...

desivps: 月に 1 回の無料 IP 変更、年間 30 ドル、ロサンゼルス VPS、2G メモリ/1 コア/30g SSD/1Gbps 帯域幅、無制限のトラフィック

desivps は現在、中国の顧客向けに、1000Mbps の帯域幅、無制限のトラフィック、無料の ...

検索エンジンの外部リンク要件は量から質へ変化

SEO の作業において、外部リンクは最も簡単に制御および操作できる要素であり、検索エンジンのランキン...

型破りな要素を活用してBaiduでのウェブサイトのパフォーマンスを向上させる

ご存知のとおり、ウェブサイトの最適化のプロセスには、ウェブサイトのキーワード密度の把握、ウェブサイト...

#おすすめ# zji:米国200g高防御サーバー、3ネットワーク直結、20%割引プロモーション

zjiは3月に米国データセンターに200Gの高防御サーバーを開設し、3つのネットワークに直接接続して...

SRE と DevOps は味方でしょうか、それとも敵でしょうか?未来をリードするのは誰でしょうか?

[[278068]]序文サイト信頼性エンジニアリング (SRE) と DevOps は現在非常に人気...

SEOリサーチセンターの学習モデルが私にどのように役立ったかについての簡単な説明

今年のSEO業界の変化に少し不安を感じており、その気持ちを表明せずにはいられません。インターネット界...

ウェブサイトの外部リンクが Baidu 検索エンジンに含まれ、削除された後に行うべきこと

Baidu が外部リンクを公開して以来、多くのウェブサイトの外部リンクがインデックスされた後に削除さ...

vpsget-5.95ドル/512MBメモリ/20GBハードディスク/2TBトラフィック

vpsget についてはよく知りません。ドメイン名は 2009 年に登録されました。ASN を見ると...

食品・飲料業界の新ブランドレポート

今日は、誰もが毎日関わっているかもしれない大きなビジネス、食品と飲料の新しい全国的なトレンドについて...

粘り強さが報われます。Flarum が最初の RC1 安定候補バージョンをリリースしました。

Flarum は、エレガントで軽量 (100K 以下) な PHP フォーラム プログラムとして、私...

crazydomains は、ドメイン名を超低価格で提供し続けています。.com1 ポンドなど。

crazydomains.com.au がドメイン名のプロモーションを再開しました。最も魅力的なもの...