次のコードの問題を分析してください:
// 分布式锁服务 public interface RedisLockService { // 获取锁 public boolean getLock(String key); // 释放锁 public boolean releaseLock(String key); } // 业务服务 public class BizService { @Resource private RedisLockService redisLockService; public void bizMethod(String bizId) { try { // 获取锁 if(redisLockService.getLock(bizId)) { // 业务重复校验 if(!bizValidate(bizId)) { throw new BizException(ErrorBizCode.REPEATED); } // 执行业务 return doBusiness(); } // 获取锁失败 throw new BizException(ErrorBizCode.GET_LOCK_ERROR); } finally { // 释放锁 redisLockService.releaseLock(bizId); } } }
上記のコードは次のようです。いいですよ、実はこれには大きな問題が隠されています。問題は、ロックを解放するときに、現在のスレッドがロックを取得したかどうかが検証されないことです。
スレッド 1 とスレッド 2 が同時にビジネス メソッドにアクセスします
スレッド 2 ロックの取得に成功し、業務処理を実行します
スレッド 1 はロックの取得に失敗しましたが、ロックの解放に成功しました
この時点で、スレッド 3 はロックを取得しようとしました。ロックは成功しましたが、スレッド 2 の業務は処理されていないため、スレッド 3 は業務重複例外を引き起こしません。
最終的には、スレッド 2 とスレッド 3 が繰り返しビジネスを実行します
解決策は、確認した後にのみロックを解放できるようにすることです。ロックの取得が成功したことを確認します:
public class BizService { @Resource private RedisLockService redisLockService; public void bizMethod(String bizId) { boolean getLockSuccess = false; try { // 尝试获取锁 getLockSuccess = redisLockService.getLock(bizId); // 获取锁成功 if(getLockSuccess) { // 业务重复校验 if(!bizValidate(bizId)) { throw new BizException(ErrorBizCode.REPEATED); } // 执行业务 return doBusiness(); } // 获取锁失败 throw new BizException(ErrorBizCode.GET_LOCK_ERROR); } finally { // 获取锁成功才允许释放锁 if(getLockSuccess) { redisLockService.releaseLock(bizId); } } } }
いいえ。2 番目の問題は、Redis にはメモリ クリーニング メカニズムもあり、分散ロックが失敗する可能性があることです。 。
(1) 定期的な削除
Redis は定期的にどのキーの有効期限が切れているかを確認し、有効期限が切れていることが判明した場合は削除します。期限切れ
(2) 遅延削除
#キーが多すぎる場合、通常の削除では大量のリソースが消費されるため、遅延削除戦略が導入されますRedis がアクセス時にキーの有効期限が切れていることが判明した場合は、直接削除します。2.2 メモリ リサイクル メカニズムメモリが不足している場合、Redis は削除する要素をいくつか選択します:no-envictionデータのエビクションを禁止します、新規です書き込み操作はエラーを報告しますvolatile-lruデータ セットから最も最近使用されていないデータを選択します削除する有効期限volatile-ttl 削除する有効期限が設定されたデータセットから期限切れにするデータを選択しますvolatile-random
有効期限が設定されたデータ セットから削除するデータを選択しますallkeys- lru削除するデータ セットから最も最近使用されていないデータを選択します allkeys-random削除するデータ セットから任意のデータを選択してください分散ロック障害の問題を引き起こすシナリオは少なくとも 2 つあります:
allkeys-lru または
allkeys-random を使用してください。リサイクル戦略によりロックが失敗します
rree
以上がRedis 分散ロックで避けなければならない 2 つの落とし穴は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。