分散ロックが解決する必要がある問題
相互排他性: いつでも 1 つのクライアントのみがロックを所有できます。一度に複数のクライアントは所有できません。同時にクライアントの取得
#セキュリティ: ロックを削除できるのはロックを保持しているユーザーのみであり、他のユーザーは削除できません (推奨学習:Redis ビデオ チュートリアル)# # デッドロック: ロックを取得したクライアントが何らかの理由でクラッシュし、ロックの解放に失敗しました。他のクライアントはロックを取得できません。この種の問題を回避するにはメカニズムが必要です。
フォールト トレランス:ノードはダウンしていますが、クライアントは引き続きロックを取得または解放できます
Redis を介して分散ロックを実装する方法: (完全ではない方法)SETNX キーの値 :
キーが存在しない場合は、値を作成して割り当てます時間計算量:0(1)
戻り値:設定が成功した場合は 1 が返されます。 ; 設定に失敗した場合は0が返されます。
しかし、今回取得したキーは長期間有効なので、長期有効性の問題をどのように解決すればよいでしょうか?EXPIRE key 秒数
キーの生存時間を設定します。キーの有効期限が切れると (生存時間が 0 になると)、キーは自動的に削除されます
欠点: 原子性が満たされていない
以下は疑似コードです//该程序存在危险,如果执行到第二行就崩溃了,则此时key会被一直占用而无法被释放
RedisService redisService = SpringUtils.getBean(Redi sService.class);
long status = redisService.setnx(key, "1");
if(status == 1) {
redisService.expire(key, expire);
//执行独占资源逻辑
doOcuppiedWork();
}
SET key value [EX seconds] [PX milliseconds] [NX|XX]
PX ミリ秒: キーの有効期限をミリ秒ミリ秒に設定します。
NX: 次の場合のみキーが存在しません。キーがすでに存在する場合にのみキーを設定します。
XX: キーがすでに存在する場合にのみキーを設定します。
SET 操作が正常に完了した場合は、OK を返します。それ以外の場合は、OK を返します。 return nil
以下は疑似コードですRedisService redisService = SpringUtils.getBean(RedisService.class); .
String result = redisService.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if ("OK".equals(result)) {
//执行独占资源逻辑
doOcuppiedWork();
}
集中有効期限切れ多数のキーのクリアには時間がかかるため、短期的なラグが発生します。
解放計画: キーの有効期限を設定するときに、各キーにランダムな値を追加します
Redis 関連の技術記事の詳細については、
Redis Introduction Tutorial以上がRedis が分散ロックを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。