【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!! K8s概述:几种集群方案的对比 Linux到底该怎么学?RHCA架构师整理了300页学习笔记 到了2020年,技术水平到底需要达到怎样的程度才能成为顶级的阿里P8架构师 Linux怎么学?一张思维导图带你深入Linux核心原理 金九银十首战告捷!凭借这份Alibaba爆款“面试宝典”成功斩获美团Offer 大数据杀熟:我投之以元宝,它报之以砍刀! “物联网加持”下的社区长啥样儿? 潘云鹤院士:大数据智能是人工智能2.0的核心组成部分 防小孩和老人走失,定位精度达1厘米?上海社区为先进物联网产品提供落地场景 技术老兵十年专攻MySQL编写了763页核心总结,90MySQL问题全解 【Jenkins自动化部署】Windows节点Apache+Django服务自动化构建 Mybatis 使用通用 mapper 正道的光!阿里爆款Jenkins+K8s笔记终于全网开源了 不要死磕Java并发了,阿里P7架构师带你深入剖析synchronized的实现原理 EtherNet/IP协议基础知识(Part 1) CGB2005-京淘13 思科 OSPF协议简单配置与分析 在一家公司呆了 10 年的程序员,最后都怎么了? 致力物联网芯片研发,奕斯伟计算获逾20亿元融资 Unity性能优化技巧 纪念首次撸出来的编程题--2020深信服软件测试岗 qml 去除标题栏后 拖动窗口和改变窗口大小 如何舒服地在图书馆用ipad入门深度学习【windows jupyter远程】 力扣Java版个人代码分享-树篇( 107. 二叉树的层次遍历 II) 第十届蓝桥杯省赛java类B组 试题 E:迷宫 (动态规划之回溯法) Unity+罗技G29方向盘+Realistic Car Controller 制作简单的模拟驾驶 2020阿里笔试题解(9.11) 起飞!这份技术点拉满的ELk+Lucene笔记,可能价值百万 好文精选整理--Redis+Nginx+设计模式+Spring全家桶+SQL+Dubbo技术 覆盖全网的微服务架构笔记,看完还不懂你来打我 技术干货:JVM架构体系与GC命令全梳理,建议收藏 跪拜,阿里P9加班到凌晨,硬肝三个月推出这份IT架构运维实践 太厉害了,华为架构师终于整理出SSM+Nginx+Redis+SQL+微服务pdf 膜拜!终于有人总结出Spring+SpringMVC+MyBatis源码层PDF了 开发1-5年的Java程序员,该学习哪些知识实现涨薪30K? 云原生景观:供应层(Provisioning)介绍 vulhub学习笔记-struts2 S2-057 Remote Code Execution Vulnerablity远程代码执行 微服务启动报 Error creating bean with name ‘eurekaAutoServiceRegistration‘ 异常 「信息安全-密码与隐藏技术」RSA加密算法的实现(CPP 实现) 单例模式线程是否安全? DDCTF2020 Writeup 迭代器模式在开源代码中的应用 微信群总是有人发广告?看我用Python写一个自动化机器人消灭他! 极光大数据持续亏损,称风控产品数据涉10亿移动端用户、包括财产消费等信息,对外投资极贷管家 揭秘英飞凌最新安全芯片解决方案:为物联网设备量身定制,小封装易开发 蒙草大数据西乌旗智慧畜牧业系统建设取得新进展 移动转售产业与大数据产业交流座谈会即将召开 19-2!62比24!湖人4大数据碾压对手,夺赛点进西决稳了 Web前端程序员每天的工作都是做什么的?有哪些是必须要做的?
您的位置:首页 >运维 >

【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!!

写在前面

之前,我们在《【高并发】高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!》一文中,详细讲解了高并发秒杀系统的架构设计,其中,我们介绍了可以使用Redis存储秒杀商品的库存数量。很多小伙伴看完后,觉得一头雾水,看完是看完了,那如何实现呢?今天,我们就一起来看看Redis是如何助力高并发秒杀系统的!

秒杀业务

在电商领域,存在着典型的秒杀业务场景,那何谓秒杀场景呢。简单的来说就是一件商品的购买人数远远大于这件商品的库存,而且这件商品在很短的时间内就会被抢购一空。比如每年的618、双11大促,小米新品促销等业务场景,就是典型的秒杀业务场景。

秒杀业务最大的特点就是瞬时并发流量高,在电商系统中,库存数量往往会远远小于并发流量,比如:天猫的秒杀活动,可能库存只有几百、几千件,而瞬间涌入的抢购并发流量可能会达到几十到几百万。

所以,我们可以将秒杀系统的业务特点总结如下。

(1)限时、限量、限价

在规定的时间内进行;秒杀活动中商品的数量有限;商品的价格会远远低于原来的价格,也就是说,在秒杀活动中,商品会以远远低于原来的价格出售。

例如,秒杀活动的时间仅限于某天上午10点到10点半,商品数量只有10万件,售完为止,而且商品的价格非常低,例如:1元购等业务场景。

限时、限量和限价可以单独存在,也可以组合存在。

(2)活动预热

需要提前配置活动;活动还未开始时,用户可以查看活动的相关信息;秒杀活动开始前,对活动进行大力宣传。

(3)持续时间短

购买的人数数量庞大;商品会迅速售完。

在系统流量呈现上,就会出现一个突刺现象,此时的并发访问量是非常高的,大部分秒杀场景下,商品会在极短的时间内售完。

秒杀三阶段

通常,从秒杀开始到结束,往往会经历三个阶段:

准备阶段:这个阶段也叫作系统预热阶段,此时会提前预热秒杀系统的业务数据,往往这个时候,用户会不断刷新秒杀页面,来查看秒杀活动是否已经开始。在一定程度上,通过用户不断刷新页面的操作,可以将一些数据存储到Redis中进行预热。秒杀阶段:这个阶段主要是秒杀活动的过程,会产生瞬时的高并发流量,对系统资源会造成巨大的冲击,所以,在秒杀阶段一定要做好系统防护。结算阶段: 完成秒杀后的数据处理工作,比如数据的一致性问题处理,异常情况处理,商品的回仓处理等。

Redis助力秒杀系统

我们可以在Redis中设计一个Hash数据结构,来支持商品库存的扣减操作,如下所示。

seckill:goodsStock:${goodsId}{totalCount:200,initStatus:0,seckillCount:0}

在我们设计的Hash数据结构中,有三个非常主要的属性。

totalCount:表示参与秒杀的商品的总数量,在秒杀活动开始前,我们就需要提前将此值加载到Redis缓存中。initStatus:我们把这个值设计成一个布尔值。秒杀开始前,这个值为0,表示秒杀未开始。可以通过定时任务或者后台操作,将此值修改为1,则表示秒杀开始。seckillCount:表示秒杀的商品数量,在秒杀过程中,此值的上限为totalCount,当此值达到totalCount时,表示商品已经秒杀完毕。

我们可以通过下面的代码片段在秒杀预热阶段,将要参与秒杀的商品数据加载的缓存。

/** * @author binghe * @description 秒杀前构建商品缓存代码示例 */public class SeckillCacheBuilder{private static final String GOODS_CACHE = "seckill:goodsStock:"; private String getCacheKey(String id) { returnGOODS_CACHE.concat(id);} public void prepare(String id, int totalCount) { String key = getCacheKey(id); Map<String, Integer> goods = new HashMap<>(); goods.put("totalCount", totalCount); goods.put("initStatus", 0); goods.put("seckillCount", 0); redisTemplate.opsForHash().putAll(key, goods);}}

秒杀开始的时候,我们需要在代码中首先判断缓存中的seckillCount值是否小于totalCount值,如果seckillCount值确实小于totalCount值,我们才能够对库存进行锁定。在我们的程序中,这两步其实并不是原子性的。如果在分布式环境中,我们通过多台机器同时操作Redis缓存,就会发生同步问题,进而引起“超卖”的严重后果。

在电商领域,有一个专业名词叫作“超卖”。顾名思义:“超卖”就是说卖出的商品数量比商品的库存数量多,这在电商领域是一个非常严重的问题。那么,我们如何解决“超卖”问题呢?

Lua脚本完美解决超卖问题

我们如何解决多台机器同时操作Redis出现的同步问题呢?一个比较好的方案就是使用Lua脚本。我们可以使用Lua脚本将Redis中扣减库存的操作封装成一个原子操作,这样就能够保证操作的原子性,从而解决高并发环境下的同步问题。

例如,我们可以编写如下的Lua脚本代码,来执行Redis中的库存扣减操作。

local resultFlag = "0" local n = tonumber(ARGV[1]) local key = KEYS[1] local goodsInfo = redis.call("HMGET",key,"totalCount","seckillCount") local total = tonumber(goodsInfo[1]) local alloc = tonumber(goodsInfo[2]) if not total then return resultFlag end if total >= alloc + nthen local ret = redis.call("HINCRBY",key,"seckillCount",n) return tostring(ret) end return resultFlag

我们可以使用如下的Java代码来调用上述Lua脚本。

public int secKill(String id, int number) { String key = getCacheKey(id); Object seckillCount =redisTemplate.execute(script, Arrays.asList(key), String.valueOf(number)); return Integer.valueOf(seckillCount.toString()); }

这样,我们在执行秒杀活动时,就能够保证操作的原子性,从而有效的避免数据的同步问题,进而有效的解决了“超卖”问题。

好了,今天就聊到这儿吧!别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!!

冰 河CSDN认证博客专家hivestormhadoop微信搜一搜【冰河技术】,关注这个有深度的程序员,每天阅读超硬核技术干货,回复【PDF】有我准备的一线大厂面试资料和简历模板(不断更新中),希望大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过努力成功进入到了心仪的公司,一定不要懈怠放松,职场成长和新技术学习一样,不进则退。如果有幸我们江湖再见!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。