Rabbitmq集群和镜像队列

1引言

1.1编写目的

2 原理和使用

2.1镜像队列原理

2.1.1 原理

默认的一个rabbitmq中的queue是在一个node上的,至于在那个node上取决于client 进行declared的时候的顺序,于此不同的是rabbitmq中的exchange、bindings都是需要在全部的节点上存在的,也就是rabbitmq集群天生就是支持自动同步这些信息的。而queue则是可以通过mirrored 同步到多个节点上,至于到底是几个节点可以指定。

其实rabbitmq集群中的queue不是没有同步,是有同步的,只是他们同步的只是queue的定义部分或者说声明部分,并没有同步queue里面的msg,要想实现也同步queue里面的msg 就需要使用镜像队列了

每一个queue都会创建在一个master node或者
多个slaves node上
,并且当master 丢失的时候,最老的slaves node将会变成最新的master,当然这有一个前提那就是要求slave node必须已经同步了master node的内容,如果没有同步的话那么这个slave node是不可以成为master node的

2.1.2 rabbitmq的集群和镜像队列区别

rabbitmq的集群是根据erlang的同步机制来实现的,这是erlang自带的功能,十分强大,如果几个rabbitmq node进行了集群后,这些node 之前是可以同步 元数据的,包括exchange的元数据、队列的元数据、binding的元数据,当时需要注意的是不会包括同步queue的内容默认情况下。主要是因为如果同步的queue的内容的话,如果出现了queue很多的时候,并且每一个queue的内容都很大的时候,rabbitmq就仅仅需要忙着处理这些本node的queue还要负责处理和不同的node之前进行同步,这会造成系统很大负载,对rabbitmq的整体性能会有很多的影响,因此默认是关闭的。那么如果你非要进行队列的内容同步,比如你的队列吞吐量并不高,每一个队列的内容也不大,对性能不会造成什么影响,那么就可以打开镜像队列,这个时候集群之前就会同步queue的内容了。

镜像队列其实就是原来channel只会按照binding来把消息路由给某个队列,现在如果你使用了镜像队列,那么channel就需要并行的把消息路由给master node 同时还需要把消息同步给slave node上,所以当使用镜像队列以后性能是一定会下降的

另外说下rabbitmq的集群node中必须有一个要配置为磁盘类型,这个是防止数据丢失的,另外如果整个集群都停掉了那么应该要保证最后一个down掉的node首先被启动,如果不可以则要使用forget_cluster_node命令将最后关闭的那个node移出集群,如果集群中的节点几乎同时以不可控的方式down了,此时在其中一个节点使用force_boot命令重启节点

另个rabbitmq集群重用的命令:reset 可以把一个node从一个集群中移出,forget_cluster_node则是可以在另一个节点上把某一个node移出自己的集群

2.1.4 queue的master和slave node

每一个queue都有一个home node也叫主队列。所有的镜像操作首先必须要通过这个master,然后在复制到其他的mirrors上,这样做主要是为了保证消息的FIFO顺序,也就是说所有顺序执行的操作都要顺序交给master,然后channel在同步给slave node,如果master上移出了队列中的内容,那么所有的slave node也同步的移出所有的队列内容。但是要记住consumer消费的只是 master node,并不是slave node

可以通过如下的策略来决定 queue master 在那个节点上:

  • 选择存在主队列 最少的的节点: min-masters
  • 选择client 声明queue 连接的节点:client-local
  • 随机选择:random

以上策略的配置可以通过如下几个方法:

  • 在创建queue的时候使用x-queue-master-locator来指明用上面的那个策略
  • 在配置文件中使用配置项 queue_master_locator指明使用上面的某个策略

2.1.3 镜像队列的配置使用

早期的rabbitmq版本要想配置队列使用使用mirror queue,必须要consumer创建队列的时候,使用参数来指明。这种方法的不好之处在于不能从rabbitmq server端统一进行配置管理。后来进行了改进,rabbitmq通过policy来激活镜像队列,policy可以在任何时候进行修改,并且修改后立即生效,比如你可以在任何时候把一个非镜像队列通过policy修改成一个镜像队列,反这亦然。另外当一个镜像队列只有一个master 没有slaves的时候,他和非镜像队列也是不一样的,虽然看起来是一样的,相比较而言非镜像队列的性能要好很多

下面说下镜像队列的通过policy方法进行配置的方法

为了让一个queue或者对个queue变成mirror queue 必须要产生一个policy,这个policy会使用表达式语法和队列的名字进行匹配,并且会使用policy的key:ha-mode 和可选的ha-params 决定怎么同步queue

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

node names

消息被mirror到指定的node上通过指定node name,node name是erlang node name 可以通过 rabbitmqctl cluster_status 查看,一般的形式是rabbit@hostname

不管什么时候发生了镜像队列的 policy 变化,rabbitmq都会尽力保持现有的mirror 但是同时要和新的policy要尽量符合

下面是几个例子:

  • 所有以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"}'
  • 所有以test.开头的队列并镜像到集群中指明名字的两个node上
rabbitmqctl set_policy ha-nodes "^nodes\." \
   '{"ha-mode":"nodes","ha-params":["rabbit@nodeA", "rabbit@nodeB"]}

2.1.5 nodes policy 对queue master的影响

如果在改变镜像队列的 policy的时候 选择了 nodes 类型的policy 这个有可能会造成

原来存在的queue master 消失,如果这个queue master 所在的node 不在 nodes list内。为了阻止queue master的丢失,rabbitmq将会保持queue master 存在直到slaves开始同步。不过一旦同步开始,那么rabbitmq 就不会继续保证这个 queue master 还需要保持了,这个时候consumer就会失去和queue master的连接,然后需要重新连接。所以这就是说一旦queue master down,那么consumer就一定会出现一次reconnection,只是在reconnection之前你有没有包装数据的同步

例如 如果一个queue is on [A,B] 其中 node A上是 queue master ,此时如果你创建了一个policy 类型的 nodes 告诉 rabbitmq 消息需要在node [C,D] 那么在初始阶段 queue是在[A,C,D]三个node上,但是一旦同步那么就queue就会在[C,D]上,master A queue 将会被关闭.所以是要手动同步还是要自动同步,也需要我们仔细考虑

2.1.6 排他性队列(exclusive queues)

排他性队列是一种和connection生命周期关联的队列,一旦connection关闭那么排他性队列就会被删除,可以想想下如果一个node crash了 那么和这个node 建立的connection都会被关闭所以排他性队列也会被删除,因此这样的队列不应该被mirror

2.2镜像队列使用

2.2.1 新节点同步机制

如果集群中新加了一个node,那么这个node就会变成备复制节点,而且备复制节点不会主动的复制master node 上的queue的内容,当然了他是会同步master node上的queue的元数据的,那么怎么实现和master node上的queue内容同步呢,这就需要随着时间的推移一点一点的来同步了,也就是说新加的节点只会同步后来加入到master node上的队列内容并且随着master node上的queue里面的内容被不断的消费掉,很快备份节点和master node上面的内容就会一样了。

但是考虑到万一consumer正好发布消息到了新的node上,并且master node 又挂了会怎么样呢,答案是会丢失消息。因此在master node 将现存的queue的内容复制到其他的新节点之前,分辨是否所有从copy和master node拥有相同的内容就很重要了。为了检测镜像队列同步的状态,可以使用如下的命令来确定:

rabbitmqctl list_queues pid slave_pids synchronised_slave_pids

这个命令会显示出 slave-pids 和synchronised_slave_pids

如果两个是一样的时候就表示所有的队列内容同步完成了否则就是还没有同步完成

这个时候master node是一定不可以删除的

2.2.2 停止所有node后slave删除队列内容

当所有node停止后再重启,如果之前有声明为持久化的队列,那么master node上会继续保留有之前queue的全部信息和内容,但是slave node只会同步到queue的元数据,并不会同步到queue的内容,主要是slave node 重启后并不知道自己原来保留的queue的内容是否和master node上的queue的内容一致,所以干脆就删除全部的消息内容,感觉就相当于一个新的node刚刚加入一个集群一样

2.2.3 停止只有未同步的slave的master node

集群中可能会出现所有的slave node都未同步完成的时候,master被关闭了,虽然这种情况出现的可能性不会太大,但是是有这个可能的。这个关闭可能是下面两个情况:

有意的或者说可控的关闭了master node,比如有意的停止rabbitmq或者关闭了服务器,这个时候为了避免消息丢失,rabbitmq不会同步fail over 到其他的还未同步完成的slave上,相反的整个queue将会被stop掉,给人的感觉就好像是slave node根本不存在一样

无意的不是人为的,而是由于rabbitmq crash了或者突然掉电了,这个是会出发master node 自动 fail over 到未同步完成的slave node上

如果实在是想即使slave node没同步,mater node关闭后也要fail over到slave node上那么可以使用rabbitmq的policy:设置policy中的ha-promote-on-shutdown的默认值when-synced改为always

2.2.4 所有slave 关闭时候 master 异常关闭

这种情况更少见,主要是slave 都处于关闭状态时候,master node 不知道什么原因不在集群中了,一般情况下,slave都关闭了,master丢失的时候,根据上一个场景"停止只有未同步的slave的master node" 我们可以知道这个时候slave如果没有同步就被关闭了那么master消失后,queue也没有了master。但是如果我们执行 forget_cluster_node 移出master的时候,rabbitmq会试图为master node上每一个队列找到一个当前被stop的slave node,并在这个slave node重启后被提升为master,如果有多个slave node可以选择,那么最近关闭的slave node会被选中

这个需要理解为什么我们只能选择stop的slave node,而不是运行的slave node呢?答案其实在场景"停止所有node后消息同步"中说的一样,一旦关闭了slave node重启后就会自动删除所有的本地queue的内容了

rabbitmq集群和镜像队列的更多相关文章

  1. RabbitMQ集群、镜像部署配置

    1   RABBITMQ简介及安装 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.Act ...

  2. RabbitMQ 集群之镜像同步

    mirrored 在上个博文中讲到了如果做集群,那么集群是成功了,但是queue是如何存放的呢?消息又是怎么同步呢. 默认的,也就是什么也不配置,直接在某个节点中添加一个queue,那么它仅仅是属于这 ...

  3. Centos6.9下RabbitMQ集群部署记录

    之前简单介绍了CentOS下单机部署RabbltMQ环境的操作记录,下面详细说下RabbitMQ集群知识,RabbitMQ是用erlang开发的,集群非常方便,因为erlang天生就是一门分布式语言, ...

  4. RabbitMQ学习笔记(五、RabbitMQ集群)

    目录: RabbitMQ集群 镜像队列 RabbitMQ服务日志 RabbitMQ分布式部署 高可用集群 RabbitMQ集群: 1.集群中组件的状态 首先MQ一定要是一个高可用的中间件所以集群肯定是 ...

  5. RabbitMQ集群部署、高可用和持久化

    RabbitMQ 安装和使用 1.安装依赖环境 在 http://www.rabbitmq.com/which-erlang.html 页面查看安装rabbitmq需要安装erlang对应的版本 在 ...

  6. RabbitMQ集群架构(HA)并结合.NET Core实操

    一.前言 已经一年没有更新博客了,由于公司事务比较多,并且楼主我也积极在公司项目中不断实践.net core.DDD以及Abp vnext,也积累了一些吐血经验,目前我在做一家在线教育公司负责智慧校园 ...

  7. 消息中间件-RabbitMQ集群和高可用

    多机多节点集群部署 一. 环境准备 准备三台安装好RabbitMQ 的机器,安装方法见 安装步骤 10.10.1.41 10.10.1.42 10.10.1.43 提示:如果使用虚拟机,可以在一台VM ...

  8. rabbitmq集群搭建方法简介(测试机linux centos)【转】

    本文将介绍四台机器搭建rabbitmq集群: rabbitmq IP和主机名(每台机器已安装RabbitMQ 3.5.6, Erlang 18.1) 192.168.87.73 localhost73 ...

  9. rabbitmq集群搭建,镜像队列搭建

    原文地址:https://www.jianshu.com/p/11963564dd3d 教你如何从0开始搭建rabbitmq集群 一.准备工作 1.三台centos虚拟机 2.三台虚拟机都安装了doc ...

随机推荐

  1. 全网最详细的ReentrantReadWriteLock源码剖析(万字长文)

    碎碎念) 花了两天时间,终于把ReentrantReadWriteLock(读写锁)解析做完了.之前钻研过AQS(AbstractQueuedSynchronizer)的源码,弄懂读写锁也没有想象中那 ...

  2. 重学Git(一)

    一.最最最基础操作 # 初始化仓库 git init # 添加文件到暂存区 git add readme.md # 提交 git commit -m 'wrote a readme file' 二.简 ...

  3. Hive(四)【DML 数据导入导出】

    目录 一.数据导入 1.1 [load]--向数据中装载数据 案例 1.2 [insert]--查询语句向表中插入数据 案例 1.3 [as select]--查询语句中创建表且加载数据 案例 1.4 ...

  4. spring注解-自动装配

    Spring利用依赖注入(DI)完成对IOC容器中中各个组件的依赖关系赋值 一.@Autowired 默认优先按照类型去容器中找对应的组件(applicationContext.getBean(Boo ...

  5. 【Java 设计】如何优雅避免空指针调用

    空指针引入 为了避免空指针调用,我们经常会看到这样的语句 if (someobject != null) { someobject.doCalc();} 最终,项目中会存在大量判空代码,多么丑陋繁冗! ...

  6. 加密解密、食谱、新冠序列,各种有趣的开源项目Github上都有

    Github上是我们程序员学习开源代码.提升编程技巧的好地方.好学校,但是除了学习,小伙伴们有没有发现过Github上一些特别有意思的项目呢? 今天TJ君就来和大家分享几个自认为特别有趣的开源项目: ...

  7. 从一次解决Nancy参数绑定“bug”开始发布自己的第一个nuget包(上篇)

    起因 最近,同事跟我说,他们负责的一个Api程序出现了一些很奇怪的事情.这个Api是为环保局做的一个扬尘质控大屏提供数据的,底层是基于Nancy做的.因为发现有些接口的数据出现异常,他就去调试了一下, ...

  8. 在Eclipse中编写jQuery代码时产生的错误(连载)

    1.Error:启动Eclipse中的服务,显示错误,端口号被占用 解决方法: 方式一:修改对应的端口号(实际情况实际处理) 方式二:在进程中关闭Eclispe重新打开即可(截图说明) 2.Error ...

  9. Java中的对于多态的理解

    一.什么是多态 面向对象的三大特性:封装.继承.多态 多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行为方式.(发送消息就是函数调用) 实现多态的技 ...

  10. Redis的一致性哈希算法

    一.节点取余 根据redis的键或者ID,再根据节点数量进行取余. key:value如下 name:1 zhangsna:18:北京 对name:1 进行hash操作,得出来得值是242342345 ...