RabbitMQ内建集群机制,利用Erlang提供的开放电信平台(OTP,Open telecom Platform)通信框架,使得集群很容易进行横向扩展,提高系统吞吐量。这里只讨论集群的概念、原理,关于如何创建集群见官方介绍: http://www.rabbitmq.com/clustering.html

内存节点和磁盘节点

RabbitMQ将队列、exchange、绑定、vhost的配置信息(也就是创建时提供的信息)称为元数据(集群状态时,集群节点地址、节点与其它元数据的关系也是元数据),简单理解--除掉MQ中消息内容本身,其它的都是元数据。在作为单独节点运行时,RabbitMQ将所有的元数据保存在内存中,将标记为可持久化的队列,exchange(和相应的绑定)保存到磁盘。作为集群时,这些元数据可能仅仅在内存中(称为内存节点RAM node),或同时保存在硬盘中(称为磁盘节点disk node),每个集群最少有一个磁盘节点,可有0个或多个内存节点。单一节点的RabbitMQ必须是一个磁盘节点。问题:磁盘节点会保存非持久化队列的信息到磁盘吗?内存节点会保存持久化的消息到磁盘吗?都会。

Metadata writes in RAM and disk nodes.

磁盘节点保证集群重启的时候可以重建持久化的Exchange,Queue等信息,所有这些信息的更新都必须先通过磁盘节点保存。所以磁盘节点太多影响性能,磁盘节点太少不安全。这里的性能指的是创建Exchange,queue的性能,一般我们不需要经常创建、更新这些信息,使用磁盘节点不会有性能影响,但对于RPC之类的应用场景,需要频繁的创建和删除queue,便需要考虑性能问题了。

如果集群中的磁盘节点都崩溃的话,集群可以继续进行路由工作,但是不能进行元数据改动的操作,例如创建Exchange、queue,添加删除节点。

添加删除节点。节点加入或离开集群至少要通知一个磁盘节点,正常的情况是需要全部的磁盘节点在线,并更新全部磁盘节点(如果有多个磁盘节点,只通知了其中的一个,集群会出问题)。内存节点重启时会连接一个硬盘节点,获得集群元数据拷贝(内存节点唯一存储到磁盘的元数据是磁盘节点的地址)。

队列和Exchange在集群中的工作方式

队列只会在集群的一个节点上创建,也就是说队列的消息只会出现在一个节点(发送者和消费者都有可能连接到集群的其它节点,但它们都必须通过创建队列的节点首发消息),当然集群中的所有节点都知道到哪能找到这个队列。当队列所在的这个节点崩溃的时候,这个队列便从集群中消失了,附加在队列上的消费者会丢失订阅(收到异常),发送者的消息自然也无法发送到这个队列,也就是消息丢失了。这时候需要重建队列(捕获异常,重建),但是如果队列是持久化的,无法重建队列,只能等待故障节点恢复。队列只在一个节点创建的策略是出于性能的考虑,这样数据没有冗余,可以提高节点吞吐量,方便横向扩展。

Queue behavior in standalone and cluster configurations

Exchange会在集群的全部节点上创建,因为Exchange本质上是一个名称和绑定的列表(可以理解为一张查询表),在集群每个节点都保留一份并不会有性能开销。每次创建Exchange的时候,这个信息会发布到所有节点上。这样,在有节点崩溃的时候,连接在节点上的终端只需要连接到集群的其它节点,不需要重建Exchange,但是如果使用镜像队列的主备模式,不能保证exchange会恢复,所以,好习惯是终端每次连接RabbitMQ时都创建exchange。

Exchange and queue distribution in a cluster.

镜像队列

为了实现高可用性(记得持久化队列所在节点崩溃的情况么),RabbitMQ从版本2.6.0开始,提供镜像队列功能。设置为镜像的队列会在集群的多个节点上创建,这样消息会有备份。一个主队列Master可以有多个从队列slave,一旦master不可用,最老的slave成为新的master。官方介绍:http://www.rabbitmq.com/ha.html

创建镜像队列

可以在客户端通过声明队列的时候设置参数x-ha-policy来创建镜像,例如下面将队列hello-queue镜像到所有节点。

queue_args = {"x-ha-policy" : "all"}

channel.queue_declare(queue="hello-queue", arguments=queue_args)

如果要指定作为slave的节点,可以像下面这样提供slave列表。

queue_args = {"x-ha-policy" : "nodes", "x-ha-policy-params" : [rabbit@testServer]}

channel.queue_declare(queue="hello-queue", arguments=queue_args)

也可以在服务器端通过设置Policy来配置,见连接 http://www.rabbitmq.com/ha.html#genesis 。一般采用服务端配置,实现简单,方便修改。

规则可以用来配置exchang和queue上的参数(关于Policy的解释: http://www.rabbitmq.com/parameters.html#policies ),类似于客户端创建exchange和queue提供的参数,但是并不完全一样。每个exchange或queue只能应用一个规则,如果有多个规则匹配,则使用优先级最高的规则。每个规则可以配置多个参数,例如federation-upstream-set和ha-mode,通过这两个参数可以控制federation(跨网同步插件)和mirror(镜像机制)。

问题:主节点是哪个?这取决于master选择的策略,通过参数x-queue-master-locator(规则queue_master_locator)可以设置策略。

  • Pick the node hosting the minimum number of masters: min-masters
  • Pick the node the client that declares the queue is connected to: client-local
  • Pick a random node: random

镜像队列和异常处理

信道将消息投递到master队列和所有的slave队列,类似于fanout模式的exchange将消息路由到所有绑定的队列。这样,在使用事务或发送方确认模式时,需要多个成功事务或发送方确认消息。

异常时消费者的处理方式。

  • 当slave队列所在的节点崩溃时,连接在这个节点上的消费者会丢失连接,重新连接到集群后可以重新附到master队列上;master队列所在节点上的消费者没有影响。
  • 当master队列所在的节点崩溃时,连接在主节点的消费者会丢失连接,从新连接到集群后可以附到新的master队列;连接在slave队列节点上的消费者会收到一个消费者取消通知,这时候需要重新连接集群,附到新的master队列上。但有的AMQP客户端不支持消费者取消通知的含义(支持的客户端会抛出异常),这时候消费者只会傻傻等待,以为队列是空的,而事实上队列已经慢慢被消息塞满了。
  • 主节点崩溃时尚未确认的消息会重新投递,因为新的主节点无法确认这些消息是确实消费者没有确认,还是由于主节点崩溃导致丢失了消费者的确认,为安全起见,会回到原位置(2.7.0版本之前会回到队列末尾)重新投递。

从故障中恢复

构建RabbitMQ集群来确保可用性和性能只是保障弹性消息通信基础架构的一半,另一半是编写当节点发生故障时知道如何重连到集群的应用程序。处理到集群的重连有多种策略,比如让程序知道所有的节点地址,出问题后可以尝试其他的节点;或者使用负载均衡,这样应用只需要知道负载均衡地址,而且可以比较均匀的将连接分布到各个节点。这里只讨论负载均衡工作方式。

负载均衡为一组服务器提供单一的访问地址,见网上介绍:https://zh.wikipedia.org/wiki/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1_(%E8%AE%A1%E7%AE%97%E6%9C%BA)

RabbitMQ集群使用负载均衡。客户端通过共同的地址(例如localhost:5670)连接到负载均衡设备(或者负载均衡软件),负载均衡负责将连接分配到集群的具体节点。

Load balancing a RabbitMQ cluster.

连接丢失和故障转移

当集群节点出现问题时,应用程序必须要做出决定:下一个该连向哪里?应用程序需要重新连接到集群,并且重建连接、channel,和exchange、queue,也就是每次重连的时候想象自己连接了一个全新的MQ。C#客户端会自动处理重连(参考连接:http://www.rabbitmq.com/dotnet-api-guide.html#connection-recovery),重连分为两个部分:Connection和Topology。connection部分负责网络连接的重建,topology负责exchange、queue、绑定的重建。

Automatic Recovery From Network Failures

Connection Recovery

RabbitMQ .NET/C# client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers). The automatic recovery process for many applications follows the following steps:

  1. Reconnect
  2. Restore connection listeners
  3. Re-open channels
  4. Restore channel listeners
  5. Restore channel basic.qos setting, publisher confirms and transaction settings

Topology recovery includes the following actions, performed for every channel

  1. Re-declare exchanges (except for predefined ones)
  2. Re-declare queues
  3. Recover all bindings
  4. Recover all consumers

To enable automatic connection recovery, set ConnectionFactory.AutomaticRecoveryEnabled to true:

ConnectionFactory factory = new ConnectionFactory();
factory.AutomaticRecoveryEnabled = true;
// connection that will recover automatically
IConnection conn = factory.CreateConnection();

If recovery fails due to an exception (e.g. RabbitMQ node is still not reachable), it will be retried after a fixed time interval (default is 5 seconds). The interval can be configured:

ConnectionFactory factory = new ConnectionFactory();
// attempt recovery every 10 seconds
factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(10);

Topology Recovery

Topology recovery involves recovery of exchanges, queues, bindings and consumers. It is enabled by default but can be disabled:

ConnectionFactory factory = new ConnectionFactory();

Connection conn = factory.CreateConnection();
factory.AutomaticRecoveryEnabled = true;
factory.TopologyRecoveryEnabled  = false;

Manual Acknowledgements and Automatic Recovery

When manual acknowledgements are used, it is possible that network connection to RabbitMQ node fails between message delivery and acknowledgement. After connection recovery, RabbitMQ will reset delivery tags on all channels. This means that basic.ack, basic.nack, and basic.reject with old delivery tags will cause a channel exception. To avoid this, RabbitMQ .NET client keeps track of and updates delivery tags to make them monotonically growing between recoveries. IModel.BasicAck, IModel.BasicNack, andIModel.BasicReject then translate adjusted delivery tags into those used by RabbitMQ. Acknowledgements with stale delivery tags will not be sent. Applications that use manual acknowledgements and automatic recovery must be capable of handling redeliveries.

Tip:如果消费者通过EventingBasicConsumer接收消息,使用connection自动重建不会恢复消息监听。

心跳

集群各个节点之间,RabbitMQ服务和客户端之间都需要监测TCP连接,以便网络断开时执行相关处理。操作系统可能需要花点时间才会发现连接出了问题,比如Linux默认需要约11分钟后才会检测到。AMQP 0-9-1提供心跳机制以便更快的检测网络情况,同时,心跳也能防止有些网络设备关掉“idle”的TCP连接。RabbitMQ实现了这个机制( http://www.rabbitmq.com/heartbeats.html )。

心跳超时时间

服务器和客户端连接的时候会协定一个心跳超时时间,如果超过这个时间还没有收到心跳,则认为连接断开。3.5.5之前心跳的默认超时时间是580s,之后是60s。心跳包的发送间隔是timeout/2,也就是丢失2个心跳包便会认为断开。将超时时间设为0表示禁用心跳。

var cf = new ConnectionFactory();

// set the heartbeat timeout to 60 seconds

cf.RequestedHeartbeat = 60;

RabbitMQ介绍5 - 集群的更多相关文章

  1. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

  2. RabbitMQ安装以及集群部署

    本次记录安装RabbitMQ的过程,只针对MAC下单机版安装.单机集群安装方法以及配置haproxy负载均衡. RabbitMQ单机版本安装 RabbitMQ单机集群安装方法(适合开发练习) Rabb ...

  3. RabbitMQ安装、集群搭建、概念解析

    RabbitMQ安装.集群搭建.概念解析 基本概念 为什么会产生MQ 1.解耦:采用异步方式实现业务需求达到解耦的目的. 2.缓冲流量,削峰填谷: 问:为什么会有流量冲击? 答:采用"直接调 ...

  4. 使用Kafka的一些简单介绍: 1集群 2原理 3 术语

    目录 第一节 Kafka 集群 Kafka 集群搭建 Kafka 集群快速搭建 第二节 集群管理工具 集群管理工具 集群 Issues 第三节 使用命令操纵集群 第四节 Kafka 术语说明 第五节 ...

  5. 超详细,多图文介绍redis集群方式并搭建redis伪集群

    超详细,多图文介绍redis集群方式并搭建redis伪集群 超多图文,对新手友好度极好.敲命令的过程中,难免会敲错,但为了截好一张合适的图,一旦出现一点问题,为了好的演示效果,就要从头开始敲.且看且珍 ...

  6. 【Hadoop离线基础总结】zookeeper的介绍以及集群环境搭建、网络编程和RPC的简单了解

    ZooKeeper的介绍以及集群环境搭建.网络编程和RPC的简单了解 ZooKeeper介绍 概述 ZooKeeper是一个分布式协调服务的开源框架,主要用来解决分布式集群中应用系统的一致性问题.例如 ...

  7. Centos 6.5 Rabbitmq 安装和集群,镜像部署

    centos 6.5 rabbitmq 安装和集群,镜像部署 安装erlang: yum install gcc glibc-devel make ncurses-devel openssl-deve ...

  8. RabbitMQ镜像队列集群搭建、与SpringBoot整合

    镜像模式 集群模式非常经典的就是Mirror镜像模式,保证100%数据不丢失,在实际工作中也是用的最多的,并且实现集群比较的简单. Mirror镜像队列,目的是为了保证 RabbitMQ 数据的高可靠 ...

  9. Linux源码安装RabbitMQ高可用集群

    1.环境说明 linux版本:CentOS Linux release 7.9.2009 erlang版本:erlang-24.0 rabbitmq版本:rabbitmq_server-3.9.13 ...

随机推荐

  1. 【转】SocketRocket:iOS WebSocket客户端开源框架

    原文网址:http://blog.csdn.net/zmp1123/article/details/44015507 WebSocket: WebSocket通信协议实现的是基于浏览器的原生socke ...

  2. Tutorial: Triplet Loss Layer Design for CNN

    Tutorial:  Triplet Loss Layer Design for CNN Xiao Wang  2016.05.02 Triplet Loss Layer could be a tri ...

  3. oracle_dblink配置

    说明:一下是未配置本地服务的dblink. 前提:   授权>  grant create public database link,create database link to myAcco ...

  4. easyui datagrid 添删改(纪录)

    var groups;//用户组为另一个表,所以需先加载,用于编辑时下拉框 var editindex = undefined; var action; $(function () { $.ajax( ...

  5. PHP快速排序及其时间复杂度

    <?php function quickSort(&$arr, $l, $r) { if (count($arr)<2 || $l>$r) return; $tmp_l = ...

  6. 基于window.onerror事件 建立前端错误日志

    QA不是万能的,用户的浏览环境非常复杂,很多情况无法靠测试用例去覆盖,所以最好建立一个前端错误日志,在真实用户端收集bug. try&catch是一个捕获前端错误的常见方法,比如: { //给 ...

  7. maxscript, 数组和字符串下标是从1开始的

    maxscript中数组和字符串下标是从1开始的.

  8. Python画图形界面

    使用QTdesigner 生成.ui文件,输入命令行pyuic4 -o test.py test.ui 在生成的Python文件后面输入下面代码 if __name__=="__main__ ...

  9. Ruby Exception

    begin #可能发生异常的地方 rescue #如何处理异常 end rescue,哈哈,太有爱的一个单词了... begin #可能发生异常的地方 rescue => exception # ...

  10. rpm包安装时发现缺少其他依赖

    多年来一直困扰我的问题,就是当我们下载了一个rpm包来安装的时候发现缺少依赖.以前的做法是网上挨个去搜索依赖的rpm,然后依次安装. # rpm -ivh google-chrome-stable_c ...