1. はじめに
1.コンセプト
https://redisson.org
https://github.com/redisson/redisson
Redisson は、Redis に基づいて実装された Java インメモリ データ グリッド (In-Memory Data Grid) です。これは、一連の分散型共通 Java オブジェクトを提供するだけでなく、多くの分散型サービスも提供します。
Redisson の目的は、Redis に関するユーザーの関心の分離 (関心の分離) を促進し、ユーザーがビジネス ロジックの処理により集中できるようにすることです。
基本的な分散オブジェクトと高度で抽象的な分散サービスを備えた Redis ベースの分散ツールは、分散車輪の再発明を試みるすべてのプログラマーに、分散の問題のほとんどに対する解決策をもたらします。
Redisson は、Redis に基づいて実装された Java インメモリ データ グリッド (In-Memory Data Grid) です。これは、一連の分散共通 Java オブジェクトを提供するだけでなく、さまざまな分散ロックの実装を含む多くの分散サービスも提供します。
2. 違い
レディソン、ジェディス、レタスの違いは何ですか? 雷峰と雷峰塔ではありません
Redisson と 2 人の違いは、マウスを使用してグラフィカル インターフェイスを操作するのと、もう 1 つはコマンド ラインを使用してファイルを操作するようなものです。Redisson は高レベルの抽象化であり、Jedis と Lettuce は Redis コマンドのカプセル化です。
Jedis は、Java を介して Redis クライアントに接続するために Redis によって正式に開始されたツールキットです。Redis のさまざまなコマンド サポートを提供します。Lettuce は、拡張可能なスレッドセーフな Redis クライアントです。
通信フレームワークは Netty に基づいており、高度な Redis 機能をサポートします。センチネル、クラスター、パイプライン、自動再接続、Redis データ モデル。Spring Boot 2.x 以降、Lettuce が Jedis に代わって優先 Redis クライアントになりました。
Redisson は Redis に基づいて構築されており、通信は Netty の包括的で新しいミドルウェアに基づいています。エンタープライズ レベルの開発で Redis を使用するための最適なテンプレートである Jedis は、Redis コマンドをカプセル化しています。Lettuce はさらに豊富な API を備えており、サポートもサポートしてい
ますクラスターやその他のモード。しかし、どちらも最後で止まり、Redis データベースを操作するための足場を提供するだけですが、Redisson は Redis、Lua、Netty に基づいた成熟した分散ソリューション、さらには Redis が公式に推奨するツールセットを確立しました。
2. クイックスタート
1、pom.xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
2. Redisson クライアントを構成する
@Configuration
public class RedisConfig {
@Bean
public RedissonClient redissonClient() {
// 配置类
Config config = new Config();
// 添加redis地址,这里添加了单点的地址,也可以使用config.useClusterServers()添加集群地址
config.useSingleServer().setAddress("redis://192.168.150.101:6379").setPassowrd("123321");
// 创建客户端
return Redisson.create(config);
}
}
3. Redisson の分散ロックを使用する
@Resource
private RedissonClient redissonClient;
@Test
void testRedisson() throws InterruptedException {
// 获取锁(可重入),指定锁的名称
RLock lock = redissonClient.getLock("anyLock");
// 尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS);
// 判断释放获取成功
if (isLock) {
try {
System.out.println("执行业务");
} finally {
// 释放锁
lock.unlock();
}
}
}
3. 原則
Lua スクリプトとは何ですか?
Lua スクリプトは、redis に組み込まれた軽量でコンパクトな言語です。その実行は、redis の eval /evalsha コマンドを通じて実行され、操作は Lua スクリプトにカプセル化されます。いずれの場合も、一度に実行されるアトミックな操作です。時間。
ロックを取得する Lua スクリプト:
local key = KEYS[1]; -- 锁的key
local threadId = ARGV[1]; -- 线程唯一标识
local releaseTime = ARGV[2]; -- 锁的自动释放时间
-- 判断是否存在
if(redis.call('exists', key) == 0) then
-- 不存在, 获取锁
redis.call('hset', key, threadId, '1');
-- 设置有效期
redis.call('expire', key, releaseTime);
return 1; -- 返回结果
end;
-- 锁已经存在,判断threadId是否是自己
if(redis.call('hexists', key, threadId) == 1) then
-- 不存在, 获取锁,重入次数+1
redis.call('hincrby', key, threadId, '1');
-- 设置有效期
redis.call('expire', key, releaseTime);
return 1; -- 返回结果
end;
return 0; -- 代码走到这里,说明获取锁的不是自己,获取锁失败
ロックを解除する Lua スクリプト:
local key = KEYS[1]; -- 锁的key
local threadId = ARGV[1]; -- 线程唯一标识
local releaseTime = ARGV[2]; -- 锁的自动释放时间
-- 判断当前锁是否还是被自己持有
if (redis.call('HEXISTS', key, threadId) == 0) then
return nil; -- 如果已经不是自己,则直接返回
end;
-- 是自己的锁,则重入次数-1
local count = redis.call('HINCRBY', key, threadId, -1);
-- 判断是否重入次数是否已经为0
if (count > 0) then
-- 大于0说明不能释放锁,重置有效期然后返回
redis.call('EXPIRE', key, releaseTime);
return nil;
else -- 等于0说明可以释放锁,直接删除
redis.call('DEL', key);
return nil;
end;
Redisson 分散ロック原理:
- 再入可能: ハッシュ構造を使用してスレッド ID と再入時間を記録します
- 再試行可能: セマフォと PubSub 関数を使用して、ロックの待機、ウェイクアップ、およびロックの取得失敗に対する再試行メカニズムを実装します。
- タイムアウトの更新: watchDog を使用して、定期的な間隔 (releaseTime / 3) でタイムアウト期間をリセットします。
4. Redis 分散マスター/スレーブの一貫性
1) 非再入可能 Redis 分散ロック:
- 原則: setnx の相互排他を使用する; デッドロックを回避するには ex を使用する; ロックを解放するときにスレッド マークを判断する
- 欠点: 再入不可、再試行不可、ロックタイムアウト失敗
2) 再入可能な Redis 分散ロック:
- 原則: ハッシュ構造を使用してスレッドのマーキングと再エントリ時間を記録し、watchDog を使用してロック時間を延長し、セマフォを使用してロックの再試行待機を制御します。
- 欠陥: Redis のダウンタイムによって引き起こされるロックの失敗
3) Redisson の multiLock: - 原則: ロックを正常に取得するには、複数の独立した Redis ノードがすべてのノードで再入可能ロックを取得する必要があります。
- 欠点: 高い運用コストと保守コスト、複雑な実装