RabbitMQ镜像队列实现原理

一、镜像队列使用

1.镜像队列作用

​ RabbitMQ默认集群模式,并不包管队列的高可用性,尽管队列信息,交换机、绑定这些可以复制到集群里的任何一个节点,然则队列内容不会复制,固然该模式解决一项目组节点压力,但队列节点宕机直接导致该队列无法应用,只能守候重启,所以要想在队列节点宕机或故障也能正常应用,就要复制队列内容到集群里的每个节点,须要创建镜像队列。

2.策略设置

镜像队列设置可以基于策略设置,策略设置可以通过如下两种方法:

(1)RabbitMQ 管理后台

(2)rabbitmqctl 设置

policy 添加命令:

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)具体配置见下表

definition参数详情

参数名称 描述
ha-mode 指名镜像队列模式,其值可为”all”,”exactly”或”nodes”,all:表示在集群所有节点上进行镜像;exactly:表示在指定个数的节点上镜像,节点个数由 ha-params 指定;nodes:表示在指定节点上进行镜像,节点名称通过ha-params 指定。
ha-params ha-mode模式需要用到的参数:exactly 模式下为数字表述镜像节点数,nodes 模式下为节点列表表示需要镜像的节点。
ha-sync-mode 镜像队列中消息的同步方式,其值可为”automatic”或”manually”.

例如:对队列名称为 hello 开头的所有队列镜像镜像,并且在集群的节点 rabbit@10.18.195.57上进行镜像,队列消息自动同步,policy 的设置命令:

rabbitmqctl set_policy --apply-to queues hello-ha "^hello" '{
  "ha-mode":"nodes","ha-params":["rabbit@10.18.195.57"],"ha-sync-mode":"automatic"}'
3.ha 策略确认

镜像队列策略是否生效可以通过如下两种方式验证:

(1)RabbitMQ 管理后台

可以通过策略管理验证策略是否配置正确

通过队列列表也可以查看队列应用的策略,如果是镜像策略,可以看到当前队列副本数

通过队列详情可以查看镜像队列当前主副本在哪个节点,从副本在哪几个节点

(2)rabbitmqctl 查看

查看策略详情指令:

rabbitmqctl list_policies

返回:

查看队列是否镜像指令:

rabbitmqctl list_queues name pid slave_pids

返回:

二、镜像队列实现原理

1.整体介绍

​ 通常队列由两部分组成:一部分是 amqqueue_process, 负责协议相关的消息处理,即接收生产者发布的消息,向消费者投递消息,处理消息 confirm,ack 等等;另外一部分是 backing_queue, 作为消息存储的具体形式和引擎,提供了相关接口供进程amqqueue_process调用,用来完成消息的存储及可能的持久化工作等。

​ 镜像队列和普通队列组成有所不同,镜像队列存在两类进程:master队列进程为 amqqueue_process,slave 队列进程为 rabbit_mirror_queue_slave,每个进程会创建一个 gm(guaranteed multicast)进程,镜像队列中所有 gm 进程会组成一个进程组用于广播和接收消息。同时和普通队列一样,每个进程都包含一个用于处理消息逻辑的队列 backing_queue(默认为rabbit_variable_queue)。集群中每个有客户端连接的节点都会启动若干个channel进程,channel进程中记录着镜像队列中master和所有slave进程的Pid,以便直接与队列进程通信。整体结构如下:

​ gm 负责消息广播,至于广播消息处理,master 队列上回掉处理是通过coordinator,消息相关协议操作是通过amqqueue_process处理,而 slave 队列都是由rabbit_mirror_queue_slave进行处理。

注意:消息的发布和消费都是通过 master 队列完成,master 队列对消息进行处理同时将消息的处理动作通过 gm 广播给所有 slave 队列,slave 的 gm 收到消息后,通过回调交由 rabbit_mirror_queue_slave 进行实际处理。

2.gm(Guaranteed Muticast)

​ 镜像队列 gm 组通过将所有 gm 进程形成一个循环链表,每个 gm 都会监控位于自己左右两边的 gm,当有 gm 新增时,相邻的 gm 保证当前广播的消息会通知到新的 gm 上;当有 gm 失效时,相邻的 gm 会接管保证本次广播消息会通知到所有 gm。

​ gm 组信息会记录在本地数据库(mnesia)中,不同的镜像队列行程的 gm 组也是不同的。

​ 消息从 master 队列对应的 gm 发出后,顺着链表依次传送到所有 gm 进程,由于所有 gm 进程组成一个循环链表,master 队列的 gm 线程最终会收到自己发送的消息,这个时候 master 队列就知道消息已经复制到所有 slave 队列了。

3.重要的数据结构

queue 队列相关信息

-record(q, 
        { q,                    %% 队列信息数据结构amqqueue
          exclusive_consumer,   %% 当前队列的独有消费者
          has_had_consumers,    %% 当前队列中是否有消费者的标识
          backing_queue,        %% backing_queue对应的模块名字
          backing_queue_state,  %% backing_queue对应的状态结构
          consumers,            %% 消费者存储的优先级队列
          expires,              %% 当前队列未使用就删除自己的时间
          sync_timer_ref,       %% 同步confirm的定时器,当前队列大部分接收一次消息就要确保当前定时器的存在(200ms的定时器)
          rate_timer_ref,       %% 队列中消息进入和出去的速率定时器
          expiry_timer_ref,     %% 队列中未使用就删除自己的定时器
          stats_timer,          %% 向rabbit_event发布信息的数据结构状态字段
          msg_id_to_channel,    %% 当前队列进程中等待confirm的消息gb_trees结构,里面的结构是Key:MsgId Value:{SenderPid, MsgSeqNo}
          ttl,                  %% 队列中设置的消息存在的时间
          ttl_timer_ref,        %% 队列中消息存在的定时器
          ttl_timer_expiry,     %% 当前队列头部消息的过期时间点
          senders,              %% 向当前队列发送消息的rabbit_channel进程列表
          dlx,                  %% 死亡消息要发送的exchange交换机(通过队列声明的参数或者policy接口来设置)
          dlx_routing_key,      %% 死亡消息要发送的路由规则(通过队列声明的参数或者policy接口来设置)
          max_length,           %% 当前队列中消息的最大上限(通过队列声明的参数或者policy接口来设置)
          max_bytes,            %% 队列中消息内容占的最大空间
          args_policy_version,  %% 当前队列中参数设置对应的版本号,每设置一次都会将版本号加一
          status                %% 当前队列的状态
        }).

state 记录 gm 进程状态

-record(state,
        { self,                 %% gm本身的ID
          left,                 %% 该节点左边的节点
          right,                %% 该节点右边的节点
          group_name,           %% group名称与队列名一致
          module,               %% 回调模块rabbit_mirror_queue_slave或者rabbit_mirror_queue_coordinator
          view,                 %% group成员列表视图信息,记录了成员的ID及每个成员的左右邻居节点(组装成一个循环列表)
          pub_count,            %% 当前已发布的消息计数
          members_state,        %% group成员状态列表 记录了广播状态:[#member{}]
          callback_args,        %% 回调函数的参数信息,rabbit_mirror_queue_slave/rabbit_mirror_queue_coordinator进程PID
          confirms,             %% confirm列表
          broadcast_buffer,     %% 缓存待广播的消息
          broadcast_buffer_sz,  %% 当前缓存带广播中消息实体总的大小
          broadcast_timer,      %% 广播消息定时器
          txn_executor          %% 操作Mnesia数据库的操作函数
        }).

gm_group 整个镜像队列群组的信息,该信息会存储到Mnesia数据库

-record(gm_group, 
        { name,    %% group的名称,与queue的名称一致
          version, %% group的版本号, 新增节点/节点失效时会递增
          members  %% group的成员列表, 按照节点组成的链表顺序进行排序
        }).

view_member 镜像队列群组视图成员数据结构

-record(view_member, 
        { id,       %% 单个镜像队列(结构是{版本号,该镜像队列的Pid})
          aliases,  %% 记录id对应的左侧死亡的GM进程列表
          left,     %% 当前镜像队列左边的镜像队列(结构是{版本号,该镜像队列的Pid})
          right     <
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值