Redisson
,字如其名,是搭建在缓存中间件Redis
基础上的一款综合中间件,除了拥有Redis
本身提供的强大功能外,还提供了诸如分布式锁、分布式服务、延迟队列、远程调用等强大的功能。
从名字上就可以看出来:Redis + son,犹如Redis
的儿子,儿子不仅继承了老爸强大的血脉,而且还自己修炼、发展出了属于自己的一套本领…..
Redisson
开源地址为https://github.com/redisson/redisson/wiki/目录
△ Redisson官网首页截图
本文我们将使用中间件Redisson
中强大的功能组件“分布式锁”,来解决高并发下多线程导致的超卖以及重复秒杀等安全问题。
在正文开始之前,先来解决一个问题:为什么要用Redisso,而不是Redis?
相较于原生Redis
的SetNX+Expire
实现的分布式锁而言,Redisson
的分布式锁组件可以解决原生Redis
组合命令带来的一些缺陷,即在执行SetNX
命令之后,在还没来得及执行Expire
操作之前,如果此时Redis
的服务器节点恰好出现宕机或者服务不能用的情况,那将会导致相应的Key
永远存于缓存中,即处于所谓的“永久被锁死”的状态!
而Redisson
的分布式锁则可以很好地解决这种问题,其底层的实现机制在于:Redisson
内部提供了一个监控锁的看门狗WatchDog
,其作用在于Redis
实例被关闭之前,不断延长锁的有效期。除此之外,Redisson
还通过加锁的方法提供了leaseTime
等参数来指定加锁的有效时间,即超过这个时间后“锁”便自动解开了。
下面我们将加入相关的依赖Jar及其配置,使用“分布式锁”组件,来解决秒杀过程中出现的“库存超卖”、“重复秒杀”等并发安全问题。
org.redisson
redisson
3.8.2
然后需要在配置文件application.properties
中加入Redis
服务所在的服务器节点Host
、端口Port
等信息,如下所示:
redis.config.host=redis://127.0.0.1:6379
spring.redis.password=
其自定义注入Bean组件的源代码如下所示:
@Configuration
public class RedissonConfig {
@Autowired
private Environment env;
@Bean
public RedissonClient redissonClient(){
Config config=new Config();
config.useSingleServer()
.setAddress(env.getProperty("redis.config.host"))
.setPassword(env.getProperty("spring.redis.password"));
RedissonClient client=Redisson.create(config);
return client;
}
}
在KillService
服务类中我们开辟了一个新的处理方法,即killItem
,其完整的源码如下所示:
@Autowired
private RedissonClient redissonClient;
//秒杀核心业务逻辑的处理-redisson分布式锁
@Override
public Boolean killItem (Integer killId, Integer userId) throws Exception {
Boolean result=false;
final String lockKey=new StringBuffer().append(killId).append("-RedissonLock").toString();
RLock lock=redissonClient.getLock(lockKey);
try {
//TODO:第一个参数30s=表示尝试获取锁,并且最大等待获取锁的时间为30s
//TODO:第二个参数10s=表示上锁之后,10s内操作完毕将自动释放锁
Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS);
if (cacheRes){
//TODO:核心业务逻辑的处理
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
ItemKill itemKill=itemKillMapper.selectById(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItem(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception("redisson-您已经抢购过该商品了!");
}
}
}finally {
//TODO:释放锁
lock.unlock();
}
return result;
}
从该源代码中,我们主要利用了Redisson
分布式锁中的“可重入锁”组件,其使用过程需要经过如下几个步骤:
A.需要尝试去获取锁,其对应的代码以及注释如下所示,
//TODO:第一个参数30s=表示尝试获取分布式锁,并且最大的等待获取锁的时间为30s
//TODO:第二个参数10s=表示上锁之后,10s内操作完毕将自动释放锁
Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS);
B.在获取到锁之后,即cacheRes=true
,即可进入秒杀核心业务代码的执行;同时在处理完成之后,需要释放锁,如下所示:
//TODO:释放锁
lock.unlock();
接下来进入压测环节,压测之前设定待秒杀商品的可秒杀总数total=6
,并设置随机可选取的用户ID列表
的总数为10个,其取值为10040~10049;
在压测完成之后,理论上最好的结果是:total
最终变为=0,同时item_kill_success
数据库表中有 6 条秒杀成功而生成的订单记录。
此时,我们尝试将线程组中并发的线程数调整为10w,点击启动按钮,稍等片刻,观察控制台的输出信息以及item_kill
和item_kill_success
这两个数据库表的数据变化情况,并查看其最终的记录结果,如下图所示:
对于这一结果,其实可以说是预料之中了!!!
经过反复压测、可以得出结论:Redisson
的分布式锁确实可以解决多线程高并发场景中并发安全性问题。
本文详细内容在笔者录制的视频课中有更详细的介绍。感兴趣的读者可以扫码了解课程详情。
????今日特惠!
《Java 架构师全套实战课》
从技术栈到企业项目实战
10+技术栈&50+应用案例&5大企业级项目实战
原价1042元,线下售价高达8000多
今日特惠直降,仅需 ¥199
????长按识别扫描二维码,立即秒杀
01
为什么推荐这门课?
▋项目驱动,解锁实战经验
课程以当前正火爆的Spring Boot为主线,将10+主流技术栈与50+应用案例结合,并精选5大企业级项目进行实战,真正将所学理论应用到实际项目中!
▋完善的学习路径,3大阶段逐层递进
本系列课程共3个阶段,每个阶段都具有相应的关联性,是一层嵌一层,逐层递进。
▋还原架构演进过程,从0到1做项目
课程并不是割裂的,而是从需求分析开始到最终运行测试的完整闭环,让你学到的不仅仅是知识点、项目案例,更是一个完整的项目从需求分析到落地实施的全流程。
上下滑动查看更多↑↑↑
02
谁来教你?
讲师是前阿里高级后端开发工程师钟林森。
畅销书《分布式中间件技术实战(Java版)》《Spring Boot企业级项目开发-入门到精通》作者;程序员实战基地-fightjava.com 创始人;长期扎根于一线撸码开发与系统架构设计!
03
购课福利
现在购买,你可以马上获得以下福利:
1、主讲老师社群答疑,解决学习问题!
2、源码及课件等资料,全部赠送!
3、覆盖多领域的高品质直播课,0元学!
4、互联网大厂高频面试考题,免费分享!
此外,还赠送给你 5 门强化学习效果的程序员精品课,仅限今日!
再次提醒您
原价 ¥1042
今日特惠,仅需199元
还等什么,立即扫码抢购
你最关心的问题
Q:如何学习?有效期多久?
A:购课后登陆「程序员学院」APP或者 CSDN 学院官网,随时可学,并且永久有效。
Q:如何领取价值500元的精品课程?
A:购课后扫码添加下方微信,获得讲师答疑服务,并领取价值500元的精品课程。
Q:学习时遇到不懂的问题怎么办?
A:遇到问题可以随时在交流群,与授课老师或者助教进行沟通。
阅读原文,低价抢课!