redis分散ロック最適化の実装
スタンドアロンアプリケーションでは、synchronizedキーワードやLockツールクラスを使って直接ロックを行うことができますが、分散アプリケーションでは、ロックを実装するためのツールが必要です。
ロック処理を平易に説明すると、次のようになります。
1.ピットを占拠する
2. ロジックを実行する
3. 穴埋め
この穴埋め作業をredisで行うことができます。
ロックの基本バージョン
//Get the lock by taking the pit
boolean lock = redis.setIfAbsent(key, value);
if (lock) {
//business logic
//fill the hole
redis.delete(lock)
}
ロックを取得した後にアプリケーションがダウンし、ロックが解除されないとデッドロックが発生する
ロックを取得する際に、ロックに有効期限を追加する必要があります。
redis.setIfAbsent(key, value);
redis.expire(key, value);
また、誤ってロックを取得した際に有効期限をうまく設定しないとデッドロックが発生することがあります
setとexpireの操作をluaスクリプトでアトミック操作にまとめ、有効期限を正常に設定できるようにする。
ロックが期限切れになっても、現在のタスクが終了していなければ、他のアプリケーションによってロックが取得される可能性があり、ロックのキーが更新され、現在のタスクがロックを解放し終わると、他の人のロックが解放されることになります
ロックを解除する。
- 現在のロックの値と自身のロックの値が一致するかどうかを判断する。
- 一致しない場合は解放しない。 値が一致した場合、ロックを解除するキーを削除する。
ロックを解放する際、キーの値が一致したと判断しても、その後キーの有効期限が切れてロックが他の人に取得された場合、キーを削除すると、他の人のロックを解放することになります
クエリ、判定、削除のロジックがアトミックな操作になるように、luaスクリプトを使用します。
ロック再連続性を保証する方法
再帰的なメソッドやその他の呼び出しにロックロジックがある場合、そのロジックは
lock.lock();
//logic
lock.lock();
//logic
lock.unLock();
lock.unLock();
リエントラントロックを実装するには、ロックの値を操作し、その値にリエントラントの数を記録し、ゼロになるまでリエントラントごとに1加算、アンロックごとに1減算し、キーを削除してロックを解除すればよいでしょう。
key:
{
"value":1
}
ビジネスロジックに時間がかかりすぎて、ロックが早く切れ、解除された場合はどうするか?
- 有効期限を長く設定する
- ロックに更新機能を追加する必要がある。
長い有効期限を設定することの欠点は、アプリケーションが停止した後、ロックが他の誰かによってアクセスされる前に長い時間を経験する必要がある場合、ビジネスに影響を与えるということです。
ロックがダウンした場合、より短い有効期限でロックもスワイプされる更新機能があれば、よりエレガントな解決策になります。
Redissionでロックを取得した場合、watchDogスレッドが起動し、現在のスレッドがまだロックを保持しているかどうかを監視し、保持している場合は更新される
10秒ごとにロックが保持されているかどうかを確認し、解除されていない場合はロックの有効期限をリセットして更新します。
アプリケーションがredisのマスターノードでロック取得に成功した場合、マスターノードがダウンしてスレーブノードにロックデータがまだ同期されておらず、マスター・スレーブ切り替え後に他のアプリケーションが分散ロック取得の機会を狙っている場合
レッドロック
マスター・スレーブ構造では問題があるのでは? redlockでは、マスター・スレーブ関係のない複数のredisMasterノードを使って、同時にダウンしないように、できれば合計数が奇数であるように切り替えます。
redLockは、複数のノードのロックを同時に取得し、半分以上のノードがロック取得に成功した場合のみ成功し、それ以外は失敗し、すべてのノードからロックを削除するためにロールバックすることで動作します。
参考資料
つまり、大きなRedisの分散ロックはこのように設計されているのです。
Redis分散ロック最適化に関する記事は以上です。redis分散ロック最適化については、Scripting Houseの過去記事を検索していただくか、引き続き以下の関連記事をご覧ください。
関連
-
redis の RedissonLock が待ちロックを実装する方法
-
Redisによる分散ロック(setnx, getset, incr)の実装とタイムアウトの扱い方
-
Redisの重複排除の3つの手法のまとめ
-
Redisで緯度・経度座標データを簡単に扱う方法
-
redis クラスタの実装は同じプレフィックスを持つキーをクリーンアップします。
-
Redisトランザクション処理の使用方法
-
マイクロサービス領域におけるredisの貢献度を説明する
-
Redisの分散ロックについて簡単に説明します
-
インストール後、Redis-cliが動作しない(redis-cli: コマンドが見つからない)。
-
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 実装 サイバーパンク風ボタン
おすすめ
-
redisキャッシュストレージのセッション原理機構
-
redis分散ロックについて解説(redis分散ロックの最適化処理とRedissonの利用について)
-
redisクラスタ構築プロセス (非常に詳細、初心者向け)
-
Redis永続化RDBとAOFの実装プロセス
-
redisでluaスクリプトを使用するためのチュートリアル
-
インタビューFAQです。Redisキャッシュとデータベース間のデータ整合性を確保する方法
-
Redisデータ永続化技術解説
-
Redisによる携帯電話認証コード配信の模倣例
-
RedisClusterが16,384個のスロットを持つ設計になっている理由
-
Redis の例外と使用法のまとめ