Redisベースの分散ロック---redisTemplate
2531 ワード
分散ロックアプリケーションシーンの多くは、高同時、大流量シーンで使用されます.複数のプロセスが同じシステムにない場合、分散ロックで複数のプロセスのリソースへのアクセスを制御する必要があります.本編ではRedisベースの分散ロックについて説明する.まず2つのRedisのコマンドを見てみましょう.
キーをvalueに設定し、キーが存在しない場合はSETコマンドと同等です.keyが存在するとき、何もしません.SETNXは「SET if Not eXists」の略です.
keyをvalueに自動的に対応させ、元のkeyに対応するvalueを返します.keyが存在しますが、対応するvalueが文字列ではない場合は、エラーが返されます.
秒殺を例にとると、Redisに基づいて実現される分散ロックは、実は秒殺の方法の前後でロックを加え、ロックを解除する操作を行う.
次に、Redis分散ロックの処理を新規作成し、ロックとロック解除を書きます.
使うのは簡単です
この方法で実装される分散ロックには欠点がありますが、詳細は次のブログをクリックしてください.
SETNX key value
キーをvalueに設定し、キーが存在しない場合はSETコマンドと同等です.keyが存在するとき、何もしません.SETNXは「SET if Not eXists」の略です.
GETSET key value
keyをvalueに自動的に対応させ、元のkeyに対応するvalueを返します.keyが存在しますが、対応するvalueが文字列ではない場合は、エラーが返されます.
秒殺を例にとると、Redisに基づいて実現される分散ロックは、実は秒殺の方法の前後でロックを加え、ロックを解除する操作を行う.
public void orderProductMockDiffUser(String productId) {
//
// ...
//
}
次に、Redis分散ロックの処理を新規作成し、ロックとロック解除を書きます.
@Component
@Slf4j
public class RedisLock {
@Resource
private StringRedisTemplate redisTemplate;
/**
*
* @param key
* @param value +
* @return
*/
public boolean lock(String key, String value) {
//SETNX , true, false
if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
//
if (StringUtils.isEmpty(currentValue) && (Long.parseLong(currentValue) < System.currentTimeMillis())) {
//GETSET ,
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(value)) {
return true;
}
}
return false;
}
/**
*
*/
public void unLock(String key, String value) {
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Throwable e) {
log.error("[redis ] , {}", e.getMessage(), e);
}
}
}
使うのは簡単です
private static final int TIMEOUT = 10 * 1000; // 10
@Autowired
private RedisLock redisLock;
/**
*
*/
public void orderProductMockDiffUser(String productId) {
//
long time = System.currentTimeMillis() + TIMEOUT;
if(!redisLock.lock(productId, String.valueOf(time))) {
throw new SellException(101, " , ~");
};
//...
//
redisLock.unLock(productId, String.valueOf(time));
}
この方法で実装される分散ロックには欠点がありますが、詳細は次のブログをクリックしてください.