本文是“Java秒杀系统实战系列文章”的第十七篇,我们将继续秒杀系统的优化之路。在本文中我们将基于RabbitMQ异步通信、FIFO(先进先出)、接口限流的特性,在执行秒杀核心的处理逻辑之前架上一层“限流”的处理逻辑,从而让瞬时产生的,犹如波涛汹涌、潮水般的请求流量变得井井有条、有序性地到达后端的秒杀接口!
在前面的篇章中,我们主要是从秒杀的核心处理逻辑着手进行优化,先后从数据库级别Sql的优化、分布式锁的引入、分布式唯一ID算法的引入以及业务服务模块的异步通信、服务解耦等方式对秒杀核心业务逻辑的处理进行了大幅度的调整、优化,本文Debug将介绍一种独立于“秒杀核心业务逻辑”的方式对秒杀系统进行优化。
首先,我们先来回顾一下秒杀系统整体的秒杀业务逻辑的处理:
![c18cefd5571aba9194b23a104fdf54be.png](https://i-blog.csdnimg.cn/blog_migrate/182ced16b221ffd2f2960180b331e562.jpeg)
当前端高并发产生多线程请求时,正常情况下,前端会在瞬时产生犹如波涛汹涌、潮水般的请求流量到达后端的秒杀接口,此时如果我们的代码处理逻辑并不那么迅速,那么很有可能将应对不了这股蜂拥而至的高并发流量,最终可能出现各种各样乱七八糟的问题,前面所讲的“库存超卖”、“重复秒杀”便是一种体现。
而且,在某种程度上,这些请求流量对于我们来讲有两点我们需要去注意的:
(1)这些请求流量是透明的,我们后端接口压根不知道、也不需要知道请求对应的用户是哪位;
(2)这些请求最终并非全部都是有效的,即如果待秒杀的商品数量为N,而请求的流量远远大于N,则很明显,在秒杀开始后将有很大一部分的请求流量对于我们后端接口而言是木有多大用处的,因为秒杀进行到一定时间时,N很有可能已经等于0了。
基于这两点设想,我们希望对这些请求流量进行“规范化”,当前端高并发产生多线程请求流量时,我们希望将这些请求压入“队列”,使得这些请求可以“乖乖的”等待被处理,即变得井井有条、有序性地到达后端的秒杀接口,而不是像无头苍蝇般、一窝蜂的插队处理!
众所周知,RabbitMQ是一款MQ中间件,MQ正是MessageQueue,即消息队列的简称,而我们都知道队列的特点是先进先出,即FIFO;它可以实现先进入队列的消息先被消费处理、后进入队列的消息后被消费处理,因此,RabbitMQ的这一特性将可以助我们实现“接口限流”的作用,其最终的效果如下图所示:
![b16116ef21e0fb8d4dec626a00d5dc40.png](https://i-blog.csdnimg.cn/blog_migrate/323b301c7a23f8f41c0ec202009433db.jpeg)
下面我们就进入代码实战环节:
(1)首先,我们需要在RabbitmqConfig配置类中创建限流用的队列、交换机和路由消息模型,其代码如下所示:
//TODO:RabbitMQ限流专用@Beanpublic Queue executeLimitQueue(){ Map argsMap=Maps.newHashMap(); //限制channel中队列同一时刻通过的消息数量 argsMap.put("x-max-length