Spring-data-redis分散ロックの設定

3647 ワード

Spring-data-redis分散ロックの設定
分散ロックの設定が適切でないと、次の問題が発生します.
  • ロックを持つプロセスがクラッシュし、他のロック待ちプロセスがロックを取得できず、デッドロックが発生しました.
  • ロックを保持するプロセスは、操作時間が長すぎるため、ロックが自動的に解放されるが、プロセス自体はそれを知らず、他のプロセスが保持するロックを誤って解放することもある.

  • プロジェクトでは「spring-data-redis」または「spring-boot-starter-data-redis」を使用し、通常はRedisTemplateクラスでRedisを操作します.ここではredisによって分散ロックを設定する具体的な手順を説明します.
  • 分散ロック
  • を取得する.
    private RedisTemplate redisTemplate;
    
    /**
         *                      
         *
         * @param mutexKey    key
         * @param mutexVal    val,  UUID
         * @param ttl             
         * @param timeUnit          
         * @param waitMilSec     ,  <=0,          
         * @return         
         */
        private boolean getLockWithExpire(String mutexKey, String mutexVal, long ttl, TimeUnit timeUnit, long waitMilSec) {
            //            
            RedisSerializer serializer = redisTemplate.getStringSerializer();
            long start = System.currentTimeMillis();
            long now = start;
            long end = waitMilSec > 0 ? now + waitMilSec : Long.MAX_VALUE;
            Boolean isSet = false;
            //  SetNX,            
            while (now < end) {
                isSet = redisTemplate.execute(
                        redisConn ->
                                redisConn.set(serializer.serialize(mutexKey),
                                        serializer.serialize(mutexVal),
                                        Expiration.from(ttl, timeUnit),
                                        RedisStringCommands.SetOption.SET_IF_ABSENT),
                        true);
                if (Boolean.valueOf(true).equals(isSet)) {
                    //    
                    break;
                }
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                now = System.currentTimeMillis();
            }
            return Boolean.valueOf(true).equals(isSet);
        }
    

    重要なのはredisのsetNXコマンドを運用して、異なるクライアント(Jedis/lettuce)あるいは異なるapiがあって、springはそれに対して統一的なパッケージをして、そして接続を取得して、接続を解放して、異常な処理の具体的な細部を遮断して、springが他の持続的な層のフレームワークをパッケージするようにします.現在のところ、RedisTemplateはredisを操作する需要の大部分を実現することができる.Redis 2.6.12以降、Setコマンドには複数のオプションパラメータが追加されました.
    set key value [expiration EX seconds|PX milliseconds] [NX|XX]
    

    expiration:有効期限、EX秒、PXミリ秒;NX:Not Exist; XX:Exist; たとえば、key=nameが存在しない場合、value=Tomを設定し、60秒の有効期限:set name Tom EX 60 NXを設定します.このコマンドにより、SetNx+Expireが分散ロックを実現する際に発生するバグが回避されます.2.分散ロックの解除
    /**
         *      
         *
         * @param mutexKey  key
         * @param mutexVal  val
         * @return              
         */
        private boolean releaseLock(String mutexKey, String mutexVal) {
            String lua = "if redis.call('get',KEYS[1]) == ARGV[1] " +
                    "then return redis.call('del',KEYS[1]) " +
                    "else return 0 end";
            RedisSerializer serializer = redisTemplate.getStringSerializer();
            Object res = redisTemplate.execute(redisConn -> redisConn.eval(serializer.serialize(lua),
                    ReturnType.BOOLEAN,
                    1,
                    serializer.serialize(mutexKey),
                    serializer.serialize(mutexVal)), true);
            return Boolean.valueOf(true).equals(res);
        }
    

    ロックを解除するには、現在のプロセスがロックを持っているかどうかを確認してから削除する2つのステップが必要です.現在、luaスクリプトでしか動作できないACID.3.Redisが公式に推奨する分散ロック以上は単一ノードRedisで簡単な分散ロックを実現でき、マルチノードRedis、高同時性の場合、多くの問題が露呈する.RedisはRedLockを公式に推奨している.the Redlock algorithm
    コードウェアハウス
    https://gitee.com/thanksm/redis_learn/tree/master/redis_common