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的身份启动
- 首先遍历 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)
- 开启镜像队列进程
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
- 往镜像队列进程发送初始化消息
rabbit_mirror_queue_slave:go(SPid, SyncMode)
-
删除消息队列名字为QName对应的目录下面所有的消息索引磁盘文件
-
实际调用 rabbit_variable_queue 进行队列 索引等存储初始化操作( 因为索引等文件都删除了,这一步实际内存中镜像队列进程中队列数据是空的,这一步可以参考队列主节点数据恢复过程 )
-
往队列主节点的进程PID发送 同步消息
这个是队列镜像队列进程起来后,由队列从节点进程往队列主节点进程发送这个消息,请参考rabbit_mirror_queue_slave::handle_go() 里的rabbit_mirror_queue_misc:maybe_auto_sync(Q1) -
队列主节点进程接收到 sync_mirrors 消息 (rabbit_amqqueue_process 下)
-
开启同步进程并且查找到当前队列所有从节点信息,并且往所有从队列从节点进程广播发送 sync_start 同步开始的消息
-
队列从节点进程接收到 sync_start 消息(在rabbit_mirror_queue_slave 里)
-
进行判断当前这个节点是否已经是最新的数据,因为有可能本来 队列需要 1主多人的情况下,又新加一个从节点进来,原来的从节点上的数据已经是和主节点上的数据保持一致了。那本来运行的从节点上是不需要进行数据同步的。
- 已经同步过返回:sync_deny
- 需要同步返回 :sync_ready
- 同步进程给需要同步的队列从节点进程发送 同步数据
队列主节点进程遍历当前所有消息同步发送给同步进程,再由同步进程发送给从节点进程
每次发送消息之前会发送一条 这是第几条数据. 这条消息存在队列从节点进程 #state{depth_delta} 字段中,当初始化同步近个队列的时候,这个值>0大于代表不需要同步
- 队列从节点处理同步进程同步过来的消息
当队列从节点接收到 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 如何知道哪个应用程序…...
vue+element下日期组件momentjs转换赋值问题
记录下使用momentjs转换日期字符串赋值给element的日期组件报错问题; <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数字示波器 简单开箱评测。 旧的示波器感觉不好用,所以换个新的,看中了普源的这款,主要看中它便携支持PD供电,还有伯德图功能,以及12bit的垂直分辨率。如果你对我上面说的点没需求&…...
docker 安装Oracle19c
一、下载镜像 docker pull registry.cn-hangzhou.aliyuncs.com/zhuyijun/oracle:19c通过docker images 命令查看 如下图:已经有oracle 19c镜像。 二、创建挂载文件 # 创建文件 mkdir -p /home/data/oracle/oradata# 授权,不授权会导致后面安装失败 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(AOP)来实现记录操作日志的功能。我们将探讨Spring Boot集成AOP的基本概念,以及如何使用Spring Boot实现AOP记录操作日志。最后,我们将通过一个具体示例…...
C++ //练习 7.38 有些情况下我们希望提供cin作为接受istream参数的构造函数的默认实参,请声明这样的构造函数。
C Primer(第5版) 练习 7.38 练习 7.38 有些情况下我们希望提供cin作为接受istream&参数的构造函数的默认实参,请声明这样的构造函数。 环境:Linux Ubuntu(云服务器) 工具:vim 代码块 Sa…...
算法:两数之和
算法:两数之和 方法一:暴力法 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; }方法二:哈希表 func…...
pytorch: ground truth similarity matrix
按照真实标签排序pair-wise相似度矩阵的Pytorch代码 本文仅作留档,用于输出可视化 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,后 定位,再从蓝牙到NFC,这个就是我大致熟悉开源鸿蒙代码的一个顺序流程,WiFi 的年前差不多基本流程熟悉了,当然还有很多细节和内容没有写到,后续都会慢慢的丰富起来,这一篇将开启GNSS的篇…...
设计模式-创建型模式-抽象工厂模式
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。 由于工厂方法模式中的每个工厂只生产一类产品&…...
【Go】五、Grpc 的入门使用
grpc 与 protobuf grpc 使用的是 protobuf 协议,其是一个通用的 rpc 框架,基本支持主流的所有语言、其底层使用 http/2 进行网络通信,具有较高的效率 protobuf 是一种序列化格式,这种格式具有 序列化以及解码速度快(…...
PDF加粗内容重复读取解决方案
文章目录 前言发现问题解决方案问题分析大致逻辑 show my code 前言 在使用pdfplumber读取PDF的过程中,由于加黑的内容会被莫名其妙的读取两次,带来了很大的困扰。这篇文章将给出解决方案。 发现问题 在在使用pdfplumber读取PDF的过程中,读…...
Golang 并发 Channel的用法
目录 Golang 并发 Channel的用法1. channel 的创建2. nil channel读写阻塞示例close示例 3. channel 的读写4. channel 只读只写5. 关闭channelchannel关闭后,剩余的数据能否取到读取关闭的channel,将获取零值使用ok判断,是否关闭使用for-ran…...
cfa复习资料介绍之二:notes(SchweserNotes)
什么是CFA notes? CFA资料Study Notes都是外国一些出版机构针对CFA考试提供的复习资料,而其中Schweser在国内的名气最大,用的人也最多。内容详尽并且突出重点,并且CFA Notes的内容相比于官方curriculum教材更加符合中国CFA考生的心态&#x…...
FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,可以用标准 FITC 滤光片组进行成像
FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,可以用标准 FITC 滤光片组进行成像 您好,欢迎来到新研之家 文章关键词:FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,FITC 棕榈酸酯缀合物,F…...
本机防攻击简介
定义 在网络中,存在着大量针对CPU(Central Processing Unit)的恶意攻击报文以及需要正常上送CPU的各类报文。针对CPU的恶意攻击报文会导致CPU长时间繁忙的处理攻击报文,从而引发其他业务的中断甚至系统的中断;大量正常…...
Python 进阶语法:JSON
1 什么是 JSON? 1.1 JSON 的定义 JSON 是 JavaScript Object Notation 的简写,字面上的意思是 JavaScript 对象标记。本质上,JSON 是轻量级的文本数据交换格式。轻量级,是拿它与另一种数据交换格式XML进行比较,相当轻…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
