【Redis】Redis实现企业级秒杀场景实战(Redis专栏实战启动)

📫作者简介:小明java问道之路,2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公司后端高级工程师。
📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
🏆 2022博客之星TOP3 | CSDN博客专家 | 后端领域优质创作者 | CSDN内容合伙人
🏆 InfoQ(极客邦)签约作者、阿里云专家 | 签约博主、51CTO专家 | TOP红人、华为云享专家
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
🍅 文末获取联系 🍅 👇🏻 精彩专栏推荐订阅收藏 👇🏻
专栏系列(点击解锁)
学习路线(点击解锁)
知识定位
🔥Redis从入门到精通与实战🔥
Redis从入门到精通与实战
围绕原理源码讲解Redis面试知识点与实战
🔥MySQL从入门到精通🔥
MySQL从入门到精通
全面讲解MySQL知识与企业级MySQL实战 🔥计算机底层原理🔥
深入理解计算机系统CSAPP
以深入理解计算机系统为基石,构件计算机体系和计算机思维
Linux内核源码解析
围绕Linux内核讲解计算机底层原理与并发
🔥数据结构与企业题库精讲🔥
数据结构与企业题库精讲
结合工作经验深入浅出,适合各层次,笔试面试算法题精讲
🔥互联网架构分析与实战🔥
企业系统架构分析实践与落地
行业最前沿视角,专注于技术架构升级路线、架构实践
互联网企业防资损实践
互联网金融公司的防资损方法论、代码与实践
🔥Java全栈白宝书🔥
精通Java8与函数式编程
本专栏以实战为基础,逐步深入Java8以及未来的编程模式
深入理解JVM
详细介绍内存区域、字节码、方法底层,类加载和GC等知识
深入理解高并发编程
深入Liunx内核、汇编、C++全方位理解并发编程
Spring源码分析
Spring核心七IOC/AOP等源码分析
MyBatis源码分析
MyBatis核心源码分析
Java核心技术
只讲Java核心技术
本文目录
一、秒杀系统分析
二、秒杀系统整体设计
1、前端预处理
2、Redis全链路支持
三、Redis实现库存扣减
1、为什么库存扣减不放到数据库中
2、基于Redis分布式锁的扣减库存
3、基于lua脚本(原子性)的扣减库存
总结
本文导读
本文首先对秒杀系统进行整体分析,通过分析得出前端预处理、Redis全链路支持的秒杀系统整体的设计,最后给出Redis实现库存扣减,为什么不放到数据库中,以及使用Redis分布式锁、lua脚本的两种实现。
一、秒杀系统分析
秒杀活动一般是传统电商和直播电商吸引人气的活动,会对部分商品进行低价秒杀销售。秒杀活动的持续时间很短,但访问量很大,秒杀系统需要一个能够应对这种爆炸性和类似攻击的访问模型。
由于对业务前端的访问量巨大,系统对后端数据的访问也将在短时间内爆发。因此,需要设计好数据存储资源。虽然秒杀活动的持续时间很短,但在活动期间会给整个业务系统带来巨大的负载。业务系统需要制定各种策略以避免系统过载和停机。
此外业务请求的数量远远大于销售量。其中大多数是无法成功购买的请求,系统需要提前规划处理策略(请求失败策略),由于销售活动中商品价格低廉,存在套利空间,各种非法欺诈手段层出不穷,因此需要提前制定预防策略(防刷防黄牛防黑灰产机制等等)。
二、秒杀系统整体设计

1、前端预处理
在秒杀活动之前,用户会不断刷新商详页,这将导致详情页面的瞬时请求量急剧增加。一般的解决方案是尝试使业务详细信息页面的页面元素静态,然后使用CDN或浏览器来存储这些静态元素。这样大量请求可以通过CDN或浏览器直接缓存,不会到达服务器,从而降低了服务器的压力。
在Web服务器中执行各种服务预处理,检查用户的访问权限,并识别并发刷单行为。同时,在真正服务之前,还应进行服务前检查,以避免过度销售。如果发现售出数量已达到秒数,则直接结束。
2、Redis全链路支持
秒杀简而言之,有三个操作:库存检查、库存扣减和订单处理。
因为每个秒杀请求都会查询库存,只有在请求找到库存余额后,才会执行后续的库存扣减和订单处理。因此,这一阶段最大的并发压力是库存检查操作。为了支持大量高度并发的库存检查请求,我们需要在这一阶段使用Redis保存库存,以便请求可以直接从Redis读取库存并进行检查。
订单处理需要在数据库维度中执行。订单处理将涉及多个相关操作,如付款、货物交付、物流等。这些操作本身涉及数据库中的多个数据表,为了确保处理的事务,需要在数据库中完成,同时预防资损问题。
除此之外,在处理业务请求时,所有操作都应尽可能通过Redis缓存交互完成。因为秒杀商品的时间很少,所有相关信息都加载到内存中,缓存暂时用作存储,不会带来太大的成本负担。为秒杀产品建立商品信息缓存,并预热和加载所有目标产品。同时,为秒杀产品构建独立的库存缓存,以加快库存检测。这样,我们可以通过秒杀商品列表的缓存快速查询商品的信息。通过库存缓存,我们可以快速确定秒杀活动的过程,并便于在高效交易或非销售商品后快速检测和退货。在用户抢购商品后,他们需要交易、修改库存、付款和结算等相关操作,可以先利用消息队列异步分发事件信息。
三、Redis实现库存扣减
1、为什么库存扣减不放到数据库中
额外费用,库存数保存在Redis中,库存数的最新值保存在数据库中。因此,数据库更新后,需要与Redis同步。该过程增加了额外的操作逻辑和成本。
订单超过实际库存,出现超卖。由于数据库处理速度缓慢,库存余额无法及时更新,这将导致大量库存检查请求读取旧库存值并下订单,订单量将大于实际库存,导致超卖,不符合业务层面的要求。
因此,我们需要直接在Redis中进行库存扣减。具体操作是,一旦库存检查完成,此时库存过剩,我们将立即扣除Redis中的库存。此外,为了避免请求查询旧库存值,库存检查和库存扣除这两个操作需要确保原子性。

2、基于Redis分布式锁的扣减库存
使用分布式锁来支持秒杀场景的具体方法是,要求客户端首先向Redis申请分布式锁,只有请求了锁的客户端才能执行库存检查和库存扣除。此时,大多数秒杀请求将被拦截,因为它们无法获取锁。同时,切片集群中的不同实例可以分别用于存储分布式锁和商品库存信息。使用此保存方法后,秒杀请求会首先访问保存分布式锁的实例。

3、基于lua脚本(原子性)的扣减库存
在秒杀场景中,库存检查和库存扣减这两个操作应该一起执行,直接的方法是使用Redis原子操作,原子操作可以是Redis本身或Lua脚本提供的原子命令。因为库存检查和库存扣除是两个操作,不能用一个命令完成,所以我们需要使用Lua脚本以原子方式执行这两个操作。
获取商品库存信息;
将总库存转换为数值;
将已被秒杀的库存转换为数值;
if (如果当前请求的库存量加上已被秒杀的库存量仍然小于总库存量) {更新已秒杀的库存量;
}local skuInfoCount = redis.call('skuId',……); // 获取商品库存信息
local stockCount = tonember(skuInfoCount[1]); // 库存总数
local orderCount = tonember(skuInfoCount[2]); // 已被秒杀的库存
if orderCount+当前线程请求的商品数量 < stockCount then redis.call( , k); //
end return 0;
总结
本文首先对秒杀系统进行整体分析,通过分析得出前端预处理、Redis全链路支持的秒杀系统整体的设计,最后给出Redis实现库存扣减,为什么不放到数据库中,以及使用Redis分布式锁、lua脚本的两种实现。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
