RabbitMQ
RabbitMQ集群搭建
1. rabbitMQ简介
1.1 RabbitMQ的特点
MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品
1.2 使用场景
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。
1.3 含义
RabbitMQ是一个在AMQP基础上完成的,可复用的企业消息系统。他遵循Mozilla Public License开源协议
1.4 基本概念
RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP(高级消息队列协议)的标准实现。如果不熟悉AMQP,直接看RabbitMQ的文档会比较困难
1.5 重点概念说明
Broker | 简单来说就是消息队列服务器实体。 |
---|---|
Exchange | 消息交换机,它指定消息按什么规则,路由到哪个队列。 |
Queue | 消息队列载体,每个消息都会被投入到一个或多个队列。 |
Binding | 绑定,它的作用就是把exchange和queue按照路由规则绑定起来。 |
Routing Key | 路由关键字,exchange根据这个关键字进行消息投递。 |
vhost | 虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。 |
producer | 消息生产者,就是投递消息的程序。 |
consumer | 消息消费者,就是接受消息的程序。 |
channel | 消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。 |
1.6 RabbitMQ的结构图如下:
1.7 消息队列的使用过程大概如下:
- 客户端连接到消息队列服务器,打开一个channel。
- 客户端声明一个exchange,并设置相关属性。
- 客户端声明一个queue,并设置相关属性。
- 客户端使用routing key,在exchange和queue之间建立好绑定关系。
- 客户端投递消息到exchange。
- exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里
1.8 exchange的几个类型
- exchange是完全根据key进行投递的叫做Direct交换机,
- 例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。
- 对key进行模式匹配后进行投递的叫做Topic交换机,符号”#”匹配一个或多个词,符号””匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.”只匹配”abc.def”。
- 还有一种不需要key的,叫做Fanout交换机,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。
1.9 RabbitMQ消息的持久化
消息队列持久化包括3个部分:
- exchange持久化,在声明时指定durable => 1
- queue持久化,在声明时指定durable => 1
- 消息持久化,在投递时指定delivery_mode => 2(1是非持久化)
- 如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。
- 如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。
1.10 消息持久
- 将交换机置为可持久;
- 将通道置为可持久
- 消息发送时设置可持久。
当我们“生产”了一条可持久化的消息,尝试中断MQ服务,启动消费者获取消息,消息依然能够恢复。相反,则抛出异常。
2. RabbitMQ部署安装(以下操作需两个节点同步操作)
主机名 | 主机IP | 用途 |
---|---|---|
RabbitMQ-node01 | 192.168.200.23 | 主节点 |
RabbitMQ-node02 | 192.168.200.24 | 从节点 |
RabbitMQ-VIP | 192.168.200.25 | VIP |
2.1 Erlang在默认的YUM存储库中不可用,因此需要安装EPEL存储库
由于RabbitMQ依赖Erlang, 所以需要先安装Erlang。
2.1.1 安装Erlang
#添加erlang solutions源
[root@rabbitmq-node01 ~]# yum -y install epel-release
[root@rabbitmq-node01 ~]# rpm -qa epel-release
epel-release-7-11.noarch
#我们要安装最新版本的Erlang到服务器中
[root@rabbitmq-node01 ~]# yum -y update epel-release
[root@rabbitmq-node01 ~]# rpm -qa epel-release
epel-release-7-12.noarch
#安装Erlang
[root@rabbitmq-node01 ~]# yum -y install erlang socat
[root@rabbitmq-node01 ~]# rpm -qa erlang socat
socat-1.7.3.2-2.el7.x86_64
erlang-R16B-03.18.el7.x86_64
2.1.2 检查Erlang版本
[root@rabbitmq-node01 ~]# erl -version
Erlang (ASYNC_THREADS,HIPE) (BEAM) emulator version 5.10.4
2.2 安装RabbitMQ
RabbitMQ为预编译并可以直接安装的企业Linux系统提供RPM软件包。 唯一需要的依赖是将Erlang安装到系统中。 我们已经安装了Erlang,我们可以进一步下载RabbitMQ。
#通过运行下载Erlang RPM软件包。
[root@rabbitmq-node01 ~]# which wget
/usr/bin/wget
[root@rabbitmq-node01 ~]# wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.10/rabbitmq-server-3.6.10-1.el7.noarch.rpm
[root@rabbitmq-node01 ~]# ll -d rabbitmq-server-3.6.10-1.el7.noarch.rpm
-rw-r--r-- 1 root root 4930939 5月 25 2017 rabbitmq-server-3.6.10-1.el7.noarch.rpm #rpm包
#运行RPM安装RPM包
[root@rabbitmq-node01 ~]# rpm -Uvh rabbitmq-server-3.6.10-1.el7.noarch.rpm
警告:rabbitmq-server-3.6.10-1.el7.noarch.rpm: 头V4 RSA/SHA512 Signature, 密钥 ID 6026dfca: NOKEY
准备中... ################################# [100%]
正在升级/安装...
1:rabbitmq-server-3.6.10-1.el7 ################################# [100%]
2.3 开始RabbitMQ
#启动RabbitMQ服务器进程
[root@rabbitmq-node01 ~]# systemctl start rabbitmq-server
#在引导时自动启动RabbitMQ
[root@rabbitmq-node01 ~]# systemctl enable rabbitmq-server
Created symlink from /etc/systemd/system/multi-user.target.wants/rabbitmq-server.service to /usr/lib/systemd/system/rabbitmq-server.service.
#检查RabbitMQ服务器的状态
[root@rabbitmq-node01 ~]# systemctl status rabbitmq-server
如果启动成功,应该得到以下输出:
3. 访问Web控制台
3.1 启动RabbitMQ Web管理控制台(以下操作需两个节点同步操作)
[root@rabbitmq-node01 ~]# rabbitmq-plugins enable rabbitmq_management
The following plugins have been enabled:
amqp_client
cowlib
cowboy
rabbitmq_web_dispatch
rabbitmq_management_agent
rabbitmq_management
Applying plugin configuration to rabbit@rabbitmq-node01... started 6 plugins.
3.2 将RabbitMQ文件的所有权提供给RabbitMQ用户
[root@rabbitmq-node01 ~]# chown -R rabbitmq:rabbitmq /var/lib/rabbitmq/
3.3 为RabbitMQ Web管理控制台创建管理用户
[root@rabbitmq-node01 ~]# rabbitmqctl add_user admin admin
Creating user "admin" 账号 密码
[root@rabbitmq-node01 ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator]
[root@rabbitmq-node01 ~]# rabbitmqctl set_permissions -p / admin “.*” “.*” “.*”
Setting permissions for user "admin" in vhost "/"
3.4 将管理员更改为管理员用户的首选用户名,然后浏览器访问
4. 实现主从两台RabbitMQ信息同步
4.1 分别加入映射IP
[root@rabbitmq-node01 ~]# vim /etc/hosts
[root@rabbitmq-node01 ~]# tail -2 /etc/hosts
192.168.200.23 rabbitmq-node01
192.168.200.24 rabbitmq-node02
4.2 停掉Rabbitmq从节点
[root@rabbitmq-node02 ~]# systemctl status rabbitmq-server
[root@rabbitmq-node02 ~]# systemctl stop rabbitmq-server
[root@rabbitmq-node02 ~]# systemctl status rabbitmq-server
4.3 Rabbitmq主节点中的.erlang.cookie文件同步到Rabbitmq从节点
[root@rabbitmq-node02 ~]# cd /var/lib/rabbitmq
[root@rabbitmq-node02 rabbitmq]# scp -r root@192.168.200.23:/var/lib/rabbitmq/.erlang.cookie .
[root@rabbitmq-node02 rabbitmq]# ll -d .erlang.cookie
-r-------- 1 root root 20 11月 5 07:23 .erlang.cookie
#修改其属主属组与权限
[root@rabbitmq-node02 rabbitmq]# chown rabbitmq.rabbitmq .erlang.cookie
[root@rabbitmq-node02 rabbitmq]# chmod 600 .erlang.cookie
[root@rabbitmq-node02 rabbitmq]# ll -d .erlang.cookie
-rw------- 1 rabbitmq rabbitmq 20 11月 5 07:23 .erlang.cookie
4.4 启动Rabbitmq从节点
[root@rabbitmq-node02 rabbitmq]# systemctl status rabbitmq-server
[root@rabbitmq-node02 rabbitmq]# systemctl start rabbitmq-server
[root@rabbitmq-node02 rabbitmq]# systemctl status rabbitmq-server
4.5 将Rabbitmq从节点加到Rabbitmq主节点集群当中
#停掉rabbitmq-node02应用
[root@rabbitmq-node02 rabbitmq]# rabbitmqctl stop_app
Stopping rabbit application on node 'rabbit@rabbitmq-node02'
#将Rabbitmq从节点加到Rabbitmq主节点集群当中
[root@rabbitmq-node02 rabbitmq]# rabbitmqctl join_cluster rabbit@rabbitmq-node01
Clustering node 'rabbit@rabbitmq-node02' with 'rabbit@rabbitmq-node01'
#启动rabbitmq-node01应用
[root@rabbitmq-node02 rabbitmq]# rabbitmqctl start_app
Starting node 'rabbit@rabbitmq-node02'
#查看集群状态
[root@rabbitmq-node01 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@rabbitmq-node01'
[{nodes,[{disc,['rabbit@rabbitmq-node01','rabbit@rabbitmq-node02']}]},
{running_nodes,['rabbit@rabbitmq-node02','rabbit@rabbitmq-node01']},
{cluster_name,<<"rabbit@rabbitmq-node01">>},
{partitions,[]},
{alarms,[{'rabbit@rabbitmq-node02',[]},{'rabbit@rabbitmq-node01',[]}]}]
[root@rabbitmq-node02 rabbitmq]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@rabbitmq-node02'
[{nodes,[{disc,['rabbit@rabbitmq-node01','rabbit@rabbitmq-node02']}]},
{running_nodes,['rabbit@rabbitmq-node01','rabbit@rabbitmq-node02']},
{cluster_name,<<"rabbit@rabbitmq-node01">>},
{partitions,[]},
{alarms,[{'rabbit@rabbitmq-node01',[]},{'rabbit@rabbitmq-node02',[]}]}]
4.6 在web页面检查集群状态
4.7 增加主备同步自动同步模式(主从同时进行)
[root@rabbitmq-node01 ~]# rabbitmqctl set_policy -p / ha-all "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
Setting policy "ha-all" for pattern "^" to "{\"ha-mode\":\"all\",\"ha-sync-mode\":\"automatic\"}" with priority "0"
[root@rabbitmq-node01 ~]# rabbitmqctl list_policies
Listing policies
/ ha-all all ^ {"ha-mode":"all","ha-sync-mode":"automatic"} 0
[root@rabbitmq-node01 ~]# rabbitmqctl stop_app;
Stopping rabbit application on node 'rabbit@rabbitmq-node01'
[root@rabbitmq-node01 ~]# rabbitmqctl start_app;
Starting node 'rabbit@rabbitmq-node01'
4.8 在web页面测试信息同步状态
4.8.1 已知目前队列信息均为空
4.8.2 在Rabbitmq主节点添加一条队列信息
4.8.3 测试消费队列同步信息,在Rabbitmq主节点的队列中添加一条信息
5. 部署keepalive高可用集群
5.1 本地yum源安装keepalive软件
[root@rabbitmq-node01 ~]# yum -y install keepalived
[root@rabbitmq-node01 ~]# rpm -qa keepalived
keepalived-1.3.5-16.el7.x86_64
5.2 修改keealived主从优先级
#修改keealived主配置文件
[root@rabbitmq-node01 ~]# cd /etc/keepalived/
[root@rabbitmq-node01 keepalived]# vim keepalived.conf
[root@rabbitmq-node01 keepalived]# cat keepalived.conf
! Configuration File for keepalived
vrrp_instance VI_1 {
state BACKUP
interface ens32
garp_master_delay 10
virtual_router_id 44
priority 100 #主节点要高于备节点
nopreempt #当主节点恢复后,VIP不主动飘回
#advert_int的作用是巡检的次数。keepalived默认是在启动完成后3秒向state:MASTER切换。若此处设置成2,则是2*3=6秒后才开启切换。
advert_int 1
authentication {
auth_type PASS
auth_pass rabbitMQ #密码唯一,主备要一致
}
virtual_ipaddress {
192.168.200.25/24 #VIP
}
}
#修改keealived从配置文件
[root@rabbitmq-node02 rabbitmq]# cd /etc/keepalived/
[root@rabbitmq-node02 keepalived]# vim keepalived.conf
[root@rabbitmq-node02 keepalived]# cat keepalived.conf
! Configuration File for keepalived
vrrp_instance VI_1 {
state BACKUP
interface ens32
garp_master_delay 10
virtual_router_id 44
priority 90 #备节点要低于主节点
nopreempt #当主节点恢复后,VIP不主动飘回
#advert_int的作用是巡检的次数。keepalived默认是在启动完成后3秒向state:MASTER切换。若此处设置成2,则是2*3=6秒后才开启切换。
advert_int 1
authentication {
auth_type PASS
auth_pass rabbitMQ #密码唯一,主备要一致
}
virtual_ipaddress {
192.168.200.25/24 #VIP
}
}
5.3 启动keealived
[root@rabbitmq-node01 keepalived]# systemctl status keepalived
[root@rabbitmq-node01 keepalived]# systemctl start keepalived
[root@rabbitmq-node01 keepalived]# systemctl status keepalived
5.4 检查VIP状态
[root@rabbitmq-node01 keepalived]# ip addr | grep -w 192.168.200.25
inet 192.168.200.25/24 scope global secondary ens32
[root@rabbitmq-node02 keepalived]# ip addr | grep -w 192.168.200.25
5.5 测试VIP登录Rabbitmq的web页面http://192.168.200.25:15672
5.6 测试keepalived主备切换
5.6.1 宕掉主节点服务器
#模拟主节点服务器意外故障
[root@rabbitmq-node01 keepalived]# shutdown
#VIP主动飘到了从节点
[root@rabbitmq-node02 keepalived]# ip addr | grep -w 192.168.200.25
inet 192.168.200.25/24 scope global secondary ens32
5.6.2检查VIP登录Rabbitmq的web页面有无异常http://192.168.200.25:15672
5.6.3 主节点服务器已修复启动,正常运行中
#检查rabbitmq与keepalived服务均正常运行
[root@rabbitmq-node01 ~]# systemctl status rabbitmq-server
[root@rabbitmq-node01 ~]# systemctl status keepalived
#检查VIP所在位置
[root@rabbitmq-node01 ~]# ip addr | grep -w 192.168.200.25
[root@rabbitmq-node02 ~]# ip addr | grep -w 192.168.200.25
inet 192.168.200.25/24 scope global secondary ens32
#备注:这说明之前的配置已生效,VIP不会主动往回飘
5.6.4 宕掉从节点服务器
#模拟从节点服务器意外故障
[root@rabbitmq-node02 keepalived]# shutdown
#VIP主动又飘回了主节点
[root@rabbitmq-node01 ~]# ip addr | grep -w 192.168.200.25
inet 192.168.200.25/24 scope global secondary ens32