【开发系列】秒杀系统的设计

简介: 【开发系列】秒杀系统的设计
1、整体的秒杀设计
2、定时上架商品和预库存
3、秒杀商品展示
4、用户下单
   4.1 每场每个商品用户只能下一单的处理
   4.2 商品预库存
   4.3 用户异步下单
5、订单支付

原创 龙虾编程

现在许多商家了吸引顾客都会使用低价的秒杀商品来做活动,下图展示了京东的秒杀活动页面:

秒杀活动在开始的时候,用户根据自己的需要下单自己喜欢的商品,此时服务器瞬间会打入大量的流量进来,如何设计一套可以扛住高并发的秒杀系统来支撑秒杀活动?下面我们具体的做秒杀系统的设计。

1、整体的秒杀设计

秒杀系统中我们使用了LVS和Nginx来扛住第一波流量,并且在Nginx做一波限流控制;然后Nginx将请求转发到网关上,由网关将请求分发到处理服务器上(秒杀服务),接下来由处理服务器做相关的操作。下单中使用的是异步下单加WebSocket推送下单成功的消息到客户端上,使用Redis缓存来缓存商品信息、预库存信息和用户下单成功之后的订单信息。

2、定时上架商品和预库存

在秒杀活动中为了提高秒杀系统的性能,将秒杀商品、商品的库存信息提前添加到Redis中。

在秒杀活动的当天凌晨,将秒杀商品信息和库存都放到Redis中缓存起来,由于每场秒杀活动有不同的商品,所以针对不同的场次将商品信息使用Hash数据结构缓存起来。

3、秒杀商品展示

秒杀活动开始的时候,用户访问商品的页的时候,直接从redis中将缓存的商品信息给用户,这样就不用走数据库查询,提高了系统的吞吐量。

4、用户下单

4.1 每场每个商品用户只能下一单的处理

用户下单的时候,首先的要去判断一下用户本场是否已经下过单(限定每场活动的每个商品用户只能买一件,防止某个用户同时多个请求来到秒杀系统,为此在Redis中增加一个Set数据结构来记录用户本场针对某个商品已经下过单。如果Set中存在了本场次当前商品已经下过单就不可以让用户继续下单,反之可以下单。

但是高并发下此方式不能完全避免用户多次下单的问题,如下:

在t1时刻,两个线程同时请求用户的下单,此时发现没有当前的用户没有下单,放行两个线程到库存检查这一步,此时如果库存足够会让线程下单,那么就造成了同一个用户针对这个商品就多次下单了。解决方案就是在数据库中增加一个唯一键来兜底。唯一键可以使用时间+商品的id+场次来定义,如果数据插入失败就需要回补库存到Redis中。

4.2 商品预库存

商品的预库存主要作用是阻挡大部分的无效请求,因为秒杀商品往往数量比实际用户的请求数量小很多(如秒杀商品100个,用户在某个时间段中来了500个请求,此时真正要处理的请求其实就是100个,其余的400个请求多是多余的请求,因为库存不足无法下单),使用预库存可以让无效请求直接返回而不需要到订单服务中的处理。

如果存在用户下单后没有付款或者同一个用户多个请求的情况下,会出现预库存被占用导致想要购买的用户无法下单,此时需要回补预库存。回补库存我们直接采用将数据库的剩余库存数量直接放入到预库存队列中。

高并发这种方案可能会出现预库存数量比实际真实的剩余库存要多的情况,如下:

A线程和B线程回补库存的时候,此时发现真实库存是100个,B线程CPU的时间片恰好用完了,A线程首先执行回补100个库存到Redis,然后C下单成功后扣减了1个预库存,随后B线程获得了时间片,然后将100库存又回补到Redis中,此时真实的库存其实是99个,但是B线程回补多1个预库存;针对这种情况需要数据库层做兜底来保证不会超卖(创建订单的时候兜底处理)。

4.3 用户异步下单

如果用户在本场本商品没有下单,并且预库存扣减成功(实质是利用Redis的自减操作,如果自减后的结果大于0就库存是足够的)那么允许用户下单,此时我们利用MQ来异步下单。

MQ会发送两个消息,一个是实时的下单消息,一个是延迟的检查规定时间用户是否支付的消息(如果超时未支付就取消本单,并且回补预库存);MQ消息发送成功之后通知客户已经在下单队列中等待处理。

订单服务开始消费消息队列中的消息,首先会创建订单基本的信息、下单的商品信息等,创建成功之后订单信息会保存到数据库中并且数据还会同步一份到Redis中用于用户查询订单的信息。最后通过WebSocket技术将用户下单的成功的消息推送给客户端,方便用户支付。

给用户创建订单的时候底层需要使用乐观锁机制,先去扣减秒杀商品的库存(如update item set stock = stock - 1 where id = #{itemId} and stock > 0),如果扣减影响行数大于0,那么就代表扣减库存成功,可以让用户下单,这样可以保证商品不被超卖。

延迟消息(如延迟15分钟)过来之后,查询一下当前订单是否已经被支付,如果订单没有支付就将订单的状态修改成交易关闭。在修改订单的状态的中,极端情况下出现超时未支付的请求和用户支付请求同时来操作订单,如下:

此时如果不做预防措施,订单就会出现状态错乱的现象,为了解决这个问题,采用订单的状态机来处理。如下状态的转换:

超时未支付的请求和用户支付请求谁先操作谁为准(底层的Sql语句:update order set status = #{status} where order_id = #{orderId} and status = '待支付'),这样另一个线程的就操作失败,我们需要打印日志抛出异常提示。

5、订单支付

服务端创建订单成功之后,用户开始支付,支付走三方(如支付宝、微信)支付成功后需要及时修改订单的状态和同步Redis中订单的状态。

总结:

(1)秒杀系统设计中采用LVS+Nginx方式来提高系统的并发能力

(2)采用将商品信息、商品库存缓存Redis的方式来提高系统的响应和拦截无效的请求

(3)通过异步下单(MQ)的方式来给流量消峰处理,维持系统的稳定

(4)采用WebSocket的方式将下单成功的消息推送给客户端

(5)超卖问题采用乐观锁的机制做兜底处理

(6)针对用户超时未支付或者多次下单同一个商品导致商品少卖的问题,采用真实库存回补的方式来处理预库存(Redis的中的库存)

相关文章
|
24天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2577 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
164 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1576 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
978 14
|
4天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
221 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
735 9