Redis分散ロックの詳細手順について
3465 ワード
Redis分散ロックの詳細手順について
簡単に言えばRedis分布式ロックの秒殺原理
まず、1つの事実を明らかにしなければならない:秒殺期間中に1000個の要求が10個しかロックを取得できず、秒殺に成功した要求の残り990個が異常を投げ出す(分散ロックが取れないため)これが秒殺分布式ロックによる結果である(無数の要求がロックを取得しようとした)redis操作に関する方法を明らかにしなければならない:StringRedisTemplate.opsForValue().setIfAbsent(key,value)->原子間設定keyとvalue(このkeyが存在しない場合:trueが存在する場合:falseは変更しない)StringRedisTemplate.opsForValue().get(key)->value StringRedisTemplateを取得する.opsForValue().getAndSet(key,value)->原子性valueを取得してから独自のvalue値を設定する
スタートコード構想key:商品ID value:現在時間+タイムアウト時間
ロックコード構想開始:keyとvalueの設定
1.開始:無数のリクエストが分散ロックを持つ.判断(予想結果:このkeyが存在する/存在しない):setIfAbsent(key,value)原子性設定と、このkey(true/falseを返す)が存在しないかどうかをチェックする独自のkeyとvalueを設定し、存在はfalseに直接戻る(keyとvalueに設定できるスレッドは1つしかない).(このkeyは存在しない)trueを返す(分散ロックが成功したことを意味する).(このkeyが存在する)取得:get(key)複数のスレッドが現在のcurrentvalue 5を同時に取得する.判断(予想結果:ロックの期限切れ&¤tvalueがnull/currentvalueがnull/ロックの期限切れではない):タイムアウトしているかどうかを確認し、現在のcurrentvalueがnullではないことを確認し、現在の時間をcurrentvalueと比較する.取得と設定(ロックが期限切れ):複数のスレッドが原子的に前のcurrentvalue 2を再取得し始め、自分のvalueを設定します(同時に1つのスレッドしか設定できません)6.1(複数のスレッドが可能です)まで判断します(ロックが期限切れです)(予想結果:currentvalue 2はcurrentvalueと一致します&¤tvalueはnullではありません):ここでは、最初にvalueを修正してtrueを判断してロックを成功させるしかありません.その後のスレッドは、前のスレッドで変更されたvalueを取得します.6.2(currentvalue 2はcurrentvalueと一致&¤tvalueはnullではない)分布ロック成功7.(ロックが期限切れ/currentvalueがnull)このスレッドは直接例外を放出します.
コード:
ロック解除コード構想開始:keyとvalueのクリア
現在のvalue値と等しいかどうかをvalue値で判断し始めます.等しい場合はkeyとvalueをクリアします.
コード:
コード推定
タイムアウト条件が成立する場合、デッドロックが存在する可能性があります:(実際にはデッドロックは存在しません)コードは百万の要求を連続的に受け取り、ロックをかけたときに前のロックがタイムアウトしたと判断すると、複数のスレッドが入ってきてredisTemplateを順次実行する可能性があります.opsForValue().getAndSet(key, value); この文.最初のスレッドを除いたスレッドが取得ロックに入るのをフィルタします.ただしvalueは、ロックが期限切れになったと判断した後、最後のスレッドが設定したvalue値であり、スレッドがロック解除されたときに現在のcurrentvalueが表示されます!=valueはロックを解除できないため、一時的なデッドロックから離脱するには1つの状況を待つ必要があります.つまり、今回のロックが期限切れになったと判断した場合、value値を修正するスレッドが1つしか入ってこない場合、スムーズにロックを取得してロックを解除することができますが、前にロックを解除できない場合は論理実行が完了している可能性があります.
簡単に言えばRedis分布式ロックの秒殺原理
まず、1つの事実を明らかにしなければならない:秒殺期間中に1000個の要求が10個しかロックを取得できず、秒殺に成功した要求の残り990個が異常を投げ出す(分散ロックが取れないため)これが秒殺分布式ロックによる結果である(無数の要求がロックを取得しようとした)redis操作に関する方法を明らかにしなければならない:StringRedisTemplate.opsForValue().setIfAbsent(key,value)->原子間設定keyとvalue(このkeyが存在しない場合:trueが存在する場合:falseは変更しない)StringRedisTemplate.opsForValue().get(key)->value StringRedisTemplateを取得する.opsForValue().getAndSet(key,value)->原子性valueを取得してから独自のvalue値を設定する
スタートコード構想key:商品ID value:現在時間+タイムアウト時間
ロックコード構想開始:keyとvalueの設定
1.開始:無数のリクエストが分散ロックを持つ.判断(予想結果:このkeyが存在する/存在しない):setIfAbsent(key,value)原子性設定と、このkey(true/falseを返す)が存在しないかどうかをチェックする独自のkeyとvalueを設定し、存在はfalseに直接戻る(keyとvalueに設定できるスレッドは1つしかない).(このkeyは存在しない)trueを返す(分散ロックが成功したことを意味する).(このkeyが存在する)取得:get(key)複数のスレッドが現在のcurrentvalue 5を同時に取得する.判断(予想結果:ロックの期限切れ&¤tvalueがnull/currentvalueがnull/ロックの期限切れではない):タイムアウトしているかどうかを確認し、現在のcurrentvalueがnullではないことを確認し、現在の時間をcurrentvalueと比較する.取得と設定(ロックが期限切れ):複数のスレッドが原子的に前のcurrentvalue 2を再取得し始め、自分のvalueを設定します(同時に1つのスレッドしか設定できません)6.1(複数のスレッドが可能です)まで判断します(ロックが期限切れです)(予想結果:currentvalue 2はcurrentvalueと一致します&¤tvalueはnullではありません):ここでは、最初にvalueを修正してtrueを判断してロックを成功させるしかありません.その後のスレッドは、前のスレッドで変更されたvalueを取得します.6.2(currentvalue 2はcurrentvalueと一致&¤tvalueはnullではない)分布ロック成功7.(ロックが期限切れ/currentvalueがnull)このスレッドは直接例外を放出します.
コード:
/**
*
* @param key
* @param value +
* @return
*/
private StringRedisTemplate redisTemplate;
public boolean lock(String key, String value) {
// ( key value)
if(redisTemplate.opsForValue().setIfAbsent(key, value)) {
//
return true;
}
//currentValue=A value B
String currentValue = redisTemplate.opsForValue().get(key);
//
if (!StringUtils.isEmpty(currentValue)
&& Long.parseLong(currentValue) < System.currentTimeMillis()) {
//
log.info(" !!!");
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
return true;
}
}
return false;
}
ロック解除コード構想開始:keyとvalueのクリア
現在のvalue値と等しいかどうかをvalue値で判断し始めます.等しい場合はkeyとvalueをクリアします.
コード:
/**
*
* @param key
* @param value
*/
public void unlock(String key, String value) {
try {
String currentValue = redisTemplate.opsForValue().get(key);
// redis value
if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
// redis key value
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e) {
log.error("【redis 】 , {}", e);
}
}
コード推定
タイムアウト条件が成立する場合、デッドロックが存在する可能性があります:(実際にはデッドロックは存在しません)コードは百万の要求を連続的に受け取り、ロックをかけたときに前のロックがタイムアウトしたと判断すると、複数のスレッドが入ってきてredisTemplateを順次実行する可能性があります.opsForValue().getAndSet(key, value); この文.最初のスレッドを除いたスレッドが取得ロックに入るのをフィルタします.ただしvalueは、ロックが期限切れになったと判断した後、最後のスレッドが設定したvalue値であり、スレッドがロック解除されたときに現在のcurrentvalueが表示されます!=valueはロックを解除できないため、一時的なデッドロックから離脱するには1つの状況を待つ必要があります.つまり、今回のロックが期限切れになったと判断した場合、value値を修正するスレッドが1つしか入ってこない場合、スムーズにロックを取得してロックを解除することができますが、前にロックを解除できない場合は論理実行が完了している可能性があります.