大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
先来介绍一下RabbitMQ集群
RabbitMQ集群有两种模式,一种是普通模式,即默认的集群模式,另外一种为镜像模式,可以把队列做成镜像队列
我们在学习两种模式之前,先来了解下一些关于RabbitMQ集群的概念
元数据:包括队列元数据,交换器元数据,交换器元数据,vhost元数据
(1)队列元数据:队列名称和它的属性;
(2)交换器元数据:交换器名称、类型和属性;
(3)绑定元数据:一张简单的表格展示了如何将消息路由到队列;
(4)vhost元数据:为vhost内的队列、交换器和绑定提供命名空间和安全属性;
由于RabbitMQ集群会始终同步这四种类型的内部元数据,所以当用户访问其中任何一个RabbitMQ节点时,通过rabbitmqctl查询到的队列,交换机等信息都是相同的。
节点:RabbitMQ集群中包含两种节点:磁盘节点、内存节点
磁盘节点:将元数据存放在硬盘,一个集群至少有一个磁盘节点,元数据至少保存在一个磁盘上,内存节点重启后去磁盘节点拷贝当前集群元数据。如果磁盘节点全挂掉了,集群无法创建新的东西,但是仍然能继续使用已经存在的东西
内存节点:内存节点的元数据存放在内存中,性能比磁盘节点好。其性能只体现在资源管理上,比如增加或删除队列,虚拟主机,交换机等,发送和接受message速度同磁盘节点一样。
RabbitMQ的两种模式
普通模式
在普通集群里,元数据信息在所有节点上是一致的,但是队列的完整内容却只存在创建它的节点上,各个节点仅有相同的队列元数据。当生产者发送消息到节点A的队列中后,消费者从节点C拉取时,RabbitMQ会临时在节点A与节点C之间进行消息传输,把节点A中的消息实体取出并经过节点C发送给消费者。
但是该模式存在一个问题:当节点A发生故障后,节点C无法取到节点A中还未被消费的消息实体。如果队列没有做持久化,那么其它节点可以创建同样的队列继续运作,但是这样队列不持久化,消息就没持久化,那么存在该队列上的消息将永久性丢失,如果做了消息持久化,由于队列也被持久化了,其它节点无法创建对应队列,那么只有等节点A故障恢复后,消息才能被其他节点消费。
镜像模式
镜像模式是在普通模式的基础上,把需要的队列做成镜像队列,存在于多个节点来实现高可用(HA)。因为该模式会主动地将镜像队列的消息实体在各镜像节点间进行同步,即将镜像队列的队列内容同步到各个镜像节点上,所以在消费者拉取数据时不需要需临时拉取。此处注意,如果队列不是镜像队列,则其队列内容不会被同步到各个节点上。
但是该模式除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被大量消耗。通常地,对可靠性要求较高的场景建议采用镜像模式。
RabbitMQ集群搭建
我这里搭建了一个只有两台机器的RabbitMQ集群,仅作为演示
1、先在两台机器上安装好RabbitMQ(前边的文章已经讲过啦)
2、修改两台机器的.erlang.cookie为一样
如果不晓得你的.erlang.cookie在哪的话,可以
选择A机器的.erlang.cookie,然后将B机器的.erlang.cookie修改为A机器的.erlang.cookie的值(注意把改之前把B机器的erlang.cookie值记下来,万一以后有用嘞)
A机器的.erlang.cookie
B机器的.erlang.cookie
3、修改两台机器的/etc/hosts
RabbitMQ节点使用域名相互寻址,因此所有集群成员的主机名必须能够从所有集群节点解析,可以修改hosts文件或者使用DNS解析
在A和B的hosts里添加
A机器公网ip A机器名
B机器公网ip B机器名
A机器
B机器
这里要注意一下,注意机器名不能带“.”和“-”,在A,B机器上确认都能ping通两个ip,有时候会因为防火墙等问题而导致ping不通(什么?你问我怎么知道的?你说嘞!!!╭(╯^╰)╮)
4、完成了上面的步骤后,我们在两台机器上启动RabbitMQ,并安装web管理插件
rabbitmq-server start & 启动RabbitMQ
rabbitmqctl start_app 启动应用
rabbitmq-plugins enable rabbitmq_management 启用管理插件
然后在每台机器上执行以下命令
rabbitmqctl cluster_status 查看集群状态
A机器
B机器
/*******集群中的节点,disc表示为磁盘模式,ram表示为内存模式**************/
[{nodes,[{disc,[rabbit@VM_0_15_centos]}]},
/**************正在运行的集群节点*****************/
{running_nodes,[rabbit@VM_0_15_centos]},
/**************集群名称*********/
{cluster_name,<<“rabbit@VM_0_15_centos”>>},
{partitions,[]},
{alarms,[{rabbit@VM_0_15_centos,[]}]}]
其实,每一个RabbitMQ都是一个集群,只是这个集群只有一个磁盘节点Σ(⊙▽⊙”a
5、把A机器加入到B机器的集群里
在A机器上执行以下命令
rabbitmqctl stop_app 停止应用
rabbitmqctl join_cluster rabbit@VM_0_15_centos –ram 将本节点作为内存节点加入集群,不加“–ram”参数默认为磁盘节点
此时,在B机器上执行命令
rabbitmqctl cluster_status 查看集群状态
或者登陆B机器的web管理后台
可以发现A机器已经作为内存节点加入到了集群之中,但是该节点还没有运行
在A机器上启动该节点,执行命令
rabbitmqctl start_app 启动应用
rabbitmqctl cluster_status 查看集群状态
可以发现该节点已被启动,此时去B机器上查看集群状态,或是去A、B的web管理后台页面均可查看集群状态,此处不再加图片说明了
此时一个普通模式的RabbitMQ集群已经搭建成功了,然后我们可以试着在A(B)机器上用命令或在web管理后台添加删除交换机,队列,虚拟主机等操作,然后在两台机器上用命令或在web管理后台中查看对应的状态,发现两者保持一致。
我们还可以试着杀掉B机器的RabbitMQ的进程,即模拟磁盘节点挂掉的情况,然后在A机器中进行添加队列等操作,正常停掉A集群的RabbitMQ,启动磁盘节点,即B机器的RabbitMQ的服务,再启动内存节点即A节点的RabbitMQ的服务,再去web管理后台或者用命令查看你刚刚添加的东西,会发现都不存在了。这是因为内存节点的元数据存在内存中,磁盘节点的元数据存放在磁盘上,磁盘节点挂掉后,内存节点新加的元数据存放在内存节点的内存中,当把内存节点停止之后,启动磁盘节点,再启动内存节点时,内存节点会从磁盘节点拉取元数据,但是磁盘节点没有这些新加的元数据,所以新加的东西就不存在了
我们还可以试试停下A机器与B机器,然后启动A机器(内存节点),会发现报错,因为内存节点启动的时候会从磁盘节点同步数据,如果磁盘节点不启动,则内存节点会一直启动失败。故关闭集群时最好最后一个关闭磁盘节点,以防止配置丢失,除此之外任何对集群的操作都要有磁盘节点在线,磁盘节点可以有多个,但是至少有一个。
图就不截了,有点多,叙述不清之处欢迎与我讨论
以下是一些集群的操作命令
从集群中删除节点
rabbitmqctl stop_app
rabbitmqctl reset //将节点从集群中删除,即重新配置节点的集群信息
rabbitmqctl start_app
更改节点属性
rabbitmqctl stop_app
rabbitmqctl change_cluster_node_type disc/ram 更改节点为磁盘或内存节点
rabbitmqctl start_app
注意,在对集群节点操作的时候,第一个命令和最后一个命令一定是以下这两个命令
rabbitmqctl stop_app
rabbitmqctl start_app
6、镜像集群
上面已经完成RabbitMQ默认集群模式,但并不保证队列的高可用性,尽管交换机、绑定这些可以复制到集群里的任何一个节点,但是队列内容不会复制。虽然该模式解决一项目组节点压力,但队列节点宕机直接导致该队列无法应用,只能等待重启。所以要想在队列节点宕机或故障也能正常应用,就要复制队列内容到集群里的每个节点,必须要创建镜像队列。
在镜像队列模式下,如果集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点以保证服务的可用性。每一个镜像队列都包含一个master和多个slave,分别对应于不同的节点,注意一个节点既能是A队列master,又可以是B队列的slave,并非一个节点上的队列全是master。slave会准确地按照master执行命令的顺序进行命令执行,故slave与master上维护的状态应该是相同的。除了publish外所有动作都只会向master发送,然后由master将命令执行的结果广播给slave们,故看似从镜像队列中的消费操作实际上是在master上执行的。publish到镜像队列的所有消息总是被直接publish到master和所有的slave之上,这样一旦master失效了,message仍然可以继续发送到其他slave上,因此为了消息的可靠性,当master挂掉之后,最老的slave则提升为master。
镜像队列的工作原理:为队列建立一主多从,生产者发送消息时,消息会同时发送到master和所有的slave中,当消息者消费某一消息成功时,仅会通知master,然后由master通知其它的slave该消息被消费,删除该消息。但是若ack消息在消费者在发送到master后,slave收到master发送的ack消息前,master挂掉了,那么salve当选为新master时,,仍然会将该消息当做unack的消息放入队列,会造成重复消息。
那么,如何设置镜像队列呢?相信在座的各位大多都已经晓得了,对,没错,通过策略设置
我们接下来了解一些策略
设置策略的命令
rabbitmqctl set_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>
p 可选参数,针对指定 vhost 下的exchange或 queue
priority 可选参数,policy 的优先级
apply-to 可选参数,策略适用的对象类型,其值可为 “queues”, “exchanges” 或 “all”.默认是”all”
name policy 的名称
pattern 匹配模式(正则表达式)
definition 镜像定义,json 格式,包括三部分(ha-mode,ha-params,ha-sync-mode)
ha-mode |
ha-params |
结果 |
---|---|---|
all | 所有node都要复制queue,并且当集群中添加一个新的node的时候,queue也会复制过去 | |
extactly | count | queue只会同步到ha-params中指定的count个node上,如果集群中的node个数小于count,queue将会同步到整个集群中,如果集群中的node个数大于count,当一个node包含一个mirror queue并且down的时候,一个新的mirror将会被创建 |
nodes | nodes names | 消息被同步到制定的节点上 |
以下是一些例子
所有以ha.开头的队列并镜像到集群中的所有其他队列中
rabbitmqctl set_policy ha-all “^ha.” ‘{“ha-mode”:”all”}’
所有以two.开头的队列并镜像到集群中任意两个node上
rabbitmqctl set_policy ha-two “^two.” ‘{“ha-mode”:”exactly”,”ha-params”:2,”ha-sync-mode”:”automatic”}’
所有以node.开头的队列并镜像到集群中指明名字的两个node上
rabbitmqctl set_policy ha-nodes “^nodes.” ‘{“ha-mode”:”nodes”,”ha-params”:[“rabbit@nodeA”, “rabbit@nodeB”]}
除此之外,还可以在web管理后台添加策略,符合策略匹配规则的队列会成为镜像队列,同步到其它节点(注意,镜像队列可手动同步,也可自动同步,自己可以设置)
本篇当初完成了大半,今天补了一些,所以实例较少,如有兴趣的小伙伴可以去网上搜搜更多的资料
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197365.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...