RabbitMQ 初识与安装
什么是MQ?为什么要使用MQ?
MQ:MessageQueue,消息队列。队列,是一种FIFO先进先出的数据结构,消息由生产者发送到MQ进行排队,然后按提交顺序交由消息的消费者进行处理。
MQ的作用主要有以下三个方面:
- 异步:可以提高系统的响应速度、吞吐量
- 解耦: 提高系统扩展性,减少服务之间影响,稳定性增加,但同样增加了系统开发的复杂性,另外解耦后可以实现数据的分发,可以由一个多个消费者进行消费,消费者的增加或减少对生产者没有影响。
- 削峰:MQ可以充当一个蓄水池,进行上游存储(生产者),下游根据自身能力进行消费,慢慢排水,就能达到以稳定的系统资源面对突来的大流量冲击。
MQ的缺点:
- 系统可用性降低,MQ服务宕机,对业务产生影响。(服务宕机不可避免,比起服务一起死掉,只影响到了使用MQ服务,其他服务可照常进行业务,利大于弊,可以采用集群架构,保证服务高可用)
- 系统复杂度提高,引入MQ后,数据链路会变得复杂,并且带来一些问题,消息丢失、重复调用、保证消息顺序等问题
- 消息一致性问题,消息发送到多个服务,有的成功,有的出现失败等问题
主流MQ产品对比
RabbitMQ 安装
RabbitMQ是基于Erlang语言开发,所以安装前需要安装Erlang语言环境。需要注意下的是RabbitMQ与ErLang是有版本对应关系的
-
查看地址:https://www.rabbitmq.com/which-erlang.html
-
安装erlang
# 使用RPM方式安装Erlang rpm -ivh erlang-23.2.7-1.el7.x86_64.rpm #查看是否安装成功 erl -version
-
安装RabbitMQ
- 官网:添加链接描述
#使用RPM方式安装RabbitMQ rpm -Uvh rabbitmq-server-3.9.15-1.el7.noarch.rpm #查看是否安装成功 whereis rabbitmqctl #启动RabbitMQ服务 service rabbitmq-server start / systemctl start rabbitmq-server.service #打开RabbitMq Web端管理页面,访问端口HTTP 15672 rabbitmq-plugins enable rabbitmq_management
-
配置登录用户
- 默认用户guest,只能在本地local host登录访问,不能远程登录
- Web管理端也可以配置 Admin ——> User
#添加用户 rabbitmqctl add_user admin admin #配置权限 rabbitmqctl set_permissions -p / admin "." "." ".*" #为用户设置标签 rabbitmqctl set_user_tags admin administrator
先学习一波大神对RabbitMQ进行架构思想、产品特性讲解的神级文章
MQ的应答模式
-
acknowledge-mode: none(无应答模式)
在这种模式下,不管消费者异常消费,还是正常消费,MQ服务器中的队列都会自动删除已消费的消息 -
acknowledge-mode: auto(自动应答模式)
当mq的应答模式配置为auto,或者没有进行配置时,系统会默认为自动应答模式。在这种情况下,只要我们的消费者,在消费消息的时候没有抛出异常,那服务端MQ会认为,消息消费正常,删除队列中的消息;如果消费过程中,抛出了异常,消息会进行自动补偿,重会队列头部,再次被拉到消费者的缓冲区(prefetch count),进行重复消费。此时如果缓冲区的大小设置为1,那么整个队列就会被阻塞,unacked也会显示为1(单线程消费的情况下) -
acknowledge-mode: manual(手动应答模式)
当设置为应手动应答时,我们需要在消费消息的时候手动告诉MQ我们消费的情况,否者MQ会一直等待消费端的消息,如果一直没有应答,当消费数量达到缓冲区大小(prefetch count)后,队列会全部阻塞。 -
channel.basicReject(deliveryTag, true)-------------拒绝deliveryTag(一个消费线程对应的一个消费ID,是自增的LONG类型)对应的消息,第二个参数是否requeue,true则重新入队列,否则丢弃或者进入死信队列。该方法reject后,该消费者还是会消费到该条被reject的消息。
-
channel.basicNack(deliveryTag, false, true)---------------不确认deliveryTag对应的消息,第二个参数是否应用于多消息,第三个参数是否requeue,与basic.reject区别就是同时支持多个消息,可以nack该消费者先前接收未ack的所有消息。nack后的消息也会被自己消费到。
-
channel.basicRecover(true)------------是否恢复消息到队列,参数是是否requeue,true则重新入队列,并且尽可能的将之前recover的消息投递给其他消费者消费,而不是自己再次消费。false则消息会重新被投递给自己。
大神的讲解,让我对RabbitMQ整体有一个基础的认知,开始搭建集群:
普通集群(假设存在:A、B Node节点服务):
-
需要同步集群节点中的Cookie
- 默认位置:/var/lib/rabbitmq/ 目前下存在 .erlang.cookie 文件,里面有一个字符串,我们要做的就是让集群节点的每个Cookie值一致。
- 保持节点之间的通信正常,互相之间能够Ping通,设置Host名称
-
接下来将A节点加入到B节点集群中
- 启动RabbitMQ服务时,会同时启动Erlang虚拟机和RabbitMQ服务,首先我们关闭A节点的RabbitMq服务
#关闭 RabbitMq服务 rabbitmqctl stop_app # 将A节点加入到B节点集群中 rabbit@ 是固定格式 worker2 是B节点hostname rabbitmqctl join_cluster --ram rabbit@worker2
-
-ram 表示以Ram节点加入集群。RabbitMQ的集群节点分为disk和ram。disk节点会将元数据保存到硬盘当中,而ram节点只是在内存中保存元数据,我在搭建的过程中,ram节点是无法使用延时插件的,必须使用disk
-
由于ram节点减少了很多与硬盘的交互,所以,ram节点的元数据使用性能会比较高。但是,同时,这也意味着元数据的安全性是不如disk节点的。在我们这个集群中,A节点 以ram节点的身份加入到worker2集群里,因此,是存在单点故障的。如果worker2节点服务崩溃,那么元数据就有可能丢失。在企业进行部署时,性能与安全性需要自己进行平衡。
-
元数据只包含:交换机、队列的定义,与消息无关
执行完之后,我们就可以在Web管理端看见集群信息了,也可以使用命令查看:rabbitmqctl cluster_status
镜像集群
首先创建一个 /mirror(名字自取)的虚拟主机,然后再添加对应的镜像策略
# 创建虚拟主机
rabbitmqctl add_vhost /mirror
# 创建镜像策略
rabbitmqctl set_policy ha-all --vhost "/mirror" "^" '{"ha-mode":"all"}'
语法:set_policy {NAME} {PATTERN} {DEFINITION}
NAME - 策略名,可自定义
PATTERN - 队列的匹配模式(正则表达式)
^ 可以使用正则表达式,比如 ^queue_ 表示对队列名称以 queue_ 开头的所有队列进行镜像,而 ^ 会匹配所有的队列。
DEFINITION - 镜像定义,包括三个部分 ha-mode, ha-params, ha-sync-mode
- ha-mode - high available 高可用模式,指镜像队列的模式,有效值为 all/exactly/nodes。
- all,即复制到所有节点,包含新增节点。all 表示在集群中所有的节点上进行镜像。
- exactly 表示在指定个数的节点上进行镜像,节点的个数由 ha-params 指定;
- nodes 表示在指定的节点上进行镜像,节点名称通过 ha-params 指定。
- ha-params - ha-mode 模式需要用到的参数。
- ha-sync-mode - 进行队列中消息的同步方式,有效值为 automatic 和 manual
通过以上,我们就大概对Rabbit整体搭建完毕了,是时候奖励一下自己了,下篇我们学习如何通过Java 使用