首页 > 编程知识 正文

redis大并发防超卖,redis如何防止商品超卖问题

时间:2023-05-05 20:53:14 阅读:113140 作者:207

在商品和订单服务之间使用MQ

商品、服务的库存发生变化时,通过MQ通知订单、服务的库存发生了变化。

原始同步过程

查询商品信息(调用商品、服务) ) ) )。

计算总额(生成订单详细信息) ) ) ) ) ) ) ) ) ) )。

商品、服务扣除库存(调用商品、服务) ) )。

签入订单(生成订单)

//原始MySQL同步过程

//判断这张代金券是否进入抢购

seckillvouchersseckillvouchers=seckillvouchersmapper.select voucher (voucher id );

assert util.is true (seckillvouchers==null,'这张代金券没有进行抢购活动');

//判断是否有效

assert util.is true (seckillvouchers.get is valid )==0,“此活动已终止”);

//插入数据库

seckillvouchersmapper.save (seckillvouchers;

生成订单时直接提取库存。 这是最原始的去库存方案,比较简单,但有问题

许多订单可能没有支付,扣除产品库存。 因此,需要后台脚本来释放暂时未支付的订单的库存,取消订单并立即扣除库存,从而出现差距

步骤1、3商品服务、操作商品服务的数据库、步骤2、4的订单服务、操作订单服务的数据库。

避免访问不同服务的数据库,原则上同一服务只能操作自己服务的数据库。

MQ异步化

首先,我们只考虑使步骤4异步。

分析

2、4都是操作数据库,在步骤4中不再等待,并且在1、2、3成功后立即反馈给用户。

接着通过消息通知服务发出异步订单,且如果在步骤4中异步订单失败,则当尝试重试操作并重新生成订单时,MQ中的消息也可以追溯。

订单创建后,它将排队,服务将事件Order Created发布到消息队列。

也就是说,订单服务向外部发送信息。 我制作了订单,并从MQ转发到了订阅该消息的服务

商品、服务收到订单制作消息后执行去库存操作时。 请注意,在这里,由于一些不可抗力,库存的提取可能会失败。 无论成功与否,商品、服务都会向MQQ发送扣掉库存的消息。 信息的内容是库存扣款的结果。

订单服务订阅库存扣除的结果,并在收到此消息后:

如果成功提取库存,将订单状态更改为“已确认”,订单将成功

库存提取失败的情况下,如果将订单的状态变更为已取消,订单就会失败

要实现上述模型的要求,需要可靠的消息传递。 来自服务的消息一定会被MQ接收到。

用户体验变化、前端和队列中等接口。

所有商品/订单服务都将异步化,适合秒杀类场景,但流量较少时不太适合。

异步设计

库存保存在Redis中

接到要求后,Redis判断库存是否充足,扣除Redis的库存

订单服务创建订单并将其写入数据库,然后发送消息

订单支付成功后,将有出库流程。 既然有这个过程,出库就有可能失败。

有两个库存:

缓存就绪层

数据库mysql层

如果客户支持添加五个库存,则在缓存redis和数据库mysql层次结构中都将添加五个库存,并且必须使用分布式事务的最终一致性来满足是添加了所有库存还是完全不添加库存。

订单生成时,必须扣除库存。 如果先扣除redis库存,扣除成功,则生成订单并支付。 此过程不要扣除mysql库存。

redis库存耗尽后,该产品将无法订购,订单失败,屏蔽了外部的东西。

在步骤2中成功扣除了redis的库存后,生成订单,进行支付,支付成功,然后返回我的订单中心,您会发现有发放流程。

签出MQ异步解耦的任务队列,减去mysql库存。

如果成功提取mysql库存,则成功签出,整个采购订单流程完成,处于发运状态

mysql库存提取失败时,退房失败,进行一系列操作

订单状况更改为取消

返还redis的库存

退款

redis库存和mysql库存

支付前是代扣,是扣除redis库存,是锁定库存的过程

付款后真正扣款,扣款mysql库存,保证库存最终匹配

但是,在极端的情况下存在数据的不一致

只要redis库存=mysql库存就没问题

如果redis有mysql库存,就没有超卖问题,但实际上有库存,但可能没有销售

如果redis有mysql的库存,就会超卖。 超卖的订单在出库中失败

这样总体上不会发生问题。 mysql数据库层确保库存最终不成问题。

问题

数据库库存和redis库存不匹配。 怎么检测?

如果检测到不匹配,如何同步

想不出好主意

暴力的方法是寻找像凌一样的低峰期

晨1点,周期性强行覆盖。 但是极端情况下还是会存在同步后不准确,譬如在同步的过程中,刚好有一个订单在支付,这个订单支付成功后,出库的过程中,扣除了mysql的库存,但是没有扣除redis的库存

这个就是数据库同步缓存的更新机制方面的问题

属于一致性的逻辑设计的问题

缓存数 = 数据库库存数 - 待扣数

当然这里面也还有其它的方案,以及考虑到一致性的要求高低,可以使用简单或复杂的方案

就看系统复杂度了,越是大系统就要拆得越细

比如待扣数又可以放到一个队列里面,或者缓存里面,同时有计数,直接读计数就行

比如放到mongo,已支付待出库的数量,一般也不会很大,count一下,也不会损失多少

所以一般系统都不能完全保障数据链不出错,但一定要有补偿,就是出错了可以纠错

要保障不出错的代价显然太大

同步是有一套刷新机制,可以定时,也可以通过MQ,或者监控不一至同步等等。。。

也叫做保障缓存数据的新鲜度

一般不会太长时间,半小时,几分钟都有可能,不同场景需求不一样

12306

买火车票的12306,晚上的时间都不能买票,这个时间估计是在同步库存,将数据库库存同步到redis库存中, 但是买火车票之类,在订单生成前,必须扣除实际库存,也就是要扣除mysql的库存,

因为买火车票和购物不一样,购物可以付款后出库,但是买票这种,支付前就必须出库,因此,要将出库过程提前, 只有出库成功,才能生成订单,同样要引入redis库存

先扣缓存中的库存,扣除成功后,然后才可以去扣mysql中的库存。

如果扣除缓存中的库存失败,就会挡在外面,返回库存不足,这些请求不会穿刺到mysql中,挡住了大多数的请求压力。

redis库存会和mysql库存不一致,极端情况下是肯定有的,需要进行库存同步

当缓存库存比数据库库存多,那么就会出现,查询有票,但是就无法下单,下单的时候就说库存不足,这个情况下,就会造成数据库压力过大,不过12306应该有其他手段来规避这个问题,不过,我确实遇到过,查询的时候有票,但是无法下单的情况。

当缓存库存比数据库缓存少,那么不会出问题,只会出现有票,但是没有出售的情况,等完成库存同步一下, 明天又准确了。

到此这篇关于Redis解决库存超卖问题实例讲解的文章就介绍到这了,更多相关Redis解决库存超卖问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。