怎么设计一个优惠系统

怎么设计一个优惠系统

参与的项目有过类似的系统,但当时不是本人负责设计,故可能有些细节问题,勿怪。

大致的流程图:

在这里插入图片描述

只是大致的流程图,细节需完善,比如最终支付完成后,肯定需要落地MySQL保存该支付信息的,还有下单操作是多线程操作,而不是图中的单机操作,一些线程安全问题需要考虑。

大概面临的问题:

1.改系统设计之初就需面临高并发处理,怎么实现多线程下单?

以目前主流框架SpringBoot为例:
Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor。在使用线程池的大多数情况下都是异步非阻塞的。然后配置注解@EnableAsync可以开启异步任务。然后在实际执行的方法上配置注解@Async上声明是异步任务。
总结:创建一个线程池类实现 AsyncConfigurer接口,重写 getAsyncExecutor()方法,该方法定义线程池属性。最后在需要执行多线程的方法上加上@Async注解(别开口就是 new Thread(),被鄙视别怪没提醒

2.用户排队实现(为什么排队,因为先到先得)

可以封装一个排队的实体类,封装用户信息,要下单的商品信息,该订单的状态信息,时间信息等。
Redis的List数据结构是有序列表结构,可以以此实现一个队列。然后将封装的排队实体类信息存进去(记得左存右取,右存左取)

3.防止恶意抢购(即一个用户买多次)

当用户的订单进入Redis进行排队时,可以设置一个自增的int值,一旦抢单成功则该值进行自增。然后在防重复校验的过程中对该值进行判断,是否大于原值,大於则是重复排队,提示没资格购买,否则则提示已经在排队。

4.高并发下处理超卖问题

高并发环境下,容易出现多个用户抢一个订单且都下单成功的情况。
可以给参与活动的商品创建一个该商品的个数队列,如参与活动的某泡面有1000盒,某牛奶2000盒等。然后可以考虑给该泡面创建一个长度为1000的队列,牛奶类似。
多线程下单时,先从该商品的个数队列获取数据,取到数据则说明库存有余,反子则说明该商品已售罄。
在使用Redis操作时,在内存中修改数据,然后存入Redis。在高并发的情况下,容易造成多个不同的操作同时修改一个数据的情况。可以引入一个自增的int值,操作时先进行与原值判断,是否已经被修改过,若已经被修改则再次修改则抛异常。

5.订单超时问题

超时的订单需要进行数量回滚操作。可以采用MQ的延时消息实现,当该用户下单成功,即订单创建成功的时间点,同时发送一个延时消息进入MQ,大概原理即是,以延时30分钟为例,12:00成功创建一个订单,12:30的时候消费系统(mq的消息消费者)会受到该消息,同时它会去查询该订单的支付状态,如果支付成功,会在MySQL中生成一个订单,如果MySQL中没有支付,则Redis中还有该订单信息的存在,需要删除该订单信息以及用户排队信息,并恢复库存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章