rabbitmq——镜像队列

转自:http://my.oschina.net/hncscwc/blog/186350?p=1

1. 镜像队列的设置

镜像队列的配置通过添加policy完成,policy添加的命令为:

rabbitmqctl  set_policy  [-p Vhost]  Name  Pattern  Definition  [Priority]

-p Vhost:  可选参数,针对指定vhost下的queue进行设置

Name:  policy的名称

Pattern:  queue的匹配模式(正则表达式)

Definition:  镜像定义,包括三个部分 ha-mode,ha-params,ha-sync-mode

                 ha-mode:  指明镜像队列的模式,有效值为 all/exactly/nodes

                                all表示在集群所有的节点上进行镜像

                                exactly表示在指定个数的节点上进行镜像,节点的个数由ha-params指定

                                nodes表示在指定的节点上进行镜像,节点名称通过ha-params指定

                 ha-params: ha-mode模式需要用到的参数

                 ha-sync-mode:  镜像队列中消息的同步方式,有效值为automatic,manually

Priority:  可选参数, policy的优先级

例如,对队列名称以hello开头的所有队列进行镜像,并在集群的两个节点上完成镜像,policy的设置命令为:

rabbitmqctl  set_policy  hello-ha  "^hello"  '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

2. 镜像队列的大概实现

(1) 整体介绍

通常队列由两部分组成:一部分是amqqueue_process,负责协议相关的消息处理,即接收生产者发布的消息、向消费者投递消息、处理消息confirm、acknowledge等等;另一部分是backing_queue,它提供了相关的接口供amqqueue_process调用,完成消息的存储以及可能的持久化工作等。

镜像队列同样由这两部分组成,amqqueue_process仍旧进行协议相关的消息处理,backing_queue则是由master节点和slave节点组成的一个特殊的backing_queue。master节点和slave节点都由一组进程组成,一个负责消息广播的gm,一个负责对gm收到的广播消息进行回调处理。在master节点上回调处理是coordinator,在slave节点上则是mirror_queue_slave。mirror_queue_slave中包含了普通的backing_queue进行消息的存储,master节点中backing_queue包含在mirror_queue_master中由amqqueue_process进行调用。

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

 

(2) gm(Guaranteed Multicast)

传统的主从复制方式:由master节点负责向所有slave节点发送需要复制的消息,在复制过程中,如果有slave节点出现异常,master节点需要作出相应的处理;如果是master节点本身出现问题,那么slave节点间可能会进行通信决定本次复制是否继续。当然为了处理各种异常情况,整个过程中的日志记录是免不了的。

然而rabbitmq中并没有采用这种方式,而是将所有的节点形成一个循环链表,每个节点都会监控位于自己左右两边的节点,当有节点新增时,相邻的节点保证当前广播的消息会复制到新的节点上;当有节点失效时,相邻的节点会接管保证本次广播的消息会复制到所有节点。

在master节点和slave节点上的这些gm形成一个group,group的信息会记录在mnesia中。不同的镜像队列形成不同的group。

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

(3) 重要的表结构

rabbit_queue表记录队列的相关信息:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-record(amqqueue,
{
name,             %%队列的名称
durable,          %%标识队列是否持久化
auto_delete,      %%标识队列是否自动删除
exclusive_owner,  %%标识是否独占模式
arguments,        %%队列创建时的参数
pid,              %%amqqueue_process进程PID
slave_pids,       %%mirror_queue_slave进程PID集合
sync_slave_pids,  %%已同步的slave进程PID集合
policy,           %%与队列有关的policy
                  %%通过set_policy设置,没有则为undefined
gm_pids,          %%{gm,mirror_queue_coordinator},{gm,mirror_queue_slave}进程PID集合
decorator         %%
}).

注意:slave_pids的存储是按照slave加入的时间来排序的,以便master节点失效时,提升"资格最老"的slave节点为新的master。

gm_group表记录gm形成的group的相关信息:

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

3. 镜像队列的一些细节

(1) 新增节点

slave节点先从gm_group中获取对应group的所有成员信息,然后随机选择一个节点并向这个节点发送请求,这个节点收到请求后,更新gm_group对应的信息,同时通知左右节点更新邻居信息(调整对左右节点的监控)及当前正在广播的消息,然后回复通知请求节点成功加入group。请求加入group的节点收到回复后再更新rabbit_queue中的相关信息,并根据需要进行消息的同步。

(2) 消息的广播

消息从master节点发出,顺着节点链表发送。在这期间,所有的slave节点都会对消息进行缓存,当master节点收到自己发送的消息后,会再次广播ack消息,同样ack消息会顺着节点链表经过所有的slave节点,其作用是通知slave节点可以清除缓存的消息,当ack消息回到master节点时对应广播消息的生命周期结束。

下图为一个简单的示意图,A节点为master节点,广播一条内容为"test"的消息。"1"表示消息为广播的第一条消息;"id=A"表示消息的发送者为节点A。右边是slave节点记录的状态信息。

为什么所有的节点都需要缓存一份发布的消息呢?

master发布的消息是依次经过所有slave节点,在这期间的任何时刻,有可能有节点失效,那么相邻的节点可能需要重新发送给新的节点。例如,A->B->C->D->A形成的循环链表,A为master节点,广播消息发送给节点B,B再发送给C,如果节点C收到B发送的消息还未发送给D时异常结束了,那么节点B感知后节点C失效后需要重新将消息发送给D。同样,如果B节点将消息发送给C后,B,C节点中新增了E节点,那么B节点需要再将消息发送给新增的E节点。

gm的状态记录:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-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_timer,   %%广播消息定时器
txn_executor      
}).
-record(member,
{
pending_ack,  %%待确认的消息,也就是已发布的消息缓存的地方
last_pub,     %%最后一次发布的消息计数
last_ack      %%最后一次确认的消息计数
}).

(3) 节点的失效

当slave节点失效时,仅仅是相邻节点感知,然后重新调整邻居节点信息、更新rabbit_queue、gm_group的记录等。如果是master节点失效,"资格最老"的slave节点被提升为master节点,slave节点会创建出新的coordinator,并告知gm修改回调处理为coordinator,原来的mirror_queue_slave充当amqqueue_process处理生产者发布的消息,向消费者投递消息等。

上面提到如果是slave节点失效,只有相邻的节点能感知到,那么master节点失效是不是也是只有相邻的节点能感知到?假如是这样的话,如果相邻的节点不是"资格最老"的节点,怎么通知"资格最老"的节点提升为新的master节点呢?

实际上,所有的slave节点在加入group时,mirror_queue_slave进程会对master节点的amqqueue_process进程(也可能是mirror_queue_slave进程)进行监控,如果master节点失效的话,mirror_queue_slave会感知,然后再通过gm进行广播,这样所有的节点最终都会知道master节点失效。当然,只有"资格最老"的节点会提升自己为新的master。

另外,在slave提升为master时,mirror_queue_slave内部来了一次"偷梁换柱",即原本需要回调mirror_queue_slave的handle_call/handle_info/handle_cast等接口进行处理的消息,全部改为调用amqqueue_process的handle_call/handle_info/handle_cast等接口,从而可以解释上面说的,mirror_queue_slave进程充当了amqqueue_process完成协议相关的消息的处理。

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
rabbit_mirror_queue_slave.erl
handle_call({gm_deaths,LiveGMPids},From,
            State = #state{q = Q = #amqqueue{name=QName,pid=MPid}})->
    Self = self(),
    case rabbit_mirror_queue_misc:remove_from_queue(QName,
                                                    Self,
                                                    LiveGMPids) of
        {ok,Pid,DeadPids} ->
            case Pid of
                MPid ->
                    %% master hasn't changed
                    gen_server2:reply(From, ok),
                    noreply(State);
                Self ->
                    %% we've become master
                    QueueState = promote_me(From,State),
                    {become,
                     %% 改由rabbit_amqqueue_process模块处理消息
                     rabbit_amqqueue_process,
                     QueueState, hibernate};
                ...
gen_server2.erl
handle_common_reply(Reply,Msg,GS2State = #gs2_state{name=Name,
                                                    debug=Debug})->
    case Reply of
        ...
        {become, Mod, NState, Time1} ->
            Debug1=common_become(Name,Mod,NState,Debug),
            loop(find_prioritisers(
                GS2State#gs2_state{mod=Mod,
                                   state=NState,
                                   time=Time1,
                                   debug=Debug1}));
        ...
handle_msg({'gen_call',From,Msg},
           GS2State=#gs2_state{mod=Mod,
                               state=State,
                               name=Name,
                               debug=Debug}) ->
    case catch Mod:handle_call(Msg, From, State) of
        ...
handle_msg(Msg,GS2State=#gs2_state{mod=Mod,state=State})->
    Reply = (catch dispatch(Msg,Mod,State)),
    handle_common_reply(Reply, Msg, GS2State).
dispatch({'$gen_cast',Msg},Mod,State)->
    Mod:handle_cast(Msg, State);
dispatch(Info, Mod, State)->
    Mod:handle_info(Info,State).

 

(4) 消息的同步

配置镜像队列的时候有个ha-sync-mode属性,这个有什么用呢?

新节点加入到group后,最多能从左边节点获取到当前正在广播的消息内容,加入group之前已经广播的消息则无法获取到。如果此时master节点不幸失效,而新节点有恰好成为了新的master,那么加入group之前已经广播的消息则会全部丢失。

注意:这里的消息具体是指新节点加入前已经发布并复制到所有slave节点的消息,并且这些消息还未被消费者消费或者未被消费者确认。如果新节点加入前,所有广播的消息被消费者消费并确认了,master节点删除消息的同时会通知slave节点完成相应动作。这种情况等同于新节点加入前没有发布任何消息。

避免这种问题的解决办法就是对新的slave节点进行消息同步。当ha-sync-mode配置为自动同步(automatic)时,新节点加入group时会自动进行消息的同步;如果配置为manually则需要手动操作完成同步。

转载于:https://www.cnblogs.com/yanwei-wang/p/4715429.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/358415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信订阅号如何开通付费功能

前几天看了一下启舰的一个视频中谈到他做自媒体的收入,我记得应该有一年30多万的收入,大概组成是微信公众号广告每个月2万*12个月。两本安卓书收取版权提成,根据出版量8%-10%不等,他一年的出版量在10000左右吧,每本书每…

实战sqlmap绕过WAF

本文转载于https://xz.aliyun.com/t/10385 实战演示 通过前期的信息收集发现存在注入的页面如下: 直接使用sqlmap跑发现出现如下错误: python2 sqlmap.py -u "http://xxxx?&daxxtaenull&paramexxxxxx" --batch --delay1 --random…

QQ群群排名如何进行SEO优化?

QQ群排名有多个方面,比如你的qq群名称,人数,还有活跃度等等,很多因素影响你的群排名。下面给大家讲解如何做到搜索第一。第一:群名称群名称一定要和你搜索的关键词相匹配,比如我建的一个粉丝群“爱嵩阁”&a…

Flash不同版本的下载安装及必要的系统组件未正常运行的解决办法

在一个外包平台刷入职培训视频,类似于慕课的课程,需要安装Flash才能播放。一般推荐谷歌浏览器,值得注意的是2020年12月,谷歌浏览器将不再支持flash flash官网 安装步骤 在百度搜索"flash",点击Flash中国官…

UEditor 任意文件上传漏洞

1 漏洞简介 1.1 漏洞描述 Ueditor是百度开发的一个网站编辑器,目前已经不对其进行后续开发和更新,该漏洞只存在于该编辑器的.net版本。其他的php,jsp,asp版本不受此UEditor的漏洞的影响,.net存在任意文件上传,绕过文件格式的限制…

HDU 3072 SCC Intelligence System

给出一个带权有向图&#xff0c;要使整个图连通。SCC中的点之间花费为0&#xff0c;所以就先缩点&#xff0c;然后缩点后两点之间的权值为最小边的权值&#xff0c;把这些权值累加起来就是答案。 1 #include <iostream>2 #include <cstdio>3 #include <algorith…

再见,Springboot和SpringCloud

Java中说到微服务肯定离不开Spring Boot和Spring Cloud&#xff0c;这两者到底有什么关系&#xff0c;什么是微服务&#xff0c;如果单纯的说SpringBoot&#xff0c;SpringCloud&#xff0c;都是不准确的&#xff0c;那应该怎么回答。官网对于Spring Boot的介绍Spring Boot mak…

通过暴露出来的OA和github信息拿Shell

本文转载于https://xz.aliyun.com/t/10392 记一次授权渗透测试 一&#xff1a;信息收集阶段 因为目标是学校&#xff0c;一般会去考虑收集学号&#xff0c;教工号。因为有的登陆点需要此类信息&#xff0c;且密码存在规律性&#xff08;身份证后六位&#xff0c;123456&#xf…

手机上可以编程看代码的软件

以后大家会在路上看到很多人拿着手机,他不是在聊天,他有可能是运维工程师、也可能是算法开发、也可能是java开发,还可能是客户端开发,也可能是前端开发... 让你编程一直在路上,这到底是程序员的福音,还是码农的枷锁。 粉丝提问: 这里介绍几款可以在手机上编程的app,分…

给你的执行力马上充值

“执行力就是在既定的战略和愿景的前提下,组织对内外部可利用的资源进行综合协调,制定出可行性的战略,并通过有效的执行措施从而最终实现组织目标、达成组织愿景的一种力量。执行力是一个变量,不同的执行者在执行同一件事情的时候也会得到不同的结果。执行力不但因人而异,而且还…

性能,可伸缩性和活力

本文是我们学院课程中名为Java Concurrency Essentials的一部分 。 在本课程中&#xff0c;您将深入探讨并发的魔力。 将向您介绍并发和并发代码的基础知识&#xff0c;并学习诸如原子性&#xff0c;同步和线程安全之类的概念。 在这里查看 &#xff01; 目录 1.简介 2.表现…

BurpSuite v2021.8.2安装使用

文章前言 几个月之前&#xff0c;Burpsuit官方发布了BurpSuite v2021.8.2&#xff0c;但是迟迟没有时间来试试手&#xff0c;正好借着这次调休的时间来写写文章&#xff0c;顺便更新一下Burpsuite 软件下载 天翼云盘 极速安全 家庭云|网盘|文件备份|资源分享 软件安装 Step 1&a…

程序员赚钱资源汇总,结合自己亲身经历

知识计算机知识深入理解计算机系统-必修课&#xff0c;NB学校的NB课程的NB教材代码大全-&#xff08;不要被这个名字吓到&#xff0c;英文叫做 Code complete&#xff09;微软的书&#xff0c;几乎可以当作是软件工程的百科全书。很少有人完全精通甚至完成这本书中所有部分的学…

逍遥模拟器配置burpsuite抓包环境

电脑与逍遥模拟器处于同一网段&#xff0c;在burpsuite中设置代理&#xff1a; 之后在逍遥模拟器中设置网络代理 之后直接下载下面的证书并且将其拖放到逍遥模拟器中&#xff1a; 证书下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1qJmcKcVj3NqmrWKf6zb83g …

OC本学习笔记Foundation框架NSString与NSMutableString

一、NSString与NSMutableString 相信大家对NSString类都不陌生。它是OC中提供的字符串类。它的对象中的字符串都是不可变的&#xff0c;而它的子类NSMutableString类的对象中的字符串就是可变的。什么是可变与不可变呢&#xff1f;二者的差别就是在已经创建的一个字符串…

phpMyAdmin渗透利用总结

phpMyAdmin渗透利用总结 前言 总结一下常见的phpmyadmin的漏洞利用姿势 简介 phpMyAdmin 是一个以PHP为基础&#xff0c;以Web-Base方式架构在网站主机上的MySQL的数据库管理工具&#xff0c;让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂…

SQL之条件判断专题

Case when (case when 情况1 then 结果1 when 情况1 then 结果1 else &#xff0b;剩余结果 end ) 列名 IF表达式 IF(判断内容&#xff0c;0&#xff0c;1) SELECT IF( sex1&#xff0c;男 &#xff0c;女 )sex from student IFNULL表达式 IF(判断内容&#xff0c;x) 假如判…

Struts2漏洞和Struts Scan工具实战

一、Apache Struts 2漏洞背景 1.漏洞详情 2017年3月6日&#xff0c;Apache Struts 2被曝存在远程命令执行漏洞。在使用基于Jakarta插件的文件上传功能条件下&#xff0c;恶意用户可以通过修改HTTP请求头中的Content-Type值构造恶意代码&#xff0c;在服务器上执行系统命令&…

2020年前端招聘技术概览

学习当下前端技术最好的方法就是从求职网站上找出前端的招聘要求&#xff0c;因为前端技术每年变化都很快&#xff0c;每个阶段都会不一样&#xff0c;这里简单从网站招聘要求罗列&#xff0c;仅供参考。更有针对性的是针对每个公司的招聘要求写简历&#xff0c;学习相关技术&a…

jexboss工具 -- JBOSS未授权访问漏洞利用

其实所有的节日&#xff0c;都不是为了礼物和红包而生&#xff0c;而是提醒我们不要忘记爱与被爱&#xff0c;生活需要仪式感&#xff0c;而你需要的是在乎和关爱。。。 ---- 网易云热评 小受&#xff1a;Ubuntu20 小攻&#xff1a;Kali2020 一、搭建该漏洞环境 查看上一篇文章…