不是我吹,RabbitMQ 是真牛逼!
Java技术栈
www.javastack.cn
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版)》,经出版社授权发布。需要进一步学习相关内容的读者,可以点击购买下面这本书阅读。
国内图书市场上关于Java中间件的图书不少,但是真正从初学者的角度,基于实际项目,通过各种典型业务模块和案例来指导读者提高开发水平的图书却很少。
《分布式中间件技术实战(Java版)》便是以实战为主,配合必要的理论知识,介绍了几款比较流行的分布式中间件,包括其理论层面的知识要点及在实际业务场景中的实战过程,让读者几乎可以从零开始一步一个脚印地学习Java企业级应用开发的各种常用中间件,从而提高实际开发水平和项目实战能力。
如何免费获得该书呢?
请在下面留言区留言你关于“消息中间件”方面的见解或经验分享,截止03/23 20:00点留言点赞排名前10名我每人送一本感谢粉丝的持续支持。
注意,不符合要求的留言不会放出,为了公平起见,禁止恶意刷赞,后台已设置监控,刷赞的、不是真实点赞的一律无效。
如果没有中奖,喜欢本书的粉丝也可以在京东小程序直接购买。
栈长已入手,周末好好看下。