持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
1.MQ消息队列的核心概念
1.1.什么是MQ消息队列
MQ的全称是Message Queue(消息队列),是在消息的传输过程中保存消息的容器,用于分布式系统之间进行通信,通信双方将请求写入到MQ消息队列中,被调用者从MQ中读取请求数据。
在传统情况下,系统之间的调用都是通过接口进行远程调用的,如下图所示,A系统通过远程接口调用B系统,两个系统之间会存在耦合性,当B系统出现异常时,A系统的业务逻辑将会失败,并且在高并发时,系统之间的频繁调用,对整体架构性能是有所影响的。
当程序架构中引入了MQ消息队列中间件之后,请求发送的一方(A系统)称之为生产者,将通信请求通过发布的方式写入到MQ消息队列中,被请求的接收方(B系统)称之为消费者,从MQ消息队列中通过订阅的方式拿到A系统发过来的通信请求,最终完成系统调用。
MQ消息队列的性能极高,高并发的情况下,请求写入MQ消息队列中,可以有效减轻被调用者的压力,从一定程度上实现了应用程序的解耦,A系统将请求写入MQ之后,业务逻辑就算完成了,等待B系统从MQ中获取信息完成整体系统的流程。
即使B系统挂掉了,也不会影响A系统的流程,B系统恢复后从MQ中依然可以读取到消息数据。
1.2.MQ消息队列的优势
MQ的优势在于:
- 应用解耦:提高系统容错性和可维护性。
- 异步处理:提高用户体验和系统吞吐量。
- 削峰填谷:提高系统稳定性。
1)应用解耦
引入MQ之前
以电商平台为例,在传统的模式中,用户下单后,订单系统会调用库存系统、物流系统、支付系统,流程走完后用户才算下单完成,如果此时库存系统异常,订单系统与库存系统存在耦合性,业务逻辑调不通就会返回异常,从而导致用户下单失败。
并且在生产中,如果有新需求需要调用其他系统时,还需要经常性的修改订单系统的程序代码,添加新系统的调用,当不需要调用这个系统时也需要修改订单系统的程序代码,非常麻烦。
引入MQ之后
当架构中引入了MQ消息队列,可以有效的解决系统之间的耦合,从一定程度上实现应用解耦。
如下图所示,用户下单后,订单系统会将消息数据写入到MQ消息队列中,写入完成后就会返回给用户提示下单完成,库存系统、物流系统、支付系统再去MQ消息队列中消费订单系统发过来的消息数据,进行对应的业务逻辑,即使库存系统挂了,也不会影响用户的下单,并且在短时间内会迅速恢复,再从MQ中消费数据完成业务逻辑。
2)异步处理
引入MQ之前
在传统架构中,用户点击下单按钮,首先会将数据写入到数据库,大约花费20毫秒,然后去调用库存系统、物流系统、支付系统,使用同步的方式,调用完一个系统再调用一个系统,各花费300毫秒,最后返回给用户下单完成,总共耗时920毫秒,这种速度对于互联网项目而言属于比较慢的情况了,响应时间长就意味着负载高。
引入MQ之后
当引入MQ消息队列之后,用户的提交完订单后,将数据写入数据库花费20毫秒的时间,然后订单系统执行业务逻辑,不会直接调用其他系统,而是将调用的消息数据写入到MQ消息队列中,花费5毫秒时间,写入MQ之后,就会返回给用户已经下单完成了,此时其他系统再从MQ消息队列中消费订单系统的消息数据,完成整个业务流程。
3)削峰填谷
削峰填谷指的是流量高峰期,引入MQ的变化趋势,大流量由MQ接收,相当于高峰被削了一半,流量全部导到MQ就相当于填谷,最后由应用程序从MQ中消费数据。
如果流量高并发的时候,架构中没有MQ消息队列,那么用户的所有流量请求都会直接发生到应用程序,应用程序的并发量可能达不到用户的请求量,就会导致程序崩溃。
当架构中引入了MQ消息队列,那么用户的大量请求会被MQ接收,然后由应用程序通过规则从MQ中消费请求,在减轻应用程序压力的同时提高了网站的稳定性。
1.3.MQ消息队列的劣势
MQ消息队列的功能很强单,但是也存在一定的劣势。
- 系统可用性降低
- 系统引入外部中间件越多,系统的稳定性也会降低,如果MQ宕机,就会对整个业务平台造成影响。
- 系统复杂度提高
- MQ的加入大大增大了系统的复杂度,之前是远程直接调用,现在需要通过MQ进行异步调用,还需要避免消息不会被重复消费、消息传递的顺序性、消息丢失情况。
- 消息一致性问题
- 使用MQ还会出现消息不一致的问题,例如A系统通过MQ给B、C、D系统发送消息数据,B、C系统处理成功,D系统处理失败等等。
1.4.什么场景下使用MQ消息队列
在生产环境中,什么场景下需要使用MQ消息队列,什么情况下需要直接远程调用?
适合直接远程调用的场景:
1、生产者需要消费者获取反馈信息,例如A系统调用B系统,需要B系统返回一个参数,B系统带着这个参数去请求C系统,此时就无法通过MQ传递消息了,只能通过远程调用。
2、不允许各系统间的数据不一致。
适合使用MQ的场景:
1、生产者不需要从消费者出获取反馈。
2、允许短暂的不一致性,消费者从MQ中读取消息需要一定的时间处理。
3、明确要求实现应用解耦、提速、削峰的需求。
1.4.常见的MQ消息队列产品
2.RabbitMQ消息队列概述
2.1.AMQP协议概念
消息队列使用的协议AMQP,即Advanced Message Queuing Protocol(高级消息队列协议),AMQP协议是一种网络协议,应用成协议的一种,面向消息中间件设计的协议标准,基于此协议的客户端与中间件可以相互传递消息数据,不受客户端/中间件产品不同的限制,是一种通用的协议标准。
AMQP协议如下图所示:Publisher是生产者,Exchange是传输数据的交换机,Queue是存放消息数据的容器,Consumer是消费者。
传输一条消息数据的流程:首先由Publisher(生产者)通过publish方式将消息传输到中间件的Exchange(交换组件),Exchange通过路由的方式将消息数据存储在Queue队列中,最后由Consumer(消费者)通过Consumers方式从Queue队列中消费数据。
2.2.RabbitMQ架构原理
RabbitMQ通过Erlang语言开发,性能强。
RabbitMQ架构与工作原理:
RabbitMQ架构与AMQP架构类似,Producer(生产者)、Consumer(消费者)都与Broker(RabbitMQ消息中间件)建立TCP连接,频繁建立TCP连接对资源消耗有所影响,RabbitMQ在客户端连接方面提供了channel(管道)方式与服务端建立连接,在RabbitMQ的Broker中会有多个VirtualHost(虚拟主机),多个VirtualHost之间相互隔离,在每隔VirtualHost中包含了多个Exchange和Queue,每个Exchange通过Binding与Qqueue进行绑定。
生产者通过channel与RabbitMQ建立连接,将消息数据通过Exchange路由到Queue队列中,消费者通过Channel与RabbitMQ建立连接,从Queue中读取消息数据。
RabbitMQ各组件介绍:
- Broker
- 接收和分发消息的应用,RabbitMQ叫做Message Broker。
- Virtual Host
- 出于多租户和安全因素设计,把AMQP的基本组件划分到一个虚拟的分组中,类似于命名空间的概念,多个VirtualHost之间存在网络隔离。
- Connection
- 发布者和消费者与MQ之间建立TCP连接。
- Channel
- 如果每一次访问RabbitMQ都需要建立一个连接,在消息量大的时候TCP连接消耗资源太大,效率也低,Channel是在Connection内部建立的逻辑连接,如应用程序支持多线程,通常每个线程都会创建单独的Channel进行通信。
- Exchange
- 消息数据到达MQ的第一站,根据路由分发规则,匹配对应的Queue,将消息存储在Queue队列中。
- 常用的类型有direct、topic
- Queue
- 消息最终被存储在Queue队列中,等待消费者读取
- Binding
- Exchange和Queue之间的绑定
RabbitMQ的工作模式包含简单模式、work queues、发布订阅模式、路由模式、Topics主题模式等等。
JAVA程序连接RabbitMQ需要通过JMS接口,JMS是JavaEE规范的一种,类似于JDBC接口,RabbitMQ官方没有提供JMS接口,但是开源社区有RabbitMQ的JMS实现包。
2.3.RabbitMQ与Erlang版本对照表
| RabbitMQ version | Minimum required Erlang/OTP | Maximum supported Erlang/OTP |
|---|---|---|
| 3.8.16 | 23.2 | 24.x |
| 3.8.15、3.8.14、3.8.13、3.8.12、3.8.11、3.8.10、3.8.9 | 22.3 | 23.x |
| 3.8.8、3.8.7、3.8.6、3.8.5、3.8.4 | 21.3 | 23.x |
| 3.8.3、3.8.2、3.8.1、3.8.0 | 21.3 | 22.x |
| 3.7.27、3.7.26、3.7.25、3.7.24、3.7.23、3.7.22、3.7.21、3.7.20、3.7.19 | 21.3 | 22.x |
| 3.7.18、3.7.17、3.7.16、3.7.15 | 20.3 | 22.x |
| 3.7.14、3.7.13、3.7.12、3.7.11 | 20.3 | 21.x |
| 3.7.10、3.7.9、3.7.8、3.7.7 | 19.3 | 21.x |
| 3.7.6、3.7.5、3.7.4、3.7.3、3.7.2、3.7.1、3.7.0 | 19.3 | 20.x |
3.RabbitMQ官网使用
RabbitMQ的官网十分详细,每种技术都可以在官网上找到解决方案。
官网地址:www.rabbitmq.com/
1)点击Get Started进入使用说明页面。
2)Download+Installation表示下载和安装,RabbitMQ Tutorials是文档操作手册
3)RabbitMQ支持Docker部署。
4.使用RPM包的方式部署RabbitMQ消息队列
4.1.安装Erlang环境
RabbitMQ 3.7.10版本需要依赖Erlang 19.3以上的版本。
1.安装依赖软件
[root@rabbitmq ~]# yum -y install build-essential openssl openssl-devel unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
2.安装erlang
[root@rabbitmq ~]# rpm -ivh erlang-19.3.6.4-1.el6.x86_64.rpm
警告:erlang-19.3.6.4-1.el6.x86_64.rpm: 头V4 RSA/SHA1 Signature, 密钥 ID 6026dfca: NOKEY
准备中... ################################# [100%]
正在升级/安装...
1:erlang-19.3.6.4-1.el6 ################################# [100%]
3.查看erlang的版本
[root@rabbitmq ~]# erl -version
Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 8.3.5.3
[root@rabbitmq rabbitmq]# systemctl start rabbitmq-server
4.2.部署RabbitMQ消息队列
1.安装socat
[root@rabbitmq rabbitmq]# yum -y install socat
2.下载RabbitMQ rpm包
[root@rabbitmq rabbitmq]# wget https://repo.huaweicloud.com/rabbitmq-server/v3.7.10/rabbitmq-server-3.7.10-1.el7.noarch.rpm
3.安装RabbitMQ
[root@rabbitmq rabbitmq]# rpm -ivh rabbitmq-server-3.7.10-1.el7.noarch.rpm
警告:rabbitmq-server-3.7.10-1.el7.noarch.rpm: 头V4 RSA/SHA1 Signature, 密钥 ID 6026dfca: NOKEY
准备中... ################################# [100%]
正在升级/安装...
1:rabbitmq-server-3.7.10-1.el7 ################################# [100%]
4.3.开启RabbitMQ后台管理系统
1.开启后台管理系统
[root@rabbitmq ~]# rabbitmq-plugins enable rabbitmq_management
Enabling plugins on node rabbit@elkstack-3:
rabbitmq_management
The following plugins have been configured:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
Applying plugin configuration to rabbit@elkstack-3...
The following plugins have been enabled:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
started 3 plugins.
2.开放登陆用户
[root@rabbitmq ~]# vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.7.10/ebin/rabbit.app
{loopback_users, [guest]}, #39行,将默认的<<"guest">>改成guest
4.4.启动RabbitMQ
1.启动RabbitMQ
[root@rabbitmq ~]# systemctl start rabbitmq-server.service
[root@rabbitmq ~]# systemctl enable rabbitmq-server.service
2.查看RabbitMQ的端口号
[root@rabbitmq ~]# netstat -lnpt | grep beam
tcp 0 0 0.0.0.0:25672 0.0.0.0:* LISTEN 13321/beam.smp
tcp 0 0 0.0.0.0:15672 0.0.0.0:* LISTEN 13321/beam.smp
tcp6 0 0 :::5672 :::* LISTEN 13321/beam.smp
#25672是集群通信端口 15672是后台管理系统端口 5672是程序连接MQ使用的端口
4.5.访问RabbitMQ的后台管理系统
访问服务器的5672端口进入MQ的后台管理系统,账号密码都是guest。
MQ后台管理系统界面如下。