分布式ロックメカニズムの原理と実現方式


前言
  • 分散ロックは、分散システム間の共有リソースへの同期アクセスを制御する方式
  • である.
  • 分散システムでは、動作を調整する必要があることが多い.異なるシステムまたは同じシステムの異なるホスト間で1つまたは複数のリソースが共有されている場合、これらのリソースにアクセスする際には、互いに干渉しないように反発して一貫性を保証する必要があり、この場合、分散ロックを使用する必要があります.
  • ここでは主に3つの方式を簡単に紹介する:データベースベースの実現方式、redisベースの実現方式、ZooKeeperベースの実現方式.

  • シーンの例
  • は、1つのプロセスAがあると仮定し、1時間ごとにユーザーにメール「Hello world」を送信し、高可用性のために、複数のマシンに複数のプロセスを配置し、ダウンタイムを回避しなければならない.
  • は2台のマシンに配備されていると仮定し、問題が発生すると、ユーザーは1時間に2つの「Hello world」を受け取り、情報が重複します.
  • 「Hello world」を1つだけ送信すれば、分散ロックの概念を導入することができます.
  • プロセスAとプロセスBはメールを送信する前にまずロックを登録し、プロセスAがロックを奪ったと仮定すると、プロセスBは結果を待っています.もし送信に成功したら、Bは今回のタスクを放棄し、次の時間を待っています.
  • 問題の核心はどのようにロックを登録するかにあり、ロックの存在と登録ロックを検査するのは原子的な操作であり、mysqlのメインキーのように、存在するとinsertできない.つまり、私のロックを覆うことができない.待っていなければならない.
  • 分散ロックを実現する方法はいくつかあります.最も簡単なのは、1時間ごとにこの時間をプライマリ・キーとしてmysqlにデータを書き込み、データベースを利用して一貫性を維持することです.

  • 分散ロックを使用する理由
  • アプリケーションを開発する際に、共有変数にマルチスレッド同期アクセスする必要がある場合は、Javaマルチスレッドを使用して解決できます.
  • は、これが単一のアプリケーションであることに注意し、すなわち、すべての要求が現在のサーバのjvm内部に割り当てられ、オペレーティングシステムのスレッドにマッピングされて処理されるが、この共有変数はこのjvm内部のメモリ領域にすぎない.
  • 後に業務が発展し、クラスタを作る必要があり、1つのアプリケーションは数台の機械に配置し、負荷の均衡を行う必要があり、大体以下の図である:
  • 上図分析:
    (1)  A  JVM1、JVM2、JVM3  JVM   (    A                 ,         ),          ,  A     JVM1、JVM2、JVM3       ;
    (2)                  ,        。
    (3)         ,            JVM       ,  A       ,       ,          。
    (4)               ,               。
  • は、方法または属性が高同時性の場合に同じ時間に同じスレッドでしか実行できないことを保証するために、従来のスタンドアロンアプリケーションのスタンドアロン配置の場合、java同時処理の関連APIを使用して反発制御(ReentrantLockまたはSynchronizedなど)を行うことができる.
  • は、シングルマシン環境においてjavaにおいて多くの同時処理関連APIを提供する.
  • しかし、ビジネスの発展の必要性に従って、元の単体単機が配置したシステムが分布式クラスタシステムに進化した後、分布式システムはマルチスレッド、マルチプロセスで異なるマシンに分布するため、これは元の単機配置の場合の同時制御ロック戦略を失効させ、単純なjava APIは分布式ロックの能力を提供することができない.
  • この問題を解決するためには、分散ロックが解決すべき問題であるJVMにまたがる反発メカニズムが必要である.

  • 分散ロックが備えるべき条件
  • 分散システム環境において、1つの方法は同じ時間に1つの機械の1つのスレッドによってしか実行できない.
  • 高利用可能な取得ロックと解放ロック;
  • 高性能の取得ロックと解放ロック;
  • は再入可能な特性を備えている.
  • はロックの失効メカニズムを備え、デッドロックを防止する.
  • は、非ブロックロック特性を備えている.すなわち、ロックが取得されなければ、取得ロックに直接戻って失敗する.

  • 分散ロックの実装-前言
  • 現在、ほとんどの大規模なWebサイトやアプリケーションは分散的に導入されており、分散シーンにおけるデータ整合性の問題はずっと重要な話題となっています.
  • 分散CAP理論は、どの分散システムも一貫性、可用性、パーティション許容誤差を同時に満たすことができず、最大2つしか満たすことができないことを示しています.
  • なので、多くのシステムは設計の初めにこの3つを取捨選択しました.インターネット分野のほとんどのシーンでは、強い一貫性を犠牲にしてシステムの高可用性を取り替える必要があり、システムは最終的な一貫性を保証するだけで、この最終的な時間が実際にユーザーが受け入れられる範囲内であればよいことが多い.
  • 多くのシーンでは、データの最終的な一貫性を保証するために、分散トランザクション、分散ロックなど、多くの技術案をサポートする必要があります.場合によっては、同じスレッドで実行する方法を保証する必要があります.
  • データベースに基づいて分散ロックを実現する.キャッシュredisなどに基づいて分散ロックを実現する.Zookeeperに基づいて分散ロックを実現した.

  • データベースベースの実装
  • データベースの実現方式の核心思想に基づいて:データベースの中で1つの表を作成して、表の中で方法名などのフィールドを含んで、そして方法名のフィールドの上で唯一のインデックスを作成して、ある方法を実行したいならば、この方法名を使って表の中にデータを挿入して、成功に挿入してロックを取得して、実行が完成した後に対応する行のデータを削除してロックを解放します.
  • テーブルを作成します:
    DROP TABLE IF EXISTS `method_lock`;
    CREATE TABLE `method_lock` (
     `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '  ',
     `method_name` varchar(64) NOT NULL COMMENT '      ',
     `desc` varchar(255) NOT NULL COMMENT '    ',
     `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     PRIMARY KEY (`id`),
     UNIQUE KEY `uidx_method_name` (`method_name`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT=‘      ';
  • メソッドを実行するには、このメソッド名を使用してテーブルにデータを挿入します:
    INSERT INTO method_lock (method_name, desc) VALUES ('methodName', ‘   methodName');
  • .
  • method_nameは一意の制約を行い,ここで複数の要求が同時にデータベースにコミットされると,データベースは1つの操作のみが成功することを保証し,操作に成功したスレッドがこの方法のロックを獲得し,メソッドボリュームコンテンツを実行できると考えられる.
  • が正常に挿入するとロックを取得し、実行が完了すると対応する行データ解放ロックを削除する:
    delete from method_lock where method_name ='methodName';
  • .
  • データベースベースのこのような実装は簡単であるが、分散ロックが備えるべき条件については、
    (1)           ,                          ,  ,         、    、    。
    (2)         ,             ,       ,          ,  ,         ,                  ,         ,                          ,         ;
    (3)       ,              ,      ,          ,             ,  ,         ,        ,                  ;
    (4)        ,           ,          ,       。
  • を解決し、最適化する必要がある問題がある.
  • は実施過程で様々な異なる問題に直面し、これらの問題を解決するために、実現方式はますます複雑になるだろう.データベースに依存するにはリソースのオーバーヘッドが必要であり、パフォーマンスの問題を考慮する必要があります.

  • redisベースの実装方式
  • redis分散ロックが選択された理由:
    (1)redis      ;
    (2)redis         ,        
  • 分散ロックを使用する際に主に使用するコマンドの紹介:
    (1)SETNX
         SETNX key val:    key    ,set  key val    ,  1; key  ,      ,  0。
    (2)expire
        expire key timeout: key        ,   second,            ,    。
    (3)delete
        delete key:  key
  • 実現思想:
    (1)      ,  setnx  ,   expire           ,           ,  value         UUID,              。
    (2)                  ,             。
    (3)      ,  UUID       ,    ,   delete     。
  • ZooKeeperベースの実装
  • ZooKeeperは、分散アプリケーションにコンシステンシサービスを提供するオープンソースコンポーネントであり、内部には階層化されたファイルシステムディレクトリツリー構造があり、同じディレクトリの下に一意のファイル名しかないことを規定しています.
  • ZooKeeperに基づいて分散ロックを実装するには、
    (1)      mylock;
    (2)  A      mylock           ;
    (3)  mylock         ,             ,     ,            ,   ;
    (4)  B      ,          ,           ;
    (5)  A   ,       ,  B       ,           ,       。
  • ここでは、ZooKeeperクライアントであるApacheのオープンソースライブラリCuratorを推奨します.Curatorが提供するInterProcessMutexは分散ロックの実装であり、acquireメソッドはロックを取得するために使用され、releaseはロックを解放するために使用されます.
  • の利点:高可用性、再入可能、ブロックロック特性を備え、失効したデッドロック問題を解決することができる.
  • の欠点:ノードの頻繁な作成と削除が必要なため、性能的にはredis方式に及ばない.

  • まとめ
  • の上の3つの方式は、すべての場合に完璧ではないので、異なるアプリケーションシーンに応じて最適な実現方式を選択しなければならない.
  • 分散環境では、リソースをロックすることが重要である場合があります.たとえば、リソースを買い占める場合、分散ロックを使用すると、リソースをよく制御できます.

  • リファレンスリンク
    https://blog.csdn.net/xlgen15...