Redis実装分散ロック(springタイミングタスククラスタ適用Redis分散ロック)


前の2つの記事で紹介しました
Spring注釈によるタイミングタスクの実現:https://blog.csdn.net/QiaoRui_/article/details/82999655
Springタイミングタスクの動的変更:https://blog.csdn.net/QiaoRui_/article/details/83110794
説明:
動的に実行するかどうかにかかわらず、単機サービスは問題ありませんが、サービスがクラスタモードであれば、1つのタスクは各マシンで1回実行されます.これは私たちが必要としないに違いありません.私たちが実現しなければならないのは、クラスタ全体が毎回1つのタスクだけで実行に成功することですが、springはこれに対してあまりサポートされていません.そのため、私たちは統一的なデータ取得所が必要で、参考ネット上でridesの一致性を利用して実現することを決定して、最初から参考ネット上でsetnxコマンドを利用して実現して、しかしやはりあまり完備していないと感じて、タイミングタスクを捨てて、直接Redis分布式ロックを実現するのが最も適切で、タイミングタスク業務でロックを追加して、業務はロックを解除すればいいです.
この事例は複数のWebサイトを通じて参考になり、実際に自分で操作しても問題なく、完全に正常に使用できます.
実装:

import redis.clients.jedis.JedisCluster;

import java.util.Collections;

/**
 *
 * redis      ,    
 */
public class RedisTool {

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;

    /**
     *         
     * @param jedis Redis   
     * @param lockKey  
     * @param requestId     
     * @param expireTime     ,  
     * @return       
     */
    public static boolean tryGetDistributedLock(JedisCluster jedis, String lockKey, String requestId, int expireTime) {
        /*
        *          ,lockKey  Redis key,requestId  Redis value,SET_IF_NOT_EXIST         (NX),
        * SET_WITH_EXPIRE_TIME          (PX)  ,expireTime          
        * */
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }

    /**
     *       
     * @param jedis Redis   
     * @param lockKey  
     * @param requestId     
     * @return       
     */
    public static boolean releaseDistributedLock(JedisCluster jedis, String lockKey, String requestId) {

        /*
        *   Lua    ,        value ,     requestId  ,        (  )
        * eval    Lua     ,Lua             ,    eval      ,Redis        ,                        ,        
        * */
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

}

前編ブログの業務による引用
package com.rails.travel.conf.task.myschedule;

import com.rails.travel.common.FrameSpringBeanUtil;
import com.rails.travel.common.RedisTool;
import redis.clients.jedis.JedisCluster;

import java.util.Date;


public class MyRunnable3 implements Runnable {

    //           bean  ,           bean  
    //FrameSpringBeanUtil         :https://blog.csdn.net/QiaoRui_/article/details/83094960
    private JedisCluster jedisCluster = FrameSpringBeanUtil.getBean(JedisCluster.class);

    @Override
    public void run() {
        //  ,        ,          
        boolean lock = RedisTool.tryGetDistributedLock(jedisCluster, MyRunnable3.class.toString(), MyRunnable3.class.toString(), 3000);
        //         ,         
        if (lock){
            //      
            System.out.print("     3" + new Date());
            //        ,                   ,   ,        key        
            RedisTool.releaseDistributedLock(jedisCluster,MyRunnable3.class.toString(), MyRunnable3.class.toString());
        }
    }
}

説明:
ロック解除ツール類は直接ブログや公式サイトなどを見て利用するもので、ブログは見なければならない.実現原理や現在のネット上の誤ったやり方の問題点を完全に理解することができる.私が使い始めたのはブログで述べた最初の誤った方法だ.
ブログ:https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/#%E5%8F%82%E8%80%83%E9%98%85%E8%AF%BB
Redis中国語コマンドリファレンスではsetコマンドの最後にも同様の解決策が示されています.http://doc.redisfans.com/string/set.html
Redis公式サイトでは、分散ロックについても、推奨GitHub実装を含めて、この方法である.https://redis.io/topics/distlock