注:每天进步一点点,记录每日成长,思考的第04/365天 ;
本文预计阅读时间: 5分钟
Redis分布式锁解决电商订单库存并发问题。
基于Redis使用分布式锁已经不是什么新鲜事了。这篇文章分享的是使用redis分布式锁解决商品超卖事故的一个案例。
库存超卖问题是有很多种技术解决方案的,比如悲观锁,分布式锁,乐观锁,队列串行化,Redis原子操作,等等解决方案。
常见分布式锁解决方案:

三种分布式锁实现方式对比:
1、数据库分布式锁实现缺点:
1)db操作性能较差,且有锁表的风险;
2)非阻塞操作失败后,需要轮询,占用cpu资源;
3)长时间不commit或者长时间轮询,可能会占用较多连接资源。
2、ZK分布式锁实现缺点:
性能不如redis,因为其写操作(获取锁释放锁)都需要在Leader上执行,然后同步到follower。
3、Redis(缓存)分布式锁实现缺点:
1)过期时间不好控制;
2)非阻塞,操作失败后,需要轮询,占用cpu资源;
1
01
使用原生redis实现
使用原生Redis
的SetNX+
Expire实现的分布式锁。
//方案1 setnx
String lockKey = "zhyRedis";
//通过val,给锁设置唯一id,防止其他线程删除锁
String clientId = UUID.randomUUID().toString(); //或者雪花生成位置ID
boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS);
// redisTemplate.expire(lockKey,10,TimeUnit.SECONDS) //旧版本redis(新版直接设置在后面,如上)
//如果获取不到锁,则返回失败
if(!result){
result "failed";
}
try {
//如果能获取到锁,则返回成功
Integer count = Integer.parseInt(redisTemplate.opsForValue.get("count").toString());
if (count > 0) {
Integer realCount = count - 1;
System.out.Println("购买成功,剩余库存:" + realCount.toString());
redisTemplate.opsForValue().set("count",realCount.toString());
}else{
System.out.Println("购买失败,库存不足");
}
} catch(Exception e){
e.printStackTrace();
return "failed";
} finally{
//解锁
//判断当前客户端id与redis分布式中持有的客户端id一致,才能删除锁
if(clientId.equals(redisTemplate.opsForValue().get(lockKey))){
redisTemplate.delete(lockKey)
}
}
1
02
使用redisson实现
Redis的
SetNX+Expire实现的分布式锁而言,
Redisson的分布式锁组件可以解决原生
Redis组合命令带来的一些缺陷,即redis的超时时间值不知道设置为多少才合适。如果此时
Redis的服务器节点恰好出现宕机或者服务不能用的情况,那将会导致相应的
Key永远存于缓存中,即处于所谓的“永久被锁死”的状态!
Redisson内部提供了一个监控锁的看门狗
WatchDog,其作用在于
Redis实例被关闭之前,不断延长锁的有效期。
除此之外,Redisson
还通过加锁的方法提供了leaseTime
等参数来指定加锁的有效时间,即超过这个时间后“锁”便自动解开了。
//方案2 redisson
String lockKey = "zhyRedis";
RLock rLock = redisson.getLock(lockKey);
try {
rLock.lock(10, TimeUnit.SECONDS)
//如果能获取到锁,则返回成功
Integer count = Integer.parseInt(redisTemplate.opsForValue.get("count").toString());
if (count > 0) {
Integer realCount = count - 1;
System.out.Println("购买成功,剩余库存:" + realCount.toString());
redisTemplate.opsForValue().set("count",realCount.toString());
}else{
System.out.Println("购买失败,库存不足");
}
} catch(Exception e){
e.printStackTrace();
return "failed";
} finally{
//解锁
rLock.unlock();
}
文章转载自欢乐毅城,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




