商城抢购秒杀服务器架构设计解析

2020-04-17 16:02:50 浏览数 (1)

RabbitMQ作为一款能实现高性能存储分发消息的分布式中间件,具有异步通信、服务解耦、接口限流、消息分发和业务延迟处理等功能,在实际生产环境中具有很广泛的应用,其特性可以概括为如图1所示。

图1 RabbitMQ的作用

正是由于RabbitMQ拥有如此多的特性,才使得其在实际应用系统中具有一席之地,本节主要介绍一下RabbitMQ的典型应用场景。

1.异步通信和服务解耦

以“用户注册”为实际场景,传统的企业级应用处理用户注册的流程,首先是用户在界面上输入用户名、邮箱或手机号等信息,确认无误后,单击“注册”按钮提交相关信息。

前端会将这个信息提交到后端相关接口进行处理,后端在接收到这些信息后,会先对这些信息进行最基本的校验,校验成功后会将信息写入数据库相关数据表中,而为了用户注册的安全性,后端会调用邮件服务器提供的接口发送一封邮件验证用户的合法性,或者调用短信服务的发送短信验证码接口给用户进行验证,最后才将响应信息返回给前端用户,并提示“注册成功”,整个流程如图2所示。

图2 传统的企业级应用系统用户注册流程

从图2的流程可以看出,用户从单击“注册”按钮,提交相关信息之后便需要经历“漫长”的等待时间,整体的等待时间约等于“写入数据库” “邮箱验证” “短信确认”的处理时间之和。在处理过程中如果发邮件和发短信业务逻辑出现异常,整个流程将会终止,很显然这种处理方式对于当前互联网用户来说几乎不能接受!

仔细分析用户注册的整个流程,不难发现其核心的业务逻辑在于“判断用户注册信息的合法性并将信息写入数据库”,而“发送邮件”和“短信验证”服务在某种程度上并不归属于“用户注册”的核心流程,因而可以将相应的服务从其中解耦出来,并采用消息中间件如RabbitMQ进行异步通信,如图3所示。

图3 引入RabbitMQ消息中间件后用户注册的流程

可以看到RabbitMQ的引入,将“一条线走到底”的业务服务模块进行了解耦,系统接口的整体响应时间也明显降低了许多,即实现了“低延迟”。从用户的角度上看,这将给用户带来很好的体验效果。

2.接口限流和消息分发

以“商城用户抢购商品”为例,商城为了吸引用户流量,会不定期地举办线上商城热门商品的抢购活动,当抢购活动开始之前,用户犹如“守株待兔”一般会盯在屏幕前等待活动的开始,当活动开始之时,由于商品数量有限,所有的用户几乎会在同一时刻单击“抢购”按钮开始进行商品的抢购,整体流程如图4所示。

图4 商城商品抢购活动传统的处理流程

毫无疑问,在抢购活动开始的那一刻,将会产生巨大的用户抢购流量,这些请求几乎在同一时间到达后端系统接口。而在正常的情况下,后端系统接口在接收到前端发送过来的请求时,会执行如下流程:

首先会校验用户和商品等信息的合法性,当校验通过之后,会判断当前商品的库存是否充足,如果充足,则代表当前用户将能成功抢购到商品,最后将用户抢购成功的相关数据记入数据库,并异步通知用户抢购成功,尽快进行付款等。

然而,通过仔细分析发现,后端系统接口在处理用户抢购的整体业务流程“太长”,而在这整块业务逻辑的处理过程中,存在着先取出库存再进行判断,最后再进行减1的更新操作,在高并发的情况下,这些业务操作会给系统带来诸多的问题。比如,商品超卖、数据不一致、用户等待时间长、系统接口挂掉等现象。因而这种单一的处理流程只适用于同一时刻前端请求量很少的情况,而对于类似商城抢购、商品秒杀等某一时刻产生高并发请求的情况则显得力不从心。

消息中间件RabbitMQ的引入可以大大地改善系统的整体业务流程和性能,如图5所示为引入RabbitMQ后系统的整体处理流程。

图5 商城商品抢购活动传统的处理流程

由图5可以看出,RabbitMQ的引入主要是从以下两个方面来优化系统的整体处理流程:

1)接口限流:当前端产生高并发请求时,并不会像“无头苍蝇”一样立即到达后端系统接口,而是像每天上班时的地铁限流一样,将这些请求按照先来后到的规则加入RabbitMQ的队列,即在某种程度上实现“接口限流”。

2)消息异步分发:当商品库存充足时,当前抢购的用户将可以抢到该商品,之后会异步地通过发送短信、发送邮件等方式通知用户抢购成功,并告知用户尽快付款,即在某种程度上实现了“消息异步分发”。

3)业务延迟处理

RabbitMQ除了可以实现消息实时异步分发之外,在某些业务场景下,还能实现消息的延时和延迟处理。下面以“春运12306抢票”为例进行说明。春运抢票相信读者都不陌生,当我们用12306抢票软件抢到火车票时,12306官方会提醒用户“请在30分钟内付款”。正常情况下用户会立即付款,然后输入相应的支付密码支付火车票的价格。扣款成功后,12306官方会发送邮件或者短信,通知用户抢票和付款成功。

然而,实际却存在着一些特殊情况,比如用户抢到火车票后,由于各种原因而迟迟没有付款,过了30分钟后仍然没有支付车票的价格,导致系统自动取消该笔订单。类似这种“需要延迟一定的时间后再进行处理”的业务在实际生产环境中并不少见,传统企业级应用对于这种业务的处理,是采用一个定时器定时去获取没有付款的订单,并判断用户的下单时间距离当前的时间是否已经超过30分钟,如果是,则表示用户在30分钟内仍然没有付款,系统将自动使该笔订单失效并回收该张车票,整个业务流程如图6所示。

图6 抢票成功后30分钟内未付款的传统处理流程

春运抢票完全可以看作是一个大数据量、高并发请求的场景,在某一时刻车票开抢之后,正常情况下将陆续会有用户抢到车票,但是距离车票付款成功是有一定的时间间隔的。

在这段时间内,如果定时器频繁地从数据库中获取“未付款”状态的订单,其数据量之大将难以想象,而且如果大批量的用户在30分钟内迟迟不付款,那从数据库中获取的数据量将一直在增长,当达到一定程度时,将给数据库服务器和应用服务器带来巨大的压力,更有甚者将直接压垮服务器,导致抢票等业务全线崩溃,带来的直接后果将不堪设想!

早期的很多抢票软件每当赶上春运高峰期时,经常会出现“网站崩溃”“单击购买车票后却一直没响应”等状况,某种程度上是因为在某一时刻产生的高并发,或者定时频繁拉取数据库得到的数据量过大等状况,导致内存、CPU、网络和数据库服务等负载过高所引起的。

而消息中间件RabbitMQ的引入,不管是从业务层面还是应用的性能层面,都大大得到了改善,如图7为引入RabbitMQ消息中间件后“抢票成功后30分钟内未付款的处理流程”的优化。

图7 抢票成功后30分钟内未付款的优化处理流程

从优化流程中可以看出,RabbitMQ的引入主要是替代了传统处理流程的“定时器处理逻辑”,取而代之的是采用RabbitMQ的延迟队列进行处理。延迟队列,顾名思义指的是可以延迟一定的时间再处理相应的业务逻辑。

RabbitMQ的这一特性在某些场景下确实能起到很好的作用,比如上面讲的“成功抢到票后30分钟内未付款的处理流程”就是比较典型的一种。除此之外,商城购物时“单击去付款而迟迟没有在规定的时间内支付”的流程的处理、点外卖时“下单成功后迟迟没有在规定的时间内付款”的流程的处理等都是实际生产环境中比较典型的场景。

除了上述所罗列的应用场景外,RabbitMQ在其他业务场景下也同样具有广泛的应用,在这里就不再一一列举了!

本文节选自机械工业出版社出版的《分布式中间件技术实战(Java版)》,经出版社授权发布。

0 人点赞