RabbitMQ集群搭建

推荐相关文章阅读:前端

入门RabbitMQ

RabbitMQ核心原理和知识点

实战RabbitMQ

 

安装和准备节点

 

一、准备3个节点(下面是笔者的主机列表):java

 

主机名称node

iplinux

node1nginx

10.68.212.101正则表达式

node2浏览器

10.68.212.102服务器

node3cookie

10.68.212.103网络

 

官方强烈建议集群节点数量为奇数,例如:一、三、五、7。

 

二、每一个节点安装好rabbitmq服务,关于安装能够查看本人前面发布的文章。

 

入门RabbitMQ 

 

三、修改每一个对应节点的hostname:

 

  •  
# node1节点执行hostnamectl set-hostname node1# node2节点执行hostnamectl set-hostname node2# node3节点执行hostnamectl set-hostname node3reboot #重启

 

 

由于集群节点之间默认经过节点名称标识相互联系,因此集群节点名称必须惟一。节点名称默认为:rabbit@hostname,例如node1节点的默认节点名称为rabbit@node1,这里hostname很重要,必定是本机hostname,且要确保全部节点正确配置了/etc/hosts,由于节点之间是经过节点名称的hostname部分进行通讯的,除了默认以外节点名称还能够经过配置环境变量RABBITMQ_NODENAME来修改,可是格式必定要符合xxx@hostname。

 

四、每一个节点配置/etc/hosts,经过hostname获取主机节点名称后进行配置,笔者这里配置以下:

 

 

  •  
10.68.212.101  node110.68.212.102  node210.68.212.103  node3
#经过ping进行测试ping node1ping node2ping node3

 

五、经过下面命令启动每一个节点rabbitmq服务,确保可以正常启动:

  •  
rabbitmq-server -detached

六、经过下面命令查看每一个节点的集群状态,默认单节点启动就是一个单节点的集群:

  •  
rabbitmqctl cluster_status

 

 

正常状况下能够看到以下输出:

 

 

  •  
Cluster name: rabbit@node1  #集群名称,默认是节点名称Disk Nodes # 磁盘类型节点列表rabbit@node1 # 节点名称Running Nodes # 正在运行节点列表rabbit@node1............省略其它

至此,3个节点安装完毕,且可以正常启动,下面咱们开始建立集群。

 

建立集群

 

一、由于集群节点之间须要互相通讯,因此须要开通端口策略,简单粗暴方式是直接关闭防火墙,可是生产环境不推荐这么作,推荐作法是全部节点执行下面linux命令开通必要的端口:

  •  
firewall-cmd --zone=public --add-port=4369/tcp --permanentfirewall-cmd --zone=public --add-port=25672/tcp --permanentfirewall-cmd --zone=public --add-port=5672/tcp --permanentfirewall-cmd --zone=public --add-port=15672/tcp --permanentfirewall-cmd --zone=public --add-port=35672-35682/tcp --permanentfirewall-cmd --reload

 

二、配置cli命令工具和rabbitm服务身份验证的erlang cookie,对每一个节点经过以下方式进行配置:

 

  •  
# 中止全部节点的rabbitmq服务和erlang jvm进程rabbitmqctl stop# 配置root用户使用CLI命令cookie为123456(123456能够改成其它复杂的值)echo "123456" > /root/.erlang.cookie# 建立rabbitmq服务端cookie目录和文件mkdir -p /var/lib/rabbitmqtouch /var/lib/rabbitmq/.erlang.cookie# 配置rabbitmq服务端cookie为123456echo "123456" > /var/lib/rabbitmq/.erlang.cookie

 

三、经过下面命令启动因此节点:

  •  
rabbitmq-server -detached

 

四、将node2节点重置后加入node1节点集群,在node2节点上执行下面的命令:

 

  •  
rabbitmqctl stop_apprabbitmqctl resetrabbitmqctl join_cluster rabbit@node1

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

五、查看node1集群状况,回到node1节点,执行下面的命令:

  •  
rabbitmqctl cluster_status

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

六、回到node2执行下面命令,启动node2节点:

  •  
rabbitmqctl start_app

 

七、再次回到node1,查看集群状态:

  •  
rabbitmqctl cluster_status

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

八、继续将node3加入node1集群:

 

  •  
rabbitmqctl stop_apprabbitmqctl resetrabbitmqctl join_cluster rabbit@node1rabbitmqctl start_app

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

九、回到node1节点查看集群状态,固然也能够直接在node2和node3节点经过查看集群状态显示的结果也是和在node1节点查看显示结果是同样的:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

十、至此,由3个节点组成的集群建立完毕。如今咱们还能够中止集群中的某个节点,例如中止node1,在node1节点上执行下面命令:

  •  
rabbitmqctl stop

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

而后在node2或node3节点上查看集群状态:

 

  •  
rabbitmqctl cluster_status

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

而后下面命令再次启动node1,此时node1将会从中止时标记的对等节点同步集群数据信息,若是对等节点不可用,则node1将启动失败,后面会提到如何解决没法启动的状况。

  •  
rabbitmq-server -detached

 

 

十一、将某个节点重置后,该节点将忘记集群,等同退出集群,例如在node3节点上执行:

 

  •  
rabbitmqctl stop_apprabbitmqctl resetrabbitmqctl start_app

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

同时查看原理集群信息以下:

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

十二、若是某个节点宕机没法访问,那么咱们能够从其它可用的集群节点上剔除该不可用的宕机节点,例如咱们模拟把node1节点停掉,而后在node2节点上剔除node1节点,命令以下:

 

 

  •  
# node1节点执行 rabbitmqctl stop
# node2节点执行rabbitmqctl forget_cluster_node rabbit@node1

 

 

如今在node2节点查看集群状态信息以下:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

注意,如今node2仍然保留原来集群最终的状态,若是要彻底解散集群,应该继续将node2进行重置,重置rabbitmq节点将删除其全部数据。

 

另外,若是此时再次启动node1,会收到如下报错信息:

Node rabbit@node1 thinks it's clustered with node rabbit@node2, but rabbit@node2 disagrees

 

缘由是node1中止时将node2标记为下次启动时的对等节点,可是node2已经将node1从集群剔除出去,此时node1启动请求从node2同步数据时被拒绝,解决这个问题的办法是当node1在启动尝试10次请求链接node2的时间窗口内快速执行重置命令将node1进行重置,完整命令以下:

 

 

  •  
rabbitmq-server -detached# 执行完上面命令后快速执行重置命令,注意必定要快rabbitmqctl reset

 

若是前面但愿时间窗口加长,能够经过修改rabbitmq配置文件下面两个配置项:

 

  •  
#等待60秒而不是30mnesia_table_loading_retry_timeout = 60000#重试15次而不是10mnesia_table_loading_retry_limit = 15

 

默认配置文件位置,新安装的服务器不存在该文件须要手工建立:

  •  
$RABBITMQ_HOME/etc/rabbitmq/rabbitmq/rabbitmq-env.conf

 

1三、咱们能够经过下面命令修改节点的类型为磁盘或RAM:

 

 

  •  
# 修改成磁盘类型rabbitmqctl stop_apprabbitmqctl change_cluster_node_type discrabbitmqctl start_app
# 修改成内存类型rabbitmqctl stop_apprabbitmqctl change_cluster_node_type ramrabbitmqctl start_app
# 或者直接在加入集群时指定节点以什么类型加入rabbitmqctl join_cluster --ram rabbit@node1

 

集群核心原理

 

一、经过前面的方式建立集群后,集群全部节点的数据或状态信息互相同步复制,除了消息队列外,消息队列默认状况下只保存在一个节点上,客户端若是访问到其它节点上时,其它节点会路由到对应的队列主节点上。也就是说集群并无实现队列的高可用,若是队列所在节点挂了,那么宕机节点上的全部队列将不可用,若是要实现队列高可用,后面会单独介绍一种叫队列镜像的方式来实现。

 

二、Admin管理插件会将集群全部节点信息汇总一并展现到前端页面。

 

三、集群节点数量强烈建议为奇数,例如:一、三、五、7。

 

四、集群中节点能够时磁盘类型,也能够是RAM内存类型,RAM类型目的是为了提高吞吐量,因为RAM类型节点全部数据在启动时从其它磁盘(只会选择磁盘类型节点)节点同步,因此一个集群必须至少有一个磁盘类型节点,一般建议是把所有节点都配置为磁盘节点。

 

五、集群节点在中止时会选择并标识一个可用的对等磁盘类型节点,做用是在下次启动时从这个标识的对等节点同步数据。若是启动时这个对等节点不可用(默认是尝试链接10次,每次超时30s),则该启动失败。可是若是中止时没有可用的对等节点,好比最后中止的节点,那么这个节点在下次启动时将不会链接对等节点来同步数据,而是直接启动,其它节点可以再次加入它。

 

六、当某个节点被重置后,或修改hostname后,再次重启将没法识别原理的集群,而是以单节点方式启动。

 

镜像队列

 

概念原理部分:

 

前面搭建的集群除了队列数据外其它数据例如交换和绑定都是在全部节点进行复制,经过镜像队列能够弥补队列高可用的问题,镜像队列思想是将队列配置为一主多从,每一个队列都有一个主节点,多个镜像节点,全部操做都是先在主节点上进行,而后复制到镜像节点,这样能够保证消息的FIFO顺序。镜像队列不会同步被主节点队列确认的消息。实际上镜像队列只实现高可用,而没有实现负载均衡的效果。若是主服务器发生故障,则将最先的镜像提高为主节点。rabbitmq经过策略policy的方式来配置镜像队列,policy按名称正则表达式方式进行队列的匹配,下面是一个例子:

 

 

  •  
rabbitmqctl set_policy ha-hello "^hello\." \  '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

 

  • set_policy:表示建立policy

  • ha-hello:表示policy名称

  • ^hello\.:表示该policy匹配名称以hello开头的队列

  • ha-mode:指定镜像队列复制因子模式,后面经过表格来讲明

  • ha-params: 配套ha-mode可选参数

  • ha-sync-mode:同步模式。

 

ha-mode

ha-params

描述

exactly

数量

指定镜像队列副本数量,具体数量由ha-params指定

all

队列镜像到集群全部节点,能够配合仲裁节点一块儿使用。

nodes

节点名称

队列镜像到指定的集群节点名称。

 

任什么时候候均可以修改policy,当policy发生变化时,它将努力将其现有镜像保留到与新策略相适应的程度。rabbitmq镜像队列复制数量最佳多少比较合适,官方给出是经验是3个节点2个,5个节点3个。除了能够配置镜像节点数量策略外,还能够配置主节点位置策略,队列主节点位置策略是经过建立队列时指定x-queue-master-locator策略属性来配置,可配置下面3种策略:

 

策略属性值

描述

min-masters

选择托管最少主节点数量的节点做为当前队列的主节点

client-local

选择客户端链接到的节点做为当前队列的主节点

random

随机选择一个节点做为当前队列的主节点

 

实战部分:

 

一、查看前面搭建的集群状态:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

二、经过下面java客户端代码建立3个测试队列:

 

pom.xml坐标:

 

  •  
<dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>4.11.3</version></dependency>

 

Main方法测试代码以下:

 

 

  •  
public class Main {
public static void main(String[] args) throws Exception { ConnectionFactory factory = new ConnectionFactory(); //这里先访问其中一个节点,后续经过软负载均衡器nginx进行rabbitmq集群服务的负载均衡 factory.setHost("10.68.212.101"); //rabbitmqctl add_user lazy 111111 //rabbitmqctl set_user_tags lazy administrator //rabbitmqctl set_permissions -p / lazy ".*" ".*" ".*" factory.setUsername("lazy"); factory.setPassword("111111"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel();
channel.queueDeclare("hello1-queue", true, false,false, null); channel.queueDeclare("hello2-queue", true, false, false, null); channel.queueDeclare("hello3-queue", true, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); }
}

 

三、登陆集群任何一个节点能够查看队列列表:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

四、两种方式能够查看队列镜像信息:

 

  •  
# 经过CLI命令行(第一种)rabbitmqctl list_queues name policy pid slave_pids
# 者在全部节点执行下面命令开启admin管理插件(第二种)rabbitmq-plugins enable rabbitmq_management而后在任何一个节点访问,后续会搭建nginx进行软负载:http://10.68.212.101:15672/登陆帐号和密码为:lazy / 111111

 

第一种方式截图:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

第二种方式截图:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

五、分别建立3个policy:

 

 

  •  
# 将hello1-开头的全部队列镜像模式设置为exactlyrabbitmqctl set_policy --vhost / --apply-to queues  ha-exactly-demo "^hello1-*" \ '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
# 将hello2-开头的全部队列镜像模式设置为allrabbitmqctl set_policy --vhost / --apply-to queues ha-all-demo "^hello2-*" \ '{"ha-mode":"all"}'
# 将hello3-开头的全部队列镜像模式设置为nodes,节点为node2,node3rabbitmqctl set_policy --vhost / --apply-to queues ha-nodes-demo "^hello3-*" \ '{"ha-mode":"nodes","ha-params":["rabbit@node2", "rabbit@node3"]}'

 

 

六、查看policy生效状况:

 

# 经过CLI命令行(第一种)查看:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

# 经过管理页面(第二种)查看:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

深度解答镜像问题:

 

一、若是修改某个队列的策略致使新的策略的节点不包含任何原理策略的节点,例如原来策略是node1,node2,新的策略节点配置为node3,node4,这种状况下数据如何迁移?

 

答:这种状况会新的策略会包含node3,node4节点以及原来策略的主节点例如node1,而后node3,node4会从原来策略的主节点node1同步消息数据,直到同步完成才将node1剔除。

 

二、当rabbitmq链接关闭时排他队列将被删除,请问排他队列能够作镜像吗?

 

答:排他队列永远不会被镜像。

 

三、若是rabbitmq镜像队列主节点发生故障,如何提高镜像节点?

答:会将运行时间最长的镜像节点提高为主节点。可是默认状况下

 

四、若是rabbitmq镜像队列主节点发生故障,会丢失哪些状况的数据吗?

 

答:镜像节点默认只会同步镜像节点第一次或从新加入(置空历史消息数据)作为主节点那一刻时间以后的主节点新的消息,不会同步加入主节点以前的消息。

从消费端来分析:若是过程当中主节点发生故障,而后提高该镜像节点为主节点,那么可能会丢失镜像节点加入以前的历史消息数据(若是消费速度很慢没有被消费完的话,可是能够经过配置为不自动提高非全量同步的镜像节点为主节点,而后经过手动同步全量数量后来弥补这个问题,注意同步过程会使全部其它队列阻塞)。而后从新排队当前镜像节点还没有收到消费者确认的那部分消息发送给消费者,因此消费者必须作好幂等性处理(由于可能会重复),因此消费端可能会丢失数据,也可能会重复收到消息。

从发送端来分析:若是发送者配置为自动确认模式,若是刚好当发送消息到主节点的同时主节点挂断,那么消息可能会丢失。可是发送者若是配置为手工确认模式,那么主节点会保证全部镜像节点都接受到该消息,才会向发布者确认并按期被落盘,因此,若是主节点挂断,那么发送者能够正确知道消息确认状况,因此发送者只要配置确认机制,基本消息不会丢失。不然,会发生丢失的可能。

 

五、镜像节点如何手工同步主队列节点的全量消息数据?

答:能够经过下面命令手工不一样历史消息数据:

  •  
 rabbitmqctl sync_queue your_queue_name

 

六、如何配置为不自动提高非全量同步的镜像节点?

答:从rabbitmq3.7.5版本开始,能够经过配置队列声明属性:ha-promote-on-failure值为:when-synced来确保不自动提高非全量同步的镜像来防止历史数据的丢失,默认值为:always表示老是自动提高非全量同步镜像节点。当值配置为:when-synced时,发送者必须使用手动确认模式才能彻底确保消息总体不丢失,不然when-synced配置就是毫无心义的。

 

七、如何查看队列节点同步状况?

答:能够经过下面命令查看:

  •  
rabbitmqctl list_queues name slave_pids synchronised_slave_pids

 

八、如何配置镜像节点为老是默认全量同步主队列全部历史数据?

答:能够经过配置队列声明属性:ha-sync-mode值为:manual表示历史全量数据须要手动同步,值为:automatic表示自动同步历史全量数据。

 

九、手动关闭rabbitmq节点,会提高镜像队列吗?

答:默认状况下,rabbitmq显示中止或操做系统关闭时,不会提高镜像队列为主队列的,此时整个队列为关闭状态。可是若是因为节点崩溃例如内存溢出,磁盘爆满或者网络中断、剔除集群等缘由时,才会提高镜像队列为主队列。

 

经过Nginx实现集群节点负载均衡:

 

一、安装nginx,这里挑选node1节点来安装nginx:

 

  •  
cd /opt/tarballwget http://nginx.org/download/nginx-1.16.1.tar.gztar -xvf nginx-1.16.1.tar.gz -C /opt/src/cd /opt/src/nginx-1.16.1/./configure --with-streammakemake install

 

二、配置nginx环境变量:

 

  •  
vi /etc/profilesource /etc/profile

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

三、启动nginx:

  •  
nginx

 

四、配置nginx负载均衡和代理转发:

  •  
vi /usr/local/nginx/conf/nginx.conf

 

关键配置内容以下:

 

  •  
stream {        upstream rabbitmq_server {                server node1:5672;                server node2:5672;                server node3:5672;        }        server {                listen       18080;                proxy_connect_timeout 5s;                proxy_timeout 5s;                proxy_pass   rabbitmq_server;        }
}
http { upstream rabbitmq_admin { server node1:15672; server node2:15672; server node3:15672;    } server { listen 18081; server_name rabbitmq_admin;
location / { proxy_pass http://rabbitmq_admin; } }}

 

五、修改node1防火墙端口策略:

 

  •  
firewall-cmd --zone=public --add-port=18080/tcp --permanentfirewall-cmd --zone=public --add-port=18081/tcp --permanentfirewall-cmd --reload

 

六、浏览器访问nginx负载均衡admin地址:

http://10.68.212.101:18081/

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

七、java客户端代码修改成以下链接地址:

 

 

  •  
public class Main {        public static void main(String[] args) throws Exception {                ConnectionFactory factory = new ConnectionFactory();                //访问nginx地址                factory.setHost("10.68.212.101");                factory.setPort(18080);                //rabbitmqctl add_user lazy 111111                //rabbitmqctl set_user_tags lazy administrator                //rabbitmqctl set_permissions -p / lazy ".*" ".*" ".*"                factory.setUsername("lazy");                factory.setPassword("111111");                Connection connection = factory.newConnection();                Channel channel = connection.createChannel();
channel.queueDeclare("hello1-queue", true, false,false, null); channel.queueDeclare("hello2-queue", true, false, false, null); channel.queueDeclare("hello3-queue", true, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); }
}

 

至此,rabbitmq集群搭建讲解完毕。

 

---------------------- 正文结束 ------------------------

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=