基于Redis的原子操作优化秒杀逻辑
内容:
对于缓存中间件Redis,相信各位小伙伴或多或少都有听说过,甚至实战过,本文我们将基于SpringBoot整合Redis中间件,并基于其优秀的“单线程”特性和原子操作实现一种“分布式锁”,进而控制“高并发情况下多线程对于共享资源的访问”,最终解决“并发安全”,即“库存超卖”或者“重复秒杀”的问题!
(1)按照惯例,首先我们需要加入Redis的第三方依赖,如下所示:
org.springframework.boot
spring-boot-starter-redis
1.3.5.RELEASE
复制代码
然后,需要在application.properties配置文件中加入Redis服务所在的Host、端口Post、链接密钥Password等信息,如下所示:
(2)紧接着,我们还需要自定义注入跟Redis的操作组件相关的Bean配置,在这里主要是自定义注入配置RedisTemplate跟StringRedisTemplate操作组件,并指定其对应的Key、Value的序列化策略:
// redis的通用化配置
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate redisTemplate(){
RedisTemplate redisTemplate=new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//TODO:指定Key、Value的序列化策略
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
@Bean
public StringRedisTemplate stringRedisTemplate(){
StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
return stringRedisTemplate;
}
}复制代码
(3)至此,可以说是做好了充足的准备,接下来我们就可以拿来用了!为了区分之前的秒杀逻辑方法,我们开了一个新的秒杀逻辑方法killItemV3,并采用Redis的原子操作SETNX和EXPIRE方法来实现一种“分布式锁”,进而控制高并发多线程对共享资源的访问,其完整源代码如下所示:
//商品秒杀核心业务逻辑的处理-redis的分布式锁
@Override
public Boolean killItemV3(Integer killId, Integer userId) throws Exception {
Boolean result=false;
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
//TODO:借助Redis的原子操作实现分布式锁-对共享操作-资源进行控制
ValueOperations valueOperations=stringRedisTemplate.opsForValue();
final String key=new StringBuffer().append(killId).append(userId).append("-RedisLock").toString();
final String value=RandomUtil.generateOrderCode();
Boolean cacheRes=valueOperations.setIfAbsent(key,value);
if (cacheRes){
stringRedisTemplate.expire(key,30, TimeUnit.SECONDS);
try {
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}catch (Exception e){
throw new Exception("还没到抢购日期、已过了抢购时间或已被抢购完毕!");
}finally {
if (value.equals(valueOperations.get(key).toString())){
stringRedisTemplate.delete(key);
}
}
}
}else{
throw new Exception("Redis-您已经抢购过该商品了!");
}
return result;
}复制代码
在上述代码中,我们主要是通过以下几个操作综合实现了“分布式锁”的功能,其中包括
(1)valueOperations.setIfAbsent(key,value);:表示当前的Key如果不存在于缓存中,那么将设置值成功,反之,如果Key已经存在于缓存中了,那么设置值将不成功!通过这一特性,我们可以将“KillId和UserId的一一对应关系~即一个人只能抢到一个商品”组合在一起作为Key!
(2)设置了Key,那么就需要在某个时间点去释放,即stringRedisTemplate.expire(key,30, TimeUnit.SECONDS);操作可以辅助实现!
(3)然鹅,真正“释放锁”的操作是如下这段代码去实现的,即判断一下当前要释放的锁是否就是之前一开始获取到的锁,如果是,就释放!这一点可以很好的避免误删锁的问题!
if (value.equals(valueOperations.get(key).toString())){
stringRedisTemplate.delete(key);
}复制代码
至此,基于Redis的原子操作实现的分布式锁,进而控制高并发多线程对于共享资源的访问,从而解决秒杀场景下“库存超卖”、“重复秒杀”等问题,下面采用JMeter进行压测,压测的用户列表跟商品的“可秒杀数量total”跟上一篇章是一样的,即total=6本书,用户总共是10个。
点击JMeter的启动按钮,观察控制台的输出信息以及数据库表item_kill和item_kill_success表,可以看到秒杀记录的结果很是令人满意:
即库存为6本的商品~书籍恰好被10个用户中的6个秒杀得到!这种结果其实对于我们、对于用户来讲肯定是皆大欢喜的结局!
虽然演员对于自己的结局很满意,但是导演却察觉到戏中仍然有一些瑕疵!即如果秒杀系统在执行Redis的原子操作SetNX后、执行Expire之前,Redis的节点宕机了,那么此时将很有可能永久进入“Key锁死”的窘境,即重启之后,由于之前的Key没有得到释放,故而这个Key将永远存在于缓存中,即对应的用户将不能秒杀该商品了! 这一点确实是一个隐患!
既然存在隐患,那么我们就得想办法解决了!莫急,下一篇章我们继续!
需要java学习路线图的私信笔者“java”领取哦!另外喜欢这篇文章的可以给笔者点个赞,关注一下,每天都会分享Java相关文章!还有不定时的福利赠送,包括整理的学习资料,面试题,源码等~~
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一线互联网技术推荐:Java工程师架构知识系统化汇总(P8系列)
欢迎关注专栏:Java架构技术进阶。里面有大量batj面试题集锦,还有各种技术分享,如有好文章也欢迎投稿哦。 微信公众号:慕容千语的架构笔记。欢迎关注一起进步。根据高端招聘平台100 offer发布的Java人才盘点报告,在过去的2018年,Java仍然是最流行、招聘供需量最大的技术语言。 在此基础上,互联网行业针对 Java 开发的招聘需求,也是近年技术类岗位供需量最大,且变化最稳定的。企业对 Java 工程师发放的面邀数占比也远高于其他岗位,在100 offer平台上,Java工程师的需求占总需求的近60%,可以说,在当前各大公司“裁员”的背景下,Java工程师,尤其是资深Java工程师依旧是硬通货。 什么样的工程师才能被称为资深,又如何成为资深Java工程师呢? 从工作时间来看,资深工程师一般具备3-5年工作经验,企业对有 3-5 年经验的 Java工程师,都会要求算法基础和编程能力扎实,有分布式、高并发经验优先,可独立负责一个模块的开发。在技术上一专多能,不仅限于写好 Java,还要触类旁通,对公司业务所需的新技术能快速学习运用,以一个资深Java开发招聘为例: 从上面的招聘信...
- 下一篇
阿里毕玄:系统架构师如何做好系统设计?
阿里妹导读:毕玄是阿里巴巴资深技术专家,07年加入阿里,一手打造了HSF,十多年来更见证参与了阿里在基础技术上的演进与发展。他觉得系统设计是远比 Java 编程技能更难的培训,很容易变成务虚课。为了挑战难题,毕玄决定大胆尝试在内部搞了个民间培训。于是就有了今天的文章,希望这些深入浅出的解读能给架构师们带来一些收获。 阿里巴巴资深技术专家 毕玄 本文转自毕玄老师个人公众号:hellojavacases(不常更新,一更就是经典) 系统设计我一直觉得是远比Java编程技能更难多了的培训,很容易变成务虚课,全是一堆理论,所以,以前从来不敢尝试做这方面的培训,今年由于一些情况,决定大胆尝试下,就在内部搞了个民间的培训,还真有不少同学捧场。在开始上这门课后,我觉得收获最大的搞不好是我自己,整理思路,从和学员的互动中学习到了很多,能更好地对系统设计的
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS关闭SELinux安全模块