redis の setnx(key, value) コマンドを使用すると、キーが存在しない場合は追加され、存在する場合は何も行われません。複数のクライアントが setnx コマンドを同時に送信した場合、1 つのクライアントだけが成功して 1 (true) を返し、他のクライアントは 0 (false) を返します。
このチュートリアルの動作環境: Windows 7 システム、Redis バージョン 5.0.10、DELL G3 コンピューター。
分散ロックの実装
ビジネス開発のニーズに伴い、元の単一マシン展開システムは分散クラスター システムに進化しました。分散システムはマルチスレッド、マルチプロセスであるため、異なるマシン上では、元の単一マシン展開の同時実行制御ロック戦略が無効になります。単純な Java API は分散ロック機能を提供できません。この問題を解決するには、共有リソースへのアクセスを制御するために JVM 間の相互排他メカニズムが必要ですが、これは分散ロックが解決する必要がある問題です。
分散ロックの主流の実装:
データベースに基づいた分散ロックの実装
キャッシュに基づいた (Redis など) )
Zookeeper に基づく
ここでは、redis に基づいて分散ロックを実装します。
基本的な実装
redis の setnx(key, value) コマンドを使用すると、キーが存在しない場合は追加され、存在する場合は何も行われません。 。複数のクライアントが setnx コマンドを同時に送信した場合、1 つのクライアントだけが成功して 1 (true) を返し、他のクライアントは 0 (false) を返します。
主に Redis Setnx コマンドを使用します
指定されたキーが存在しない場合、キーに指定された値を設定します
設定に成功しましたそして 1 を返します。設定は失敗し、0
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"
java code
public void testLock() { // 执行redis的setnx命令 String uuid = UUID.randomUUID().toString(); Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 5, TimeUnit.SECONDS); // 判断是否拿到锁 if (lock) { // 执行业务逻辑代码 // ... // 释放锁资源 (保证获取值和删除操作的原子性) LUA脚本保证删除的原子性 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; this.redisTemplate.execute(new DefaultRedisScript<>(script), Arrays.asList("lock"), Arrays.asList(uuid)); // if (StrUtil.equals(uuid,redisTemplate.opsForValue().get("lock"))){ // redisTemplate.delete("lock"); // } } else { // 其他请求尝试获取锁 testLock(); } }
を返します。分散ロックを確実に利用できるようにするには、少なくともロックの実装が次の 4 つの条件を同時に満たしていることを確認する必要があります。 time:
相互排除セックス。常に 1 つのクライアントだけがロックを保持できます。
デッドロックは発生しません。クライアントがロックをアクティブにロック解除せずにロックを保持している間にクラッシュした場合でも、その後他のクライアントがそのロックをロックできることが保証されます。
トラブルは終わるはずだ。ロックとロック解除は同じクライアントで行う必要があり、他のクライアントが追加したロックをクライアント自身がロック解除することはできません。
推奨される関連チュートリアル: Redis チュートリアル
以上がRedis分散ロックの実装原理は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。