ホームページ >データベース >Redis >Redis分散ロックを実装する方法

Redis分散ロックを実装する方法

尚
オリジナル
2019-06-29 10:43:4625214ブラウズ

Redis分散ロックを実装する方法

redis 分散ロック:
1. 実装原理
redis で set コマンドを使用して、分散ロックを実装します。

Redis バージョン 2.6.12 以降、set では次のパラメーターを使用できます:

SET KEY VALUE [EX 秒] [PX ミリ秒] [NX|XX]

EX 秒: キーの有効期限を秒に設定します。 SET キー値 EX 秒の効果は、SETEX キーの秒値と同等です。
PX ミリ秒: キーの有効期限をミリ秒単位で設定します。 SET キーの値 PX ミリ秒の効果は、PSETEX キーのミリ秒の値と同等です。
NX: キーが存在しない場合にのみキーが設定されます。 SET キー値 NX の効果は SETNX キー値と同等です。
XX: キーは、キーがすでに存在する場合にのみ設定されます。
戻り値:
SETは設定が正常に完了した場合のみOKを返します。
NX または XX が設定されているが条件を満たさないため設定操作が実行されない場合、コマンドは NULL Bulk Reply を返します。
コマンド:
> SET key value EX ttl NX

一般的な考え方は次のとおりです:
(a) SET lock currentTime expireTime EX 600 NX、set を使用してロック値を設定し、有効期限は 600 秒です。成功すると、ロックが取得されます。

(b) ロックを取得した後、ノードがオフラインになると、ロック値は有効期限に自動的に期限切れになります。
( c) ロックを解放するときは、del を使用してロック キーの値を削除します;
分散ロック サービスを提供するために redis スタンドアロン マシンを使用すると、単一点の問題が発生し、サービスの可用性が低下する可能性があります。値が高い場合、公式の推奨事項は、redis 分散ロックを実装するために redis クラスター (たとえば、5 ユニット) を使用することです。ロック要求が 3 回以上成功した場合、ロックを取得したとみなされます。詳細については、「レッドロック」を参照してください。
2. 利点
高性能、redis を永続化でき、データが簡単に失われません;
redis クラスター方式により安定性が向上します。
3. 欠点
Redis マスター/スレーブ切り替えを使用すると、一部のデータが失われる可能性があります。
4. オープンソース実装
Python バージョンのオープンソース実装: python-redis-lock。

redis 分散ロックの具体的な実装方法:

ロックとロック解除の方法:

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 lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public Boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {
        Jedis jedis = this.jedisPool.getResource();
        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 lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public Boolean releaseDistributedLock(String lockKey, String requestId) {
        Jedis jedis = this.jedisPool.getResource();
        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;

    }

2. 特定のアプリケーション

try{
String requestId = UUID.randomUUID().toString();
Boolean flag = tryGetDistributedLock(lock,requestId,1000);
int n = 0;
while(!flag){
      //如果没有获取锁,可以尝试下一个lock,如果都没有,则尝试 n 次,退出
     ...
     if(n++>5){ throw new Exception("尝试获取锁失败");}  
     ...  
}
if(!flag){
throw new Exception("尝试获取锁失败");
}
}catch(){
}finally{
    releaseDistributedLock(lock,requestId);
}

Redis 関連の知識については、Redis 使用法チュートリアル 列をご覧ください。

以上がRedis分散ロックを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。