redis の RedissonLock が待ちロックを実装する方法
前置き
クエリー・インターフェースの初回問い合わせ時に、データを取得できなければ初期化メソッドを実行して初期化し、それ以降の問い合わせは直接ライブラリに問い合わせるようにします。この設計の目的は、初期化するデータが特に大きく、別のメソッドの呼び出しで処理できない場合、あるいは毎回初期化する必要がない場合、この場合は優先的にクエリのデータを最初に初期化することにあります。
問題点
この解答から、ある疑問が生まれます。クエリーインターフェースは自然なべき乗であることが知られており、私たちは追加のべき乗処理をする必要がないのです。しかし、この方式では、クエリは単なるクエリではない。初期化メソッドはクエリなしで実行しなければならないので、本質的には挿入ロジックである。そのため、独自にべき乗処理を行う必要がある。
スキーム
単一のサービスであれば、Javaのロックを使って、各データの主キーidをロックとして、idempotentを実装することができる。しかし、最近は基本的に分散サービスなので、前回の記事で述べたように、分散ロックRedissonLockを使って実装することができる。
最初のリクエストが同時に行われると、RedissonLockは競合し、ロックを取得した人が初期化メソッドを実行します。ロックを競合させないリクエストは、ロックが解放されるまでの待ち時間を設定することができます。ロック解放は、あなたが最初にデータがよく初期化されていない照会することができ、ライブラリに直接終了します。ここでは、どのようにRedissonLockを実装して待って言及することが重要ですか?
トライロック
RedissonLockはロックメソッドでwaitTimeというパラメータを提供するAPIを提供しており、このパラメータは待ち時間です。
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit)
メッセージはwaitTimeの間、redis自身のpublish-subscribe機能が使われ、購読されることになります。
RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {
if (!subscribeFuture.cancel(false)) {
subscribeFuture.onComplete((res, e) -> {
if (e == null) {
unsubscribe(subscribeFuture, threadId);
}
});
}
acquireFailed(threadId);
return false;
}
こうすることで、ロックが解除されると同時にメッセージが投稿されます。ロックを聞いているすべてのスレッドに通知され、これらのスレッドが再びロックを追加するために競争することで、必要なべき乗の機能が実現されるのです。ロックを解放するロジックを調べているのですが、メッセージを投稿しているのでしょうか?
unlockInnerAsync
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
"return nil;" +
"end; " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " + "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; "+
"end; " +
"return nil;",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));
}
unlockInnerAsyncメソッドの中で、luaスクリプトが実行され、そのスクリプトの中で、publishコマンドが実行されたことが簡単にわかると思います。
について考える
Redissonはredisのパブリッシュ・サブスクライブ機能を巧みに利用して、分散ロック待ち機能を実装しています。では、実際のビジネス・アプリケーションでredisのパブリッシュ・サブスクライブ機能を使う場合、他にどのようなシナリオがあるでしょうか?コメント欄で自由に議論してください
RedisにRedissonLockを実装してロック待ちをする方法については、この記事が全てです。RedissonLockの詳細については、スクリプトハウスの過去記事を検索するか、以下の関連記事を引き続き閲覧してください。
関連
-
RedisTemplatを使った簡単な分散ロックの実装の話
-
redisプラグインbloom-filterをcentosにインストールする方法
-
Redis永続化RDBとAOFの実装プロセス
-
インタビューFAQです。Redisキャッシュとデータベース間のデータ整合性を確保する方法
-
Redisによる分散シングルナンバーと分散ID(カスタムルール生成)
-
シングルスレッドのredisがなぜ速いのかの紹介
-
SpringBootがRedisの分散ロックを利用して並行処理の問題を解決することについて
-
Redisシングルスレッディングの正しい理解
-
Redisの文字列はどのように実装されているか
-
redis アプリケーション編 ---- スパイク、サインイン、セッション共有
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JAVAでRedisの5つのデータ構造を利用する方法
-
Redisによる分散ロック(setnx, getset, incr)の実装とタイムアウトの扱い方
-
SpringBootプロジェクトにおけるRedis。包括的なアプリケーション
-
redis クラスタの実装は同じプレフィックスを持つキーをクリーンアップします。
-
ジェディスはRedisを操作してCaptcha配信をシミュレートする
-
redis分散ロック最適化の実装
-
Redisの高同期スパイクを防ぐために、ソースコードソリューションを売られすぎ
-
Redisトランザクション処理の使用方法
-
Redisの分散ロックについて簡単に説明します
-
Redis の例外と使用法のまとめ