分散ロックの王道ソリューション - Redisson

レディソンです。
まず、分散ロックについて Redis 公式 Web サイトに記載されている内容を見てみましょう。
backend、
frontend、
小プログラムを同じウェアハウスにアップロードしました。
Github または ## を使用できます。 #codeyun
にアクセスしてください。アドレスは次のとおりです:
Github: https://github.com/Jackson0714/PassJava-Platform
Code Cloud:https://gitee.com/jayh2018/PassJava-Platform
Supporting Tutorial: www.passjava.cn
実際の戦闘の前に、 「レディソンの原理」の使い方を見てください。
1.レディソンとは何ですか?
以前に Redis を使用したことがある場合は、Redisson を使用すると、半分の労力で 2 倍の結果が得られます。Redisson は、Redis を使用する最も簡単で便利な方法を提供します。
Redisson の目的は、ユーザー間で Redis の関心の分離 (Separation of Concern) を促進し、ユーザーがビジネス ロジックの処理により集中できるようにすることです。
Redisson は、Redis に基づいて実装された Java インメモリ データ グリッド (In-Memory Data Grid) です。

Netty フレームワーク: Redisson は、Redis として機能するだけでなく、NIO ベースの Netty フレームワークを採用しています。基盤となるドライバー client には、Redis のさまざまな構成形式への接続を提供する機能、Redis コマンドを同期、非同期、非同期ストリーミングまたはパイプラインで送信する機能、LUA スクリプトの実行処理、および返された結果を処理する機能があります
基本データ構造: ネイティブ Redis
Hash
、List
、Set
、String
、Geo
、HyperLogLog
およびその他のデータ構造は、Java で最もよく知られたマッピング (Map)
、## にカプセル化されます。 #List,
Set,
General Object Bucket,
Geospatial Bucket,
カーディナリティ推定アルゴリズム (HyperLogLog)およびその他の構造、
#分散データ構造 : これに基づいて、Multimap、LocalCachedMap、SortedSet、ScoredSortedSet、LexSortedSet、Queue、Blocking Queue、 Bounded Blocking Queue、Deque、Blocking Deque、Blocking Fair Queue、Delayed Queue、Bloom Filter、アトミック整数(AtomicLong)、アトミック倍精度浮動小数点数(AtomicDouble)、BitSetなど、Redisが本来持っていない分散データ構造。
分散ロック: Redisson は、Redis ドキュメントのアプリケーション シナリオで説明されている分散ロック
Lock
のような高レベルのロックも実装します。実際、Redisson はそれだけではなく、分散ロックに基づいて、Interlock (MultiLock)
、ReadWriteLock (ReadWriteLock)
、Fair Lock (Fair Lock) も提供します。
,Red Lock (RedLock)
,セマフォ (Semaphore)
,Expirable Semaphore (PermitExpirableSemaphore)
およびロック (CountDownLatch)
これらマルチスレッドの同時実行性の高いアプリケーションにとって重要な基本コンポーネントです。 Redisson が分散システムを構築するための重要なツールとなるのは、Redis に基づく高次アプリケーション ソリューションの実装を通じてです。Node: 独立ノードとしての Redisson を使用して、
分散実行サービス
に公開された他のノードを独立して実行できます。Distributed Scheduling Service
のリモート タスク。
#2. Redisson の統合
Redisson を Spring Boot と統合するには 2 つのオプションがあります:- プログラムによる構成。 #ファイルモードの設定。
- この記事では、Redisson をプログラムで統合する方法を紹介します。
2.1 Maven 依存関係の導入
passjava-question マイクロサービスの pom.xml に redisson の Maven 依存関係を導入します。
<!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.15.5</version> </dependency>
2.2 カスタム構成クラス
次のコードは、単一ノード Redis の構成です。
@Configuration public class MyRedissonConfig { /** * 对 Redisson 的使用都是通过 RedissonClient 对象 * @return * @throws IOException */ @Bean(destroyMethod="shutdown") // 服务停止后调用 shutdown 方法。 public RedissonClient redisson() throws IOException { // 1.创建配置 Config config = new Config(); // 集群模式 // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001"); // 2.根据 Config 创建出 RedissonClient 示例。 config.useSingleServer().setAddress("redis://127.0.0.1:6379"); return Redisson.create(config); } }
2.3 テスト構成クラス
新しい単体テスト メソッドを作成します。
@Autowired RedissonClient redissonClient; @Test public void TestRedisson() { System.out.println(redissonClient); }
このテスト メソッドを実行し、redissonClientを出力します
org.redisson.Redisson@77f66138
3. 分散リエントラント ロック
3.1 リエントラント ロック テスト
Redis に基づく Redisson 分散リエントラント ロックRLock
Java オブジェクトは、java.util.concurrent.locks.Lock
インターフェイスを実装します。また、非同期 (Async)、反射型 (Reactive)、および RxJava2 標準インターフェイスも提供します。
RLock lock = redisson.getLock("anyLock"); // 最常见的使用方法 lock.lock();
passjava オープン ソース プロジェクトを使用して、2 つの再入可能ロックをテストします:
(1) 複数のスレッドがロックを捕捉します。後続のロックは待機する必要がありますか? ? (2) ロックをプリエンプトしたスレッドが存在するサービスが停止した場合、ロックは解放されますか?
3.1.1 検証 1: リエントラント ロックはブロックされていますか?
上記 2 点を確認するために、デモ プログラムを作成しました。コード プロセスは、WuKong-lock
ロックを設定し、それをロックし、スレッド ID を出力して待機するというものです。 10 秒間ロックを解除すると、最終的に「test lock ok」という応答が返されます。
@ResponseBody @GetMapping("test-lock") public String TestLock() { // 1.获取锁,只要锁的名字一样,获取到的锁就是同一把锁。 RLock lock = redisson.getLock("WuKong-lock"); // 2.加锁 lock.lock(); try { System.out.println("加锁成功,执行后续代码。线程 ID:" + Thread.currentThread().getId()); Thread.sleep(10000); } catch (Exception e) { //TODO } finally { lock.unlock(); // 3.解锁 System.out.println("Finally,释放锁成功。线程 ID:" + Thread.currentThread().getId()); } return "test lock ok"; }
まず最初の点を確認し、2 つの http リクエストを使用してプリエンプション ロックをテストします。
リクエストされた URL:
http://localhost:11000/question/v1/redisson/test/test-lock

第一个线程对应的线程 ID 为 86,10秒后,释放锁。在这期间,第二个线程需要等待锁释放。
第一个线程释放锁之后,第二个线程获取到了锁,10 秒后,释放锁。
画了一个流程图,帮助大家理解。如下图所示:

第一步:线程 A 在 0 秒时,抢占到锁,0.1 秒后,开始执行等待 10 s。 第二步:线程 B 在 0.1 秒尝试抢占锁,未能抢到锁(被 A 抢占了)。 第三步:线程 A 在 10.1 秒后,释放锁。 第四步:线程 B 在 10.1 秒后抢占到锁,然后等待 10 秒后释放锁。
由此可以得出结论,Redisson 的可重入锁(lock)是阻塞其他线程的,需要等待其他线程释放的。
3.1.2 验证二:服务停了,锁会释放吗?
如果线程 A 在等待的过程中,服务突然停了,那么锁会释放吗?如果不释放的话,就会成为死锁,阻塞了其他线程获取锁。
我们先来看下线程 A 的获取锁后的,Redis 客户端查询到的结果,如下图所示:

WuKong-lock 有值,而且大家可以看到 TTL 在不断变小,说明 WuKong-lock 是自带过期时间的。
通过观察,经过 30 秒后,WuKong-lock 过期消失了。说明 Redisson 在停机后,占用的锁会自动释放。

那这又是什么原理呢?这里就要提一个概念了,看门狗
。

3.2 看门狗原理
如果负责储存这个分布式锁的 Redisson 节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗
,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。
默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。
如果我们未制定 lock 的超时时间,就使用 30 秒作为看门狗的默认时间。只要占锁成功,就会启动一个定时任务
:每隔 10 秒重新给锁设置过期的时间,过期时间为 30 秒。
如下图所示:

当服务器宕机后,因为锁的有效期是 30 秒,所以会在 30 秒内自动解锁。(30秒等于宕机之前的锁占用时间+后续锁占用的时间)。
如下图所示:

3.3 设置锁过期时间
我们也可以通过给锁设置过期时间,让其自动解锁。
如下所示,设置锁 8 秒后自动过期。
lock.lock(8, TimeUnit.SECONDS);
如果业务执行时间超过 8 秒,手动释放锁将会报错,如下图所示:

所以我们如果设置了锁的自动过期时间,则执行业务的时间一定要小于锁的自动过期时间,否则就会报错。
四、王者方案
上一篇我讲解了分布式锁的五种方案:Redis 分布式锁|从青铜到钻石的五种演进方案,这一篇主要是讲解如何用 Redisson 在 Spring Boot 项目中实现分布式锁的方案。
因为 Redisson 非常强大,实现分布式锁的方案非常简洁,所以称作王者方案
。
原理图如下:

代码如下所示:
// 1.设置分布式锁 RLock lock = redisson.getLock("lock"); // 2.占用锁 lock.lock(); // 3.执行业务 ... // 4.释放锁 lock.unlock();
和之前 Redis 的方案相比,简洁很多。
下面讲解下 Redisson 的其他几种分布式锁,相信大家在以后的项目中也会用到。
五、分布式读写锁
基于 Redis 的 Redisson 分布式可重入读写锁RReadWriteLock
Java对象实现了java.util.concurrent.locks.ReadWriteLock
接口。其中读锁和写锁都继承了 RLock
接口。
写锁是一个排他锁(互斥锁),读锁是一个共享锁。
读锁 + 读锁:相当于没加锁,可以并发读。 读锁 + 写锁:写锁需要等待读锁释放锁。 写锁 + 写锁:互斥,需要等待对方的锁释放。 写锁 + 读锁:读锁需要等待写锁释放。

示例代码如下:
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock"); // 最常见的使用方法 rwlock.readLock().lock(); // 或 rwlock.writeLock().lock();
另外Redisson还通过加锁的方法提供了leaseTime
的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
// 10秒钟以后自动解锁 // 无需调用unlock方法手动解锁 rwlock.readLock().lock(10, TimeUnit.SECONDS); // 或 rwlock.writeLock().lock(10, TimeUnit.SECONDS); // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁 boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS); // 或 boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS); ... lock.unlock();
六、分布式信号量
基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore
采用了与java.util.concurrent.Semaphore
相似的接口和用法。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。
关于信号量的使用大家可以想象一下这个场景,有三个停车位,当三个停车位满了后,其他车就不停了。可以把车位比作信号,现在有三个信号,停一次车,用掉一个信号,车离开就是释放一个信号。

我们用 Redisson 来演示上述停车位的场景。
先定义一个占用停车位的方法:
/** * 停车,占用停车位 * 总共 3 个车位 */ @ResponseBody @RequestMapping("park") public String park() throws InterruptedException { // 获取信号量(停车场) RSemaphore park = redisson.getSemaphore("park"); // 获取一个信号(停车位) park.acquire(); return "OK"; }
再定义一个离开车位的方法:
/** * 释放车位 * 总共 3 个车位 */ @ResponseBody @RequestMapping("leave") public String leave() throws InterruptedException { // 获取信号量(停车场) RSemaphore park = redisson.getSemaphore("park"); // 释放一个信号(停车位) park.release(); return "OK"; }
为了简便,我用 Redis 客户端添加了一个 key:“park”,值等于 3,代表信号量为 park,总共有三个值。

然后用 postman 发送 park 请求占用一个停车位。

次に、redis クライアントで park の値を確認すると、2 に変更されていることがわかります。呼び出しを 2 回続けて、park が 0 であることがわかります。4 回目の呼び出しでは、要求が waiting
であることがわかり、十分な駐車スペースがないことが示されます。ブロックを回避したい場合は、tryAcquire または tryAcquireAsync を使用できます。
駐車スペースから出るメソッドを再度呼び出します。park の値は 1 に変更されます。これは、駐車スペースが 1 つ残っていることを意味します。
注: セマフォ解放操作が複数回実行されると、残りのセマフォは 3 で制限されるのではなく、増加し続けます。
その他の分散ロック:
フェア ロック
インターロック (マルチロック)
#レッド ロック (RedLock) - ##読み取り/書き込みロック (ReadWriteLock)
- 期限切れセマフォ (PermitExpirableSemaphore)
- ラッチ (CountDownLatch)

以上が分散ロックの王道ソリューション - Redissonの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









使用シナリオ 1. 注文は正常に行われましたが、支払いが 30 分以内に行われませんでした。支払いがタイムアウトになり、注文が自動的にキャンセルされました 2. 注文に署名があり、署名後 7 日間評価が行われませんでした。注文がタイムアウトして評価されない場合、システムはデフォルトでプラスの評価を設定します 3. 注文は正常に行われます。販売者が 5 分間注文を受け取らない場合、注文はキャンセルされます。 4. 配送がタイムアウトします。 SMS リマインダーをプッシュします... 遅延が長く、リアルタイム パフォーマンスが低いシナリオでは、タスク スケジュールを使用して定期的なポーリング処理を実行できます。例: xxl-job 今日は選択します

今日皆さんに共有したいのは分散ロックについてで、この記事では 5 つのケース、図、ソース コード分析などを使用して分析します。同期ロックやロックなどの一般的なロックはすべて単一の JVM に基づいて実装されます。分散シナリオではどうすればよいでしょうか?このとき、分散ロックが登場しました。

最新のアプリケーションが進化し続け、高可用性と同時実行性のニーズが高まるにつれて、分散システム アーキテクチャがより一般的になってきています。分散システムでは、複数のプロセスまたはノードが同時に実行され、一緒にタスクを完了するため、プロセス間の同期が特に重要になります。分散環境では多くのノードが同時に共有リソースにアクセスできるため、分散システムでは同時実行性と同期の問題にどのように対処するかが重要な課題となっています。この点で、ZooKeeper は非常に人気のあるソリューションになっています。ズーキー

必要なMavenorg.springframework.bootspring-boot-starter-data-redisio.lettucelettuce-coreredis.clientsjedisorg.springframework.sessionspring-session-data-redisorg.redissonredisson3.17.5application-redis.ymlspring:redis:host:106.12.174.220port: 6379パスワード

分散システムが徐々に普及するにつれて、分散ロックはシステムの安定性とデータの一貫性を確保するための重要な手段になりました。高性能の分散メモリ データベースとして、Redis は必然的に分散ロックの重要な実装の 1 つになりました。しかし、近年、Etcd は新たな分散一貫性ソリューションとしてますます注目を集めています。この記事では、実装原理や比較分析などの観点から、Redis の分散ロック実装と Etcd の類似点と相違点について説明します。 Redis で分散ロックを実装する原理 Redis 分散ロックの実装

以前に Redis を使用していた場合は、Redisson を使用すると、半分の労力で 2 倍の結果が得られます。Redisson は、Redis を使用する最も簡単で便利な方法を提供します。 Redisson の目的は、ユーザーがビジネス ロジックの処理により集中できるように、Redis からユーザーの関心事の分離 (Separation of Concern) を促進することです。

Redisson は、Java アプリケーション用の Redis ベースのキャッシュ ソリューションです。 Java アプリケーションで Redis をキャッシュとして使用することをより便利かつ効率的にするための多くの便利な機能が提供されます。 Redisson が提供するキャッシュ機能には以下が含まれます。 1. 分散マッピング (マップ): Redisson は、分散マップを作成するための API をいくつか提供します。これらのマップには、キーと値のペア、ハッシュ エントリ、またはオブジェクトを含めることができ、複数のノード間での共有をサポートできます。

インターネットの急速な発展と Web サイトへのアクセス数の急増に伴い、分散システムの重要性が徐々に顕著になってきました。分散システムでは、同時実行の同期とデータの一貫性の問題が必然的に伴います。分散ロックは、同時実行同期の問題を解決する手段として、分散システムで徐々に広く使用されるようになりました。 PHP では、Redis を使用して分散ロックを実装できます。これについては、この記事で紹介します。分散ロックとは何ですか?分散システムにおいて、複数のマシンが同じタスクを同時に処理する場合、多重マシンの発生を避けるために、
