当前位置: 首页 > news >正文

RabbitMQ节点故障的容错方案

RabbitMQ节点故障的容错方案

  • 1. broker启动加载逻辑
    • 1.1 日志文件
    • 1.2 broker启动流程
      • 1.2.1 整体流程
      • 1.2.2 数据恢复流程
  • 2. 队列高可用
    • 2.1 选主逻辑
      • 2.1.1 从节点晋升策略
      • 2.1.2 主队列选择策略
    • 2.2 HA切换
  • 3. 疑问和思考
    • 3.1 如果一个broker宕机,运行在broker上的队列数据丢失,是否会自动做均衡?
    • 3.2 如果一个broker宕机,重新加入集群后,数据同步逻辑是怎样的?
  • 4. 参考文档

本文主要探讨rabbitmq集群镜像模式的高可用容错方案和容错能力的探讨。在出现单机故障时相关的容错方案。

更多关于分布式系统的架构思考请参考文档关于常见分布式组件高可用设计原理的理解和思考


1. broker启动加载逻辑

在rabbitmq中,只有broker进程,其余的组件或者角色都是通过broker衍生出来,因此broker的高可用和数据加载流程有必要理解和分析。

1.1 日志文件

RabbitMQ使用数据文件来存储队列、交换机和消息等信息。以下是一些常见的RabbitMQ数据文件:

  • Queues(队列):每个队列都有一个对应的数据文件用于存储队列中的消息。这些文件通常保存在RabbitMQ服务器的磁盘上,以便在服务器重启后保留消息。
  • Exchanges(交换机):交换机也有对应的数据文件,用于存储交换机的配置信息,包括交换机的名称、类型和绑定规则等。
  • Message logs(消息日志):RabbitMQ记录每个传入/传出的消息以及与之相关的元数据信息,例如消息的交换机和队列等。这些消息日志通常以日志文件的形式存储在磁盘上。
  • Cluster state(集群状态):如果使用RabbitMQ集群,每个节点都会维护一个集群状态文件,用于记录集群成员、队列分布和其他集群相关的信息。
  • Configuration files(配置文件):RabbitMQ还使用配置文件来存储服务器的配置信息,例如监听的端口、虚拟主机、用户权限等。

这些数据文件通常存储在RabbitMQ服务器的指定目录中。在默认情况下,RabbitMQ使用的数据文件位于服务器的/var/lib/rabbitmq目录下。但是,可以通过配置文件指定不同的目录或自定义数据文件的存储位置。

1.2 broker启动流程

1.2.1 整体流程

RabbitMQ节点启动流程可以归纳为以下几个步骤:

  • 启动Erlang虚拟机:RabbitMQ使用Erlang语言进行开发,所以首先需要启动Erlang虚拟机。Erlang虚拟机负责管理RabbitMQ的进程和资源。
  • 加载RabbitMQ应用程序:一旦Erlang虚拟机启动,它将加载RabbitMQ的应用程序代码。该代码包括RabbitMQ的主要组件,如AMQP协议处理器、队列管理器、交换机管理器等。
  • 初始化节点:在RabbitMQ节点启动时,它会执行一系列初始化步骤。这些步骤包括读取配置文件、创建必要的目录和文件、加载插件等。
  • 启动AMQP协议处理器:RabbitMQ使用AMQP协议来进行消息传递。一旦节点初始化完成,它会启动AMQP协议处理器,以便处理传入和传出的AMQP请求。
  • 启动队列和交换机管理器:RabbitMQ的队列管理器和交换机管理器负责管理消息队列和消息路由。这些组件在节点启动时会被启动,以便为客户端提供队列和交换机的管理功能。
  • 启动其他插件和扩展:RabbitMQ还支持许多插件和扩展,如插件可以用于实现各种功能,如可视化管理界面、消息持久化、消息过滤等。这些插件和扩展会在节点启动时被加载和启动。
  • 监听客户端连接:最后,RabbitMQ节点会开始监听传入的客户端连接。一旦客户端连接到节点,它们可以使用AMQP协议与节点进行交互,发送和接收消息。

这些步骤通常是自动完成的,用户只需要启动RabbitMQ节点,并确保配置正确,节点就可以正常工作。

1.2.2 数据恢复流程

rabbitmq节点异常恢复后的加载顺序如下

  • 优先加载本地的数据文件获取集群的配置信息,并重新组建集群
  • 如果本地的数据文件为空,则会读取集群的配置文件,并组建集群

镜像模式下,节点以Follower的身份启动

  1. 首先遍历 rabbit_queue 表,找到 需要在本节点进行做镜像的队列。
    先查询出当前需要做镜像队列的队列的所有从节点,再把通过suggested_queue_nodes 函数找出队列建议在哪些节点上需要做镜像队列,再和当前节点对比,如果需要在当前节点需要做镜像队列,则进行镜像队列进程的初始化操作

suggested_queue_nodes 函数 是通过配置策略来进行运算的,参考:rabbit_mirror_queue_mode_exactly.erl

rabbit_mirror_queue_mode_nodes.erl rabbit_mirror_queue_mode_all.erl 这三个文件的 suggested_queue_nodes 函数

用python转换下,大概以下逻辑是遍历队列当前节点队列,并跟队列的Leader进行数据同步

need_mirror_queues = []
for q in rabbit_queue:qSlaveNodeArr = []for sqid in q.Spids:if node(spid) != node():continueelse:qSlaveNodeArr.append(node(spid))breakif node() in qSlaveNodeArr:passelse:qSlaveNodeArr.append(node())suggestedNodes = suggested_queue_nodes(qSlaveNodeArr)if node() in suggestedNodes:need_mirror_queues.append(q)for q in need_mirror_queues:start_mirror(q)
  1. 开启镜像队列进程
rabbit_mirror_queue_misc::add_mirror() -- >
rabbit_amqqueue_sup_sup:start_queue_process(MirrorNode, Q, slave) --> 
rabbit_amqqueue_sub::start_link()

队列进程中加载了 rabbit_amqqueue_process 和 rabbit_mirror_queue_slave

  1. 往镜像队列进程发送初始化消息
rabbit_mirror_queue_slave:go(SPid, SyncMode)
  1. 删除消息队列名字为QName对应的目录下面所有的消息索引磁盘文件

  2. 实际调用 rabbit_variable_queue 进行队列 索引等存储初始化操作( 因为索引等文件都删除了,这一步实际内存中镜像队列进程中队列数据是空的,这一步可以参考队列主节点数据恢复过程 )

  3. 往队列主节点的进程PID发送 同步消息
    这个是队列镜像队列进程起来后,由队列从节点进程往队列主节点进程发送这个消息,请参考rabbit_mirror_queue_slave::handle_go() 里的 rabbit_mirror_queue_misc:maybe_auto_sync(Q1)

  4. 队列主节点进程接收到 sync_mirrors 消息 (rabbit_amqqueue_process 下)

  5. 开启同步进程并且查找到当前队列所有从节点信息,并且往所有从队列从节点进程广播发送 sync_start 同步开始的消息

  6. 队列从节点进程接收到 sync_start 消息(在rabbit_mirror_queue_slave 里)

  7. 进行判断当前这个节点是否已经是最新的数据,因为有可能本来 队列需要 1主多人的情况下,又新加一个从节点进来,原来的从节点上的数据已经是和主节点上的数据保持一致了。那本来运行的从节点上是不需要进行数据同步的。

  • 已经同步过返回:sync_deny
  • 需要同步返回 :sync_ready
  1. 同步进程给需要同步的队列从节点进程发送 同步数据
    队列主节点进程遍历当前所有消息同步发送给同步进程,再由同步进程发送给从节点进程

每次发送消息之前会发送一条 这是第几条数据. 这条消息存在队列从节点进程 #state{depth_delta} 字段中,当初始化同步近个队列的时候,这个值>0大于代表不需要同步

  1. 队列从节点处理同步进程同步过来的消息
    当队列从节点接收到 sync_start 消息的时候 ,会进入一个死循环接收消息的状态。这个状态只会和 同步进程之间同步,和其他进程通信延迟。从进程初始化的时候 depth_delta = undefined,当然 depth_delta = 0 的时候,这个时候就不会进入接收数据的状态,会返回给同步进程不需要同步消息。在数据同步完的时候 ,从进程会把 depth_delta 设置成 0
    rabbit_mirror_queue_slave::handle_cast({sync_start, Ref, Syncer},
    数据处理逻辑大概是拿到消息后调用 rabbit_variable_queue::publish() 往队列进程中写消息

2. 队列高可用

2.1 选主逻辑

  • 如果某个slave失效了,系统处理做些记录外几乎啥都不做:master依旧是master,客户端不需要采取任何行动,或者被通知slave失效。

  • 如果master失效了,那么slave中的一个必须被选中为master。被选中作为新的master的slave通常是最老的那个,因为最老的slave与前任master之间的同步状态应该是最好的。然而,特殊情况下,如果存在没有任何一个slave与master完全同步的情况,那么前任master中未被同步的消息将会丢失。

2.1.1 从节点晋升策略

镜像队列主节点出现故障时,最老的从节点会被提升为新的主节点。如果新提升为主节点的这个副本与原有的主节点并未完成数据的同步,那么就会出现数据的丢失,而实际应用中,出现数据丢失可能会导致出现严重后果。
rabbitmq 提供了 ha-promote-on-shutdown,ha-promote-on-failure 两个参数让用户决策是保证队列的可用性,还是保证队列的一致性;两个参数分别控制正常关闭、异常故障情况下从节点是否提升为主节点,其可设置的值为 when-synced 和 always。

ha-promote-on-shutdown/ha-promote-on-failure说明
when-synced从节点与主节点完成数据同步,才会被提升为主节点
always无论什么情况下从节点都将被提升为主节点

这里要注意的是ha-promote-on-failure设置为always,插拔网线模拟网络异常的两个测试场景:当网络恢复后,其中一个会重新变为mirror,具体是哪个变为mirror,受cluster_partition_handling处理策略的影响。

例如两台节点A,B组成集群,并且cluster_partition_handling设置为autoheal,队列的master位于节点A上,具有全量数据,mirror位于节点B上,并且还未完成消息的同步,此时出现网络异常,网络异常后两个节点交互决策:如果节点A节点成为赢家,此时B节点内部会重启,这样数据全部保留不会丢失;相反如果B节点成为赢家,A需要重启,那么由于ha-prromote-on-failure设置为always,B节点上的mirror提升为master,这样就出现了数据丢失。

2.1.2 主队列选择策略

RabbitMQ中的每个队列都有一个主队列。该节点称为队列主服务器。所有队列操作首先经过主队列,然后复制到镜像。这对于保证消息的FIFO排序是必要的。通过在策略中设置 queue-master-locator 键的方法可以定义主队列选择策略,这是常用的方法。

queue-master-locator说明
min-masters选择承载最小绑定主机数量的节点
client-local选择客户机声明队列连接到的节点
random随机选择一个节点

2.2 HA切换

如果leader节点宕机或者节点异常,会触发选举逻辑,选择新的leader队列。

3. 疑问和思考

3.1 如果一个broker宕机,运行在broker上的队列数据丢失,是否会自动做均衡?

不会。因为镜像队列所有节点理论上保持的数据相同,如果Leader节点宕机,会重新触发选举,选择新的节点成为Leader继续提供服务。

3.2 如果一个broker宕机,重新加入集群后,数据同步逻辑是怎样的?

每当一个节点加入或者重新加入(例如从网络分区中恢复过来)镜像队列,之前保存的队列内容会被清空。

ha-sync-mode说明
manual这是默认模式。新队列镜像将不接收现有消息,它只接收新消息。一旦使用者耗尽了仅存在于主服务器上的消息,新的队列镜像将随着时间的推移成为主服务器的精确副本。如果主队列在所有未同步的消息耗尽之前失败,则这些消息将丢失。您可以手动完全同步队列,详情请参阅未同步的镜像部分。
automatic当新镜像加入时,队列将自动同步。值得重申的是,队列同步是一个阻塞操作。如果队列很小,或者您在RabbitMQ节点和ha-sync-batch-size之间有一个快速的网络,那么这是一个很好的选择。

4. 参考文档

  • RabbitMQ 启动过程

相关文章:

RabbitMQ节点故障的容错方案

RabbitMQ节点故障的容错方案 1. broker启动加载逻辑1.1 日志文件1.2 broker启动流程1.2.1 整体流程1.2.2 数据恢复流程 2. 队列高可用2.1 选主逻辑2.1.1 从节点晋升策略2.1.2 主队列选择策略 2.2 HA切换 3. 疑问和思考3.1 如果一个broker宕机,运行在broker上的队列数…...

瑞_Redis_初识Redis(含安装教程)

文章目录 1 初识Redis1.1 认识NoSQL1.1.1 结构化与非结构化1.1.2 关联和非关联1.1.3 查询方式1.1.4 事务1.1.5 总结 1.2 认识Redis1.2.1 介绍1.2.2 特征1.2.3 优势 1.3 安装Redis ★★★1.3.1 Linux安装Redis1.3.1.1 安装Redis依赖 1.3.2 Windows安装Redis1.3.2.1 安装步骤1.3.…...

Android进阶(二十九) 走近 IntentFilter

文章目录 一、什么是IntentFilter ?二、IntentFilter 如何过滤隐式意图?2.1 动作测试2.2 类别测试2.3 数据测试 一、什么是IntentFilter ? 如果一个 Intent 请求在一片数据上执行一个动作, Android 如何知道哪个应用程序&#xf…...

vue+element下日期组件momentjs转换赋值问题

记录下使用momentjs转换日期字符串赋值给element的日期组件报错问题&#xff1b; <el-date-pickerv-model"form.serviceTime"type"date"class"fill-w mar-t-xs"value-format"yyyy-MM-dd HH:mm:ss"placeholder"请选择日期&quo…...

普源(RIGOL) DHO914S示波器 简单开箱评测

普源精电(RIGOL) DHO914S 12bit数字示波器 简单开箱评测。 旧的示波器感觉不好用&#xff0c;所以换个新的&#xff0c;看中了普源的这款&#xff0c;主要看中它便携支持PD供电&#xff0c;还有伯德图功能&#xff0c;以及12bit的垂直分辨率。如果你对我上面说的点没需求&…...

docker 安装Oracle19c

一、下载镜像 docker pull registry.cn-hangzhou.aliyuncs.com/zhuyijun/oracle:19c通过docker images 命令查看 如下图&#xff1a;已经有oracle 19c镜像。 二、创建挂载文件 # 创建文件 mkdir -p /home/data/oracle/oradata# 授权&#xff0c;不授权会导致后面安装失败 c…...

qt-OPENGL-星系仿真

qt-OPENGL-星系仿真 一、演示效果二、核心程序三、下载链接 一、演示效果 二、核心程序 #include "model.h"Model::Model(QOpenGLWidget *_glWidget) { glWidget _glWidget;glWidget->makeCurrent();initializeOpenGLFunctions(); }Model::~Model() {destroyV…...

Java实战:Spring Boot实现AOP记录操作日志

本文将详细介绍如何在Spring Boot应用程序中使用Aspect Oriented Programming&#xff08;AOP&#xff09;来实现记录操作日志的功能。我们将探讨Spring Boot集成AOP的基本概念&#xff0c;以及如何使用Spring Boot实现AOP记录操作日志。最后&#xff0c;我们将通过一个具体示例…...

C++ //练习 7.38 有些情况下我们希望提供cin作为接受istream参数的构造函数的默认实参,请声明这样的构造函数。

C Primer&#xff08;第5版&#xff09; 练习 7.38 练习 7.38 有些情况下我们希望提供cin作为接受istream&参数的构造函数的默认实参&#xff0c;请声明这样的构造函数。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 Sa…...

算法:两数之和

算法&#xff1a;两数之和 方法一&#xff1a;暴力法 function twoSum(nums, target) {for (let i 0; i < nums.length; i) {for (let j i 1; j < nums.length; j) {if (nums[i] nums[j] target) {return [i, j];}}}return null; }方法二&#xff1a;哈希表 func…...

pytorch: ground truth similarity matrix

按照真实标签排序pair-wise相似度矩阵的Pytorch代码 本文仅作留档&#xff0c;用于输出可视化 Inputs: Ground-truths Y ∈ R n 1 \mathbf{Y}\in\mathbb R^{n\times 1} Y∈Rn1, Similarity matrix A ∈ R n n \mathbf{A}\in\mathbb R^{n\times n} A∈RnnOutputs: Block dia…...

鸿蒙 gnss 开关使能流程

先WiFi&#xff0c;后 定位&#xff0c;再从蓝牙到NFC&#xff0c;这个就是我大致熟悉开源鸿蒙代码的一个顺序流程&#xff0c;WiFi 的年前差不多基本流程熟悉了&#xff0c;当然还有很多细节和内容没有写到&#xff0c;后续都会慢慢的丰富起来&#xff0c;这一篇将开启GNSS的篇…...

设计模式-创建型模式-抽象工厂模式

抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。抽象工厂模式又称为Kit模式&#xff0c;它是一种对象创建型模式。 由于工厂方法模式中的每个工厂只生产一类产品&…...

【Go】五、Grpc 的入门使用

grpc 与 protobuf grpc 使用的是 protobuf 协议&#xff0c;其是一个通用的 rpc 框架&#xff0c;基本支持主流的所有语言、其底层使用 http/2 进行网络通信&#xff0c;具有较高的效率 protobuf 是一种序列化格式&#xff0c;这种格式具有 序列化以及解码速度快&#xff08;…...

PDF加粗内容重复读取解决方案

文章目录 前言发现问题解决方案问题分析大致逻辑 show my code 前言 在使用pdfplumber读取PDF的过程中&#xff0c;由于加黑的内容会被莫名其妙的读取两次&#xff0c;带来了很大的困扰。这篇文章将给出解决方案。 发现问题 在在使用pdfplumber读取PDF的过程中&#xff0c;读…...

Golang 并发 Channel的用法

目录 Golang 并发 Channel的用法1. channel 的创建2. nil channel读写阻塞示例close示例 3. channel 的读写4. channel 只读只写5. 关闭channelchannel关闭后&#xff0c;剩余的数据能否取到读取关闭的channel&#xff0c;将获取零值使用ok判断&#xff0c;是否关闭使用for-ran…...

cfa复习资料介绍之二:notes(SchweserNotes)

什么是CFA notes? CFA资料Study Notes都是外国一些出版机构针对CFA考试提供的复习资料&#xff0c;而其中Schweser在国内的名气最大&#xff0c;用的人也最多。内容详尽并且突出重点&#xff0c;并且CFA Notes的内容相比于官方curriculum教材更加符合中国CFA考生的心态&#x…...

FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,可以用标准 FITC 滤光片组进行成像

FITC Palmitate Conjugate&#xff0c;FITC-棕榈酸酯缀合物&#xff0c;可以用标准 FITC 滤光片组进行成像 您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;FITC Palmitate Conjugate&#xff0c;FITC-棕榈酸酯缀合物&#xff0c;FITC 棕榈酸酯缀合物&#xff0c;F…...

本机防攻击简介

定义 在网络中&#xff0c;存在着大量针对CPU&#xff08;Central Processing Unit&#xff09;的恶意攻击报文以及需要正常上送CPU的各类报文。针对CPU的恶意攻击报文会导致CPU长时间繁忙的处理攻击报文&#xff0c;从而引发其他业务的中断甚至系统的中断&#xff1b;大量正常…...

Python 进阶语法:JSON

1 什么是 JSON&#xff1f; 1.1 JSON 的定义 JSON 是 JavaScript Object Notation 的简写&#xff0c;字面上的意思是 JavaScript 对象标记。本质上&#xff0c;JSON 是轻量级的文本数据交换格式。轻量级&#xff0c;是拿它与另一种数据交换格式XML进行比较&#xff0c;相当轻…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...