(2)RabbitMQ架构设计与应用场景

1.什么是消息中间件?

消息是指应用间传输的数据。消息体包括文本字符串、Json、内嵌对象等。
消息中间件是基于队列模型实现异步和同步传输数据的。
作用:解耦,冗余(存储)、扩展性、削峰、可恢复性、顺序保证、缓冲、异步通信。通俗点来说就是支持支撑高并发、异步解耦、流量削峰、降低耦合度。

2. AMQP是什么?

AMQP(Advanced Message Queuing Protocol,高级消息队列协议)是一个进程间传递异步消息的网络协议。
RabbitMQ是遵从AMQP协议的,而RabbitMQ的模型架构又和AMQP的模型架构是一样的。
AMQP实体模型如下:


工作原理如下:生产者(Publisher)将消息发送给交换器,交换器和队列绑定。当生产者发送消息时所携带的RoutingKey与绑定时的BindingKey相匹配时,消息即被存入相应的队列之中,消费者可以订阅相应的队列来获取消息。

3.RabbitMQ相关概念

RabbitMQ实体模型如下:


在了解完上图RabbitMQ模型后,现在让我们来看看RabbitMQ运转流程:
●生产者推送消息:
(1)生产者连接到RabbitMQ的Broker建立一个连接(Connection),开启一个信道(Channel)。
(2)生产者声明一个交换器,并设置相关属性,比如交换机类型、是否持久化等。
(3)生产者声明一个队列并设置相关属性,比如是否排他、是否持久化、是否自动删除等。
(4)生产者通过路由键将交换器和队列绑定起来。
(5)生产者发送消息至RabbitMQ的Broker,其中包含路由键、交换器等信息。
(6)相应的交换器根据接收到的路由键查找相匹配的队列。
(7)如果找到,则将从生产者发送过来的消息存入相应的队列中。
(8)如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者。
(9)关闭信道。
(10)关闭连接。
●消费者接收消息:
(1)消费者连接到RabbitMQ的Broker,建立一个连接(Connection),开启一个信道(Channel)。
(2)消费者向RabbitMQ的Broker请求消费相应队列中的消息,可能会设置相应的回调函数,以及做些准备工作(推拉模式)。
(3)等待RabbitMQ的Broker回应并投递相应队列中的消息,消费者接收消息。
(4)消费者确认(ack)接收到的消息。
(5) RabbitMQ从队列中删除相应己经被确认的消息。
(6)关闭信道。
(7)关闭连接。
注:上述有两个概念可以了解下,分别是信道(Channel)连接(Connection),我们知道无论是生产者还是消费者,都需要和RabbitMQ的Broker建立连接,这个连接就是一条TCP连接,也就是Connection的TCP连接建立起来,客户端紧接着可以创建一个AMQP信道(Channel),每个信道都会被指派一个唯一的ID。Channel是建立在Connection之上的虚拟连接,RabbitMQ处理的每条AMQP指令都是通过信道完成的。如图所示:

*这里大伙可能会有一个疑问,为什么Connection能完成Channel连接工作,还要引入Channel呢?
试想这样一个场景,一个应用程序中有很多个线程需要从RabbitMQ中消费消息或者生产消息,那么必然需要建立很多个Connection,也就是许多个TCP连接。然而对于操作系统而言,建立和销毁TCP连接是非常昂贵的开销,如果遇到使用高峰,性能瓶颈也随之显现。RabbitMQ采用类似NIO1(Non-blocking 1/0)的做法,选择TCP连接复用,不仅可以减少性能开销,同时也便于管理。
*NIO1,也称非阻塞(I/O),包含三大核心部分Channel(信道)、Buffer(缓冲区)和Selector(选择器)。NIO基于channel和Buffer进行操作,总是从信道读取数据到缓冲区中,或者从缓冲区写入到信道中。Selector用于监听多个信道的事件(比如连接打开,数据到达等)。因此,单线程可以监听多个数据的信道。NIO1中有个很有名的Reactor模式,有兴趣小伙伴可以去阅读下,这里就不详解了。
*每个线程分别把持一个信道,所以信道复用了Connection TCP连接。同时RabbitMQ可以确保每个线程的私密性,就像拥有独立的连接一样。当每个信道的流量不是很大时,复用单一的Connection可以在产生性能瓶颈的情况下有效地节TCP连接资源。但是当信道本身的流量很大时,这时候多个信道复用一个Connection就会产生性能瓶颈,进而使整体的流量被限制了。此时就需要开辟多Connection,将这些信道均摊到这些Connection中,至于这些相关的调优策略需要根据业务自身的实际情况进行调节。
*下面让我们来了解下实体中每个角色模型:
●Producer(生产者):投递消息到服务端的一方。投递消息分为两部分:消息体(payload)和标签(label)。
◎消息体:一般是带有业务逻辑结构的数据,例如一个json数据。
◎标签:消息的标签是用来表述这条消息,例如一个交换器名称跟路由键。
●Broker(代理):MQ服务节点。也可以看作一个实例,或者一台RabbitMQ服务器。
●Exchange(交换器):生产者将消息投递到队列中,实际是将消息投递到交换器,由其路由到一个或者多个队列当中。如果路由不到,会返回给生产者或者丢弃。交换器包含路由键(RoutingKey)绑定键(BindingKey),还有四种类型,后面会重点介绍。
◎路由键:生产者投递消息给交换器时会指定一个路由键,用作路由规则来决定消息的流向。
◎绑定键:交换器跟队列是通过一个绑定键关联的,这样Rabbitmq才能正确把消息投递到相关队列去。如图所示:

从上图可知道,交换器相当于投递包裹的邮箱,路由键当于填写在包裹上的地址,绑定键当于包裹目的地,当填写在包裹上地址和实际想要投递的地相匹配时,那么这个包裹才会被正确投递到目的地,最后这个目的地的“收件人”(队列)才可以保留这个包裹。如果填写的地址有错,邮递员不能正确投递到目的地,那么包裹可能会回退给“寄件人”(生产者),或者可能会被丢弃。其实在某些情形下路由键和绑定键可以看作同一个东西。
●Queue(队列):用于存储消息。遵循先进先出,后进后出原则。多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊(Round-Robin),即轮询给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

4.为什么要用到MQ?

4.1传统Http请求缺点


传统Http请求是基于请求与响应的模型下进行的,在高并发的情况下,客户端会发送大量的请求达到服务器端,这样有可能会导致我们服务器端要处理大量堆积请求,增加服务器压力。
像Window IIS服务器(IIS线程池)处理每个请求都有自己独立的线程,如果超过最大线程数,IIS的w3wp进程不会再将http.sys的队列中的请求去线程池中调用线程处理,如果请求堆积过多的情况下,有可能会导致服务器崩溃。所以一般都会在nginx入口实现限流。
http请求处理比较耗时的业务逻辑情况下,容易造成客户端(Client)一直等待,阻塞等待过程中会导致客户端超时发生重试策略,有可能会引发幂等性问题。
总结:综合以上Http请求缺点,如果接口是为Http协议的情况下,最好不要处理比较耗时的业务逻辑,耗时的业务逻辑应该单独交给多线程或者是mq去处理。

4.2MQ应用场景

结合上述总结可以知道,在处理Http请求比较耗时业务时,可以交给多线程或者是mq去处理,下面我们结合常见用户注册应用场景来解释这两者区别:

如上图所示,客户端发起一个注册用户请求,处理业务逻辑如下:
(1)InsertUser(插入用户信息),需要1秒处理时间。
(2)SendEmail(发送邮件),需要2秒处理时间。
(3)SendCoupons(发送优惠卷),需要3秒处理时间。
按照上述串行处理流程,该功能处理时间总共为6秒,这意味着用户需要等待6秒,这种用户体验是非常差的。下面再来看看多线程跟MQ如何处理这些业务逻辑。
●多线程处理

如上图所示,客户端发起一个注册用户请求到服务端后,插入用户信息同时开启一个线程处理发送邮件和优惠卷,当插入用户信息成功后立即响应状态给客户端,所以整个过程只花费1秒处理时间。
◎优点:适合小型项目,实现异步处理。
◎缺点:消耗服务器CPU资源,没有解耦。
●MQ处理

如上图所示,客户端发起一个注册用户请求到服务端后,插入用户信息同时往MQ投递一个消息处理发送邮件和优惠卷,当插入用户信息成功后立即响应给客户端,所以整个过程只花费1秒处理时间。
◎优点:适合中大型项目,实现异步处理,流量削峰、降低耦合度。
◎缺点:增加系统复杂度。

5.主流MQ区别对比

特性

ActiveMQ

RabbitMQ

RocketMQ

Kafka

开发语言

java

erlang

java

scala

单机吞吐量

万级

万级

10万级

10万级

时效性

ms级

us级

ms级

ms级以内

可用性

高(主从架构)

高(主从架构)

非常高(分布式架构)

非常高(分布式架构)

功能特性

成熟的产品,在很多公司得到应用有较多的文档各种协议支持较好。

基于erlang开发,所以并发能力很强,性能极其好,延时很低管理界面较丰富。

MQ功能比较完备,扩展性佳。

只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。


参考文献:
RabbitMQ实战指南

posted on 2022-01-24 11:53  暗断肠  阅读(647)  评论(0编辑  收藏  举报

导航