redisサブスクリプションパブリケーションメカニズムによる分散ロックの実現


推奨:jeesuite開発フレームワーク、無料オープンソース、ワンストップソリューション.
通常、分散シーンロックメカニズムを解決するにはredisが最初に考えられます.redis単一スレッドが天然にこの問題を解決したからだ.redisを使用して分散ロックを実装するには、getsetおよびsetnxを使用します.
  • getset:与えられたkeyの値をvalueに設定し、keyの古い値(old value)
  • を返す.
    redis> GETSET db mongodb    #     ,   nil
    (nil)
    
    redis> GET db
    "mongodb"
    
    redis> GETSET db redis      #      mongodb
    "mongodb"
    
    redis> GET db
    "redis"
  • SETNX:keyの値をvalueとし、keyが存在しない場合のみ.与えられたkeyが既に存在する場合、SETNXは何もしない.
  • redis> EXISTS job                # job    
    (integer) 0
    
    redis> SETNX job "programmer"    # job     
    (integer) 1
    
    redis> SETNX job "code-farmer"   #      job ,  
    (integer) 0
    
    redis> GET job                   #      
    "programmer"

    しかし、この方式は、ロックが待機している場合、ロック解放通知を自発的に取得することができず、ポーリングしてredisを絶えず調べなければならない.これにより、クエリー・リクエストが大量に発生し、待機時間が増加します(たとえば、10 msでポーリングしますが、次のミリ秒でロックが取得できるかもしれませんが、10 msを待つ必要があります).次に、redis SUBPUBメカニズムに基づいて実現した分散ロックの考え方を共有します.
  • は、redis Listキューおよびsubpubメカニズムを使用する.
  • 各待機ロックは、グローバル一意のeventIdを生成し、redisキューは、取得ロックを待機するeventIdのセットを配置する.
  • ロックを取得するプロセス1:キューに入れた後の長さがちょうど:1であれば、ロックが取得されます.
  • ロックを取得するプロセス2:キューに入れた後の長さ>1で、前のロックの解放を待つ.
  • ロック解除:まずeventIdキューRPOPから次のロック取得の通知対象とする.
  • ロック待機:スレッドブロックはredisパブリッシュメッセージを待機し、nextEventIdが現在と一致する場合、ロックを取得する.
  • その他の考慮事項:ロックタイムアウト、デッドロックなどの問題.

  • 添付:1.eventId構造:固定ビット数ノードID+13ビットタイムスタンプ+一意シーケンス
    public String buildEvenId(){
            return new StringBuilder().append(EVENT_ID_PREFIX).append(System.currentTimeMillis()).append(eventIdSeq.incrementAndGet()).toString();
        }
  • ロックを解除し、メッセージの内容を公開します:lockName+セパレータ+nextEventId
  • 完全コード:完全コードを取得