Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5764023
  • 博文数量: 291
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7924
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-06 14:28
个人简介

阿里巴巴是个快乐的青年

文章分类

全部博文(291)

文章存档

2018年(21)

2017年(4)

2016年(5)

2015年(17)

2014年(68)

2013年(174)

2012年(2)

分类: 云计算

2013-02-16 22:53:02

一、高可用队列

如果RabbitMQ broker由单节点组成,那么该节点失败将会导致停机、服务临时不可用和消息丢失(尤其是非持久化队列上的非持久化消息)。你可以发布所有消息到持久化队列,但即使这样也可能会丢失,因为在消息被发送或者被写入并刷新到磁盘也有一定的时间间隔。使用是一种确认客户端知道哪些消息已经写入磁盘的方式,但即使如此,你也不希望忍受停机,或者因节点失败而导致的服务不可用,或者因每条消息都写入磁盘而导致的性能下降。

你可以使用RabbitMQ节点来构造RabbitMQ broker。这样就能做到单点失效但整体服务可用,但是需要注意的是:exchangebind幸存下来,而queuemessage却悲剧了,因为queue和它的内容正好驻留在失效节点上,因此,失效节点将导致其queue不可用。

         可以使用active/passive节点对,这样当active节点失效时,passive节点就会被提升而取代失效节点。active/passive节点对也可以在集群中使用。这种方法能确保节点失败能被很快检测到并得以恢复,这也是passive节点需要花很长时间才能启动甚至启动失败的原因。最好的结果是临时不可用队列在失败节点上。

         为了解决这一系列问题,active/active高可用队列横空出世。通过将队列镜像到集群内其它节点来达到高可用。这样当集群内某个节点失败,队列会自动切换到镜像队列而继续工作。这种解决方案也需要RabbitMQ集群,这也就意味着不能解决分区容忍问题,因此,不推荐在广域网中使用。

 

二、镜像队列特性

         正常情况下,每个镜像队列中有一个master和多个slave,每个在不同节点上。slave运用操作同步master以维持相同的状态。master的所有操作除了publish外都会广播到slave。因此,客户端从镜像队列消费消息实际上是从master消费的。

         slave如果失败,除了统计外只有很少一部分工作要做:master依然是master,没有客户端需要任何操作或者知道slave失败了。

         如果master失败了,则其中一个slave必须被提升。此时,会发生如下情况:

         1)其中一个slave被提升为master。被提升的slave是最旧的slave。就其本身而言,最旧的slavemaster状态最一致。然而,需要注意的是message仅仅保持在master上,因此也将丢失。

         2slave认为所有之前的消费者都已经意外断开了。因此,其重新发布所有已经传递给客户端的消息,然后等待ack。这包括客户端已经回复ack的消息:要么ack在到达master之前丢失,要么丢失在master广播给slave时。无论哪种情况,新的master都没有选择余地,除了重新发布它认为没有收到ack的所有消息。

         3)客户端从镜像队列消费时支持扩展,客户端会收到通知告知它们从镜像队列的订阅已经意外被取消了。此时,它们需要重新从队列消费。发送这个通知是因为告知丢失master的客户端是必要的:否则客户端可能会继续发送过时消息的ack(失效的master),或者会看到同样的消息但是由新的master发送。当然,客户端连接到失效的节点并发现连接失败,则需要重连到集群内一个存活的节点。

         4)由于重新发布消息,客户端重新从队列消费,其需要意识到随后的消息之前已经收到过了。

         随着选择的slave变成master,没有消息发布到在这期间失效的镜像队列:消息发布到镜像队列是直接发布到master和所有slave。因此master失效,消息继续被发送到slave,包括被提升为masterslave

         相似地,客户端使用发布的消息将仍被正确确认,尽管在消息被发布到消息发布者收到确认之间master(或者任何slave)失效。因此从发布者的角度来看,发布到一个镜像队列不同于发布到任何其它类型的队列。消费者需要意识到其需要根据收到的来重新从镜像队列消费。

         如果从镜像度列(noAck=true)消费(也就是客户端不发送ack),则消息可能会丢失。这不同于标准:broker认为ack一发送给消费者(noACk=true),客户端就会突然断开连接,ack可能永远不会被收到。对于镜像队列,master可能死掉了,消息可能永远不会被那些客户端收到,并且消息不会被新的master重新发布。因为可能客户端连接到幸存节点,在这种事件发生时很有用。当然,在实践中,如果你关心不丢失消息,则建议你设置noAck=false

1、 发布者确认和事务

         镜像队列支持。从语义上来看,确认和事务在所有镜像队列上都生效。所以一个事务仅仅返回给所有镜像队列的一个客户端,同样地,确认只会被所有镜像队列的一个发布者收到。

 

三、不同步的slave

         一个节点可以在任何时候加入一个集群。当一个节点加入一个集群时,队列可能在新的节点上添加一个slave,这取决于队列的配置。此时,新的slave将是空的:其不包含任何队列的内容,目前没有同步协议。slave将收到发布给队列的新消息,消息将被添加到镜像队列的结尾。

         可以用rabbitmqctl或者管理插件来决定从哪个slave同步数据:

rabbitmqctl list_queues name slave_pids synchronised_slave_pids

 

四、启动和停止节点

         如果你停止包含镜像队列的RabbitMQ master节点,某个节点上的某个slave将会提升为master。如果你继续停止节点,将会出现镜像队列没有slave:其仅仅在一个节点上存在,该节点是其master。如果镜像队列声明为持久化的,则如果最后剩下的节点关机,队列中的持久化消息将会出现在重新启动的节点上。通常,你重启其它节点,如果其之前是镜像队列的一部分,则其会重新加入镜像队列。

         然而,当前没有方法能让slave知道它的队列是否已经从master分离而不得不重新加入(这种情况在网络分区中发生)。当slave重新加入镜像队列时,其扔掉任何已经持久化的本地内容而启动一个空的。它的行为如同一个新节点加入集群。

 

五、配置镜像

         队列通过来使能镜像。策略能在任何时刻改变;它有效创建一个非镜像队列,然后使它镜像到后面的节点(反之亦然)。非镜像队列和镜像队列之间是有区别的,前者缺乏额外的镜像基础设施,没有任何slave,因此会运行得更快。

         为了使队列称为镜像,你将会创建一个策略来匹配队列,设置策略key ha-mode ha-params(可选)。下面表格说明这些key的选项:

ha-mode

Ha-params

结果

all

(absent)

队列镜像到集群内所有节点。当新节点加入集群时,队列将被镜像到那个节点。

exactly

count

队列镜像到集群内指定数量的节点。如果集群内节点数少于此数,则队列镜像到集群内所有节点。如果集群内节点数多于此数,而且一个包含镜像的节点停止,则新的镜像将不会在另外一个节点上创建。(这阻止队列在集群内发生迁移。)

nodes

node names

队列镜像到指定节点。如果任何指定节点不在集群中,都不会产生错误。当队列声明时,如果没有任何指定节点在线,则队列会被创建在发起声明的客户端所连接的节点上。

                                        表1 key选项

         无论什么时候,队列的HA策略发生改变,它将尽力保持其已经存在的镜像直到其符合新的策略。

1、“nodes”策略和迁移master

         需要注意的是设置和修改一个“nodes”策略将不会引起已经存在的master离开,尽管你让其离开。比如:如果一个队列在{A},并且你给它一个节点策略告知它在{B C},它将会在{A B C}。如果节点A那时失败或者停机了,那个节点上的镜像将不回来且队列将继续保持在{B C}

2、一些例子

         队列名称以“ha.”开头的队列,其策略镜像到集群内所有节点:

rabbitmqctl

rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'

rabbitmqctl (Windows)

rabbitmqctl set_policy ha-all "^ha\." "{""ha-mode"":""all""}"

HTTP API

PUT /api/policies/%2f/ha-all {"pattern":"^ha\.", "definition":{"ha-mode":"all"}}

Web UI

·         Navigate to Admin > Policies > Add / update a policy.

·         Enter "ha-all" next to Name, "^ha\." next to Pattern, and "ha-mode" = "all" in the first line next to Policy.

·         Click Add policy.

         队列名称以“two.”开头的队列,其策略镜像到集群内任何两个节点:

rabbitmqctl

rabbitmqctl set_policy ha-two "^two\." \

   '{"ha-mode":"exactly","ha-params":2}'

rabbitmqctl (Windows)

rabbitmqctl set_policy ha-two "^two\." ^

   "{""ha-mode"":""exactly"",""ha-params"":2}"

HTTP API

PUT /api/policies/%2f/ha-two {"pattern":"^two\.", "definition":{"ha-mode":"exactly", "ha-params":2}}

Web UI

·         Navigate to Admin > Policies > Add / update a policy.

·         Enter "ha-two" next to Name and "^two\." next to Pattern.

·         Enter "ha-mode" = "exactly" in the first line next to Policy, then "ha-params" = 2 in the second line, and set the type on the second line to "Number".

·         Click Add policy.


阅读(11511) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

scq2099yt2013-02-16 22:57:05

文明上网,理性发言...