深度解析RocketMq源码-高可用存储组件(一) raft协议详解

1.绪论

前面的文章已经分析过,以前rocketmq通过主从复制的思想实现系统的高可用,即在搭建集群的时候会手动的设置一个主节点和从节点,在写入数据的时候,会先写入到主broker,然后再同步到从节点中。但是这样会有一个问题,就是主节点宕机过后,需要手动的修改从节点成为新的主节点。在rocketmq的最新的版本中,已经引入了dledger的架构,它利用raft共识算法,当从节点宕机过后,能够自动的选举主节点,并完成主节点和从节点的数据一致。

2.raft算法

2.1  raft算法简述

在1990年,Leslie Lamport提出来Paxos协议,它是基于多leader的协议,所以对于整个分布式系统而言,数据写入有多个入口,导致多个主节点实现强一致性变得异常困难,很难进行实现。2013年,Diego ongrao和John Ousterhout提出了raft算法,它是一个强leader的算法,即整个分布式系统只有一个leader和多个follower,leader负责数据写入,leader和follower都可以进行数据读取,这样整个系统的入口便只有一个。业界有很多对raft算法的实现,比如nacos保证高可用的jRaft框架,和rocketmq保证高可用的dledger框架等。

2.2 raft算法问题拆分

1. 主节点选举

当主节点宕机,如何从从节点当中选择一个新的主节点?

2.日志复制

如何将主节点中的数据同步到从节点中?

3.安全性

分布式系统存在多个情况,算法需要设置哪些限制来为系统的可用性和安全性提供保障?

2.3 leader选举

2.3.1  选举的目的

raft算法有如此复杂的选举流程,这样做的目的是什么呢,其实本质上是为了选择出整个集群中拥有最新一条数据的follower来作为leader,并且同步给其他的follower,这样才能保证整个集群拥有follower宕机过后最新的一条数据,从而保证数据不丢失。为什么这样做能够保证数据不丢失呢,后面我们分析完raft协议的日志复制,再来分析这个问题。

2.3.2 raft算法中的角色

raft算法中有三种角色,分别是leader,follower和candidate,leaderf负责写数据,并且写数据过后,会将数据复制给follower。leader会给每个follower发送心跳数据,如果某个follower超过某个时间没有收到心跳数据,便会认为leader已经宕机,便会将自己设置为candidate,并会将当前的term加1,并且发起选举。在选举成功过后,设置自己为follower,并且给其他follower发送心跳数据,防止发起新的一轮选举。这就是raft算法的大概步骤。

2.3.3 raft算法中的任期号term

1.什么是term

term是一个单调递增的数字,每次candidate在发起选举的时候,便会将当前的term增加1。并且raft协议规定在每个term中,只能有一次选举。

2.为什么需要任期号

比如在candiate发起新的一轮选举过后,并且成功当选为follower,老的leader恢复,当时发现自己的term已经小于当前的leader的term,所以便会自动将自己更新为follower。

2.3.4 raft算法中需要交换的数据报文

RequestVotes Rpc:用来进行投票的协议

AppendEntries Rpc:leader向follower同步日志的报文,并且也会作为心跳报文发送给follower,当follower收到心跳过后,会重置选举的时钟。

2.3.5 raft算法选举的具体流程

我们现在假设有A,B,C,D,E五个节点搭建了集群。

1.leader宕机

假设在最开始的时候,A节点是leader节点,但是A节点突然宕机,假设B节点的超时时钟最先到期,发现没有收到leader的心跳包过后,开始发起选举。

在选举的时候,为了防止选举风暴,也就是每个节点都同时发起选举,这样会导致很难选举出新的leader,所以可以没有收到leader的心跳包的时间设置为随机时间,这样他们选举就会分隔开。

2.出现新的candidate并且发起投票

B节点将自己的term加1,同时将自己的id,term和最新一条日志索引的Id封装成RequestVotes Rpc发送给其他节点。

3.其他follower开始投票

其他节点收到投票请求过后,开始进行投票,投票规则如下:

1.如果当前节点在当前term内没有投过票,才开始投票,否则,跳过。
2.如果当前follower节点发现term比收到的投票请求中的term要低,便将自己的term更新为最新的term。

3.如果leader或者candidate发现自己的term比当前的term要小,便立刻恢复为follower。这个主要解决leader宕机或者candiate宕机过后,已经过去几轮投票了,然后恢复的场景。

4.follower会将投票的最新的日志索引和自身的最新一条索引比较,如果不是则拒绝投票。这样做的目的是为了保证最终投票出来的leader一定拥有整个集群最新的一条日志。raft协议在进行日志复制的时候,一定是保证超过半数以上follower节点复制日志成功过后,才会返回成功。所以在leader宕机过后,一定能够保证整个集群超过一半的节点拥有最新的日志,再结合投票时一定是半数以上的支持,才能当选leader,也即他的索引一定是大于等于集群半数以上节点的,所以一定有用最新的日志。

综上,选举投票其实就是,首先判断当前节点在当前的term内没有投过票,如果投过,便跳过;然后比较term,如果自己的term小于当前candidate节点的term,便更新自己的term,否则,便跳过;然后再比较自己的索引,如果当前节点的索引文件小于等于candidate的索引文件。上述三个条件都满足过后,才会投票给当前candidate。

4.比较投票结果

投票结果分为3种情况:

1.选举成功

如果或者整个集群N/2+1个节点的支持,便当选该节点为leader,并且发送心跳包给其他节点。candidate或者leader节点收到过后,直接设置自己状态为follower,而follower则会重置选举时钟。

2.选举失败

如果在选举过程中,收到其他节点已经成为leader,并且term大于等于自己,便更新自己状态为follower。

3.选举超时

如果在选举过程可能因为有其他节点在进行选举,所以会分散自己的票数,这个时候便会重新选举。由于每个节点的选举时钟是不一样的,所以可以尽量避免这种情况的发生。

2.4 日志复制

2.4.1 日志同步

在leader选举成功过后,数据便会从leader写入,然后leader同步给follower,此时会采用两阶段的提交方式,leader收到客户端的写入操作后,将其封装成一条日志文件,同步给follower;follower将给leader返回ack。leader收到半数以上ack过后,便将日志应用到状态机。如果存在follower超过过一定时间也没有返回ack,leader会一直重试。

那leader是什么时候将日志文件应用到状态机中的呢,每次leader会将自己最新一条已经应用到状态机的日志的索引通过心跳包发送给follower,这样follower在收到过后,会将小于该索引的日志全部应用到状态机中。

注:什么是状态机呢,即leader向follower同步的是一系列命令,每个分布式节点都存储有一些列的日志命令和一个状态机,只要按照顺序将这些命令应用到状态机中,最后所有节点的状态一定是一致的。比如更新节点的主节点为新的主节点就是状态机需要进行的操作。

2.4.2 一致性检查

存在两种异常情况:

1.如果某个从节点宕机过后,在恢复,这个时候,从节点的日志已经落后主节点一大截,如何保证主节点和从节点数据一致呢?
2.新的主节点当选过后,可能某些从节点中存在一些没有被应用的日志,这个时候从节点的索引比主节点大。

针对上面两个问题,如何解决呢?坚持一个原则,也即主节点只会增加索引,不会删除索引。

leader会为每个follower维护一个next Index,在新leader当选过后,会初始化每个follower的next index为自己最后一条日志的Index+1 ,然后进行一致性检查。如果某个follower的日志和自己的日志不一致,便会将next Indedx进行减1,然后进行重试,直到找到最后一条与follwer相同的日志,然后进行重试,最后达成统一。

2.5 安全限制

为了保证raft算法的安全性,所以需要增加一些限制:

2.5.1. 选举限制

前面已经说过,选举的时候为了保证leader一定是拥有整个集群最新一条日志的节点,所以在投票的时候,会将candidate的最新一条索引与自身最新一条索引进行比较,只有索引大于等于自己,才会投票给它。

2.5.2 提交限制

每个leader只会commit当前leader term的条目。这样就会避免某些并没有给用户返回成功的数据被应用到系统中。比如比如A节点在当选leader过后,只复制了少于一半的数据,就宕机了,这个时候并且没有给客户端返回成功,这部分数据就是脏数据,如果A节点恢复并成功当选leader过后,又有可能将该日志复制到其他follower,最后这条日志被成功应用。所以为了解决该问题,直接将这部分数据淘汰掉,只能commit当前leader term的条目。

2.6 日志压缩

raft算法存储的日志其实是一些列的命令,但是如果节点宕机过后,再进行重启,会将所有的命令加载一遍,这样会耗费很长的时间。所以可以定期的将状态机应用完命令的结果快照一份并存储起来。其实就是类似于redis的Aof和rdb。

3.参考文献

1.https://blog.csdn.net/weixin_63566550/article/details/134794739

2.https://juejin.cn/post/6907151199141625870

3.Raft协议详解--背景+概念介绍+算法剖析-CSDN博客

A节点突然宕机

raft算法是基于强leader的共识算法

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

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

相关文章

坎德拉candela3d光伏电站三维设计软件【无标题】

Candela3D 是一款基于 SketchUp(草图大师)开发的新一代光伏电站三维设计软件。它适用于复杂地形、平坦地形光伏电站的建设项目,同时适用于可研、初设、施工图、项目运营等阶段。这款软件具有多项功能,例如: • 能够突…

【云原生】Docker可视化工具Portainer使用详解

目录 一、前言 二、docker可视化管理概述​​​​​​​ 2.1 什么是docker可视化管理 2.1.1 Docker可视化管理常用功能 2.2 为什么需要docker可视化管理工具 2.3 docker可视化工具带来的好处 三、常用的docker容器可视化管理工具解决方案 3.1 Portainer 3.2 Rancher 3…

【Python机器学习】k均值聚类——矢量量化,或者将k均值看作分解

虽然k均值是一种聚类算法,但在k均值和分解方法之间存在一些相似之处。k均值尝试利用簇中心来表示每个数据点,可以看作仅用一个分量来表示每个数据点,该分量由簇中心给出。这种观点将k均值看作是一种分解方法,其中每个点用单一分量…

可视化大屏开发系列——DataV的使用

以下内容为近期个人学习总结,若有错误之处,欢迎指出! 可视化大屏开发系列——DataV的使用 一、介绍二、注意事项1、技术支持2、兼容性3、状态更新 三、实现效果四、使用(在vue2项目中)1.npm安装2.main.js中引入3.开启愉…

QNX OS微内核系统

微内核架构 微内核(Microkernel)架构是一种操作系统架构模式,其核心思想是尽量将操作系统的基本功能压缩在最小的核心中,而将其他服务(如设备驱动、文件系统、网络协议等)放在用户空间中运行,从而增加系统的灵活性和安全性,这种架构有几个主要特点和优势: 最小化核心…

WordPress软件下载主题Inpandora

Inpandora(中文名为潘多拉)是一款基于软件下载站定制的WordPress主题,帮助站长使用WordPress快速搭建一个专业的WordPress软件博客。Inpandora这款WordPress主题可以说是因软件而生,从UI设计到后台设置功能,都充分体现…

设计软件有哪些?贴图插件篇(1),渲染100邀请码1a12

设计师经常要处理贴图,这里介绍一些贴图所用到的插件。 1、Substance 3D Painter Substance 3D Painter是Substance 3D软件套件中的一部分,是一款专业的纹理绘制软件。它提供了直观的界面和强大的工具,用于在3D模型上进行高质量的纹理绘制和…

基于51单片机数字频率计的设计资料

题目:基于51单片机数字频率计的设计 系 部: 专 业: 学 号: …

【七】【QT开发应用】跨UI发送信号,跨线程发送信号

跨UI发送信号 基本框架 新建窗口 自定义信号 跨线程发送信号 新建线程 查看线程号 完整代码 跨UI发送信号 setdialog.h #ifndef SETDIALOG_H #define SETDIALOG_H#include <QDialog>namespace Ui { class setdialog; }class setdialog : public QDialog {Q_OBJECTpub…

1panel OpenResty 设置网站重定向

当我们部署网站时需要&#xff0c;输入"cheshi.com"域名回车&#xff0c;希望他自动跳转https://cheshi.com/indx/&#xff0c;而不是直接跳转https://cheshi.com时可以利用重定向来实现&#xff0c; 这里演示的是 1panel 如何设置&#xff08;nginx 貌似也是这样配…

数据结构9——排序

一、冒泡排序 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff0c;顾名思义&#xff0c;就是指越小的元素会经由交换慢慢“浮”到数列的顶端。 算法原理 从左到右&#xff0c;依次比较相邻的元素大小&#xff0c;更大的元素交换到右边&#xff1b;从第一组相邻元素比较…

ChatGPT-4o也参加高考了,还写了六大考卷的全部作文! |【WeThinkIn出品】

写在前面 【WeThinkIn出品】栏目专注于分享Rocky的最新思考与经验总结&#xff0c;包含但不限于技术领域。欢迎大家一起交流学习&#x1f4aa; 欢迎大家关注Rocky的公众号&#xff1a;WeThinkIn 欢迎大家关注Rocky的知乎&#xff1a;Rocky Ding AIGC算法工程师面试面经秘籍分享…

C# 关于通讯观察线程(1) -- 开启通讯线程

通讯观察线程是个有意思&#xff0c;又是非常实用的功能。 具体怎么实现呢&#xff0c;我们来看看主要过程的伪代码。对于高手这也许很简单&#xff0c;但是要用好也是需要实践到通讯的流程正确&#xff0c;同时应对好网络故障等。 先在合适的地方启动观察线程&#xff1a; …

Leetcode84 柱状图中最大的矩形

题目描述 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积 解题思路 思路一&#xff1a;暴力寻找&#xff0c;从每个位置出发&#xff0c;向左右两边扩…

Web项目部署后浏览器刷新返回Nginx的404错误对应解决方案

data: 2024/6/22 16:05:34 周六 limou3434 叠甲&#xff1a;以下文章主要是依靠我的实际编码学习中总结出来的经验之谈&#xff0c;求逻辑自洽&#xff0c;不能百分百保证正确&#xff0c;有错误、未定义、不合适的内容请尽情指出&#xff01; 文章目录 1.源头2.排错3.原因4.解…

刷代码随想录有感(114):动态规划——最少数量的零钱换整

题干&#xff1a; 代码&#xff1a; class Solution { public:int coinChange(vector<int>& coins, int amount) {vector<int>dp(amount 1, INT_MAX);dp[0] 0;for(int i 0; i < coins.size(); i){for(int j coins[i]; j < amount; j){if(dp[j - coi…

使用Vue开发页面(前置知识)

前言 在了解Vue开发之前&#xff0c;需要有基本的页面知识。 页面主要有三部分组成&#xff1a; 组件 HTML样式 CSS交互 JS 本文将以最快&#xff0c;最简单&#xff0c;最通俗的方式讲解 HTML 一个基本的HTML文件有以下格式 <!DOCTYPE html> <html lang"e…

《洛基第二季》:多元宇宙的奇幻之旅

在浩瀚无垠的影视宇宙中&#xff0c;有一部剧如璀璨星辰般耀眼&#xff0c;那就是备受期待的《洛基第二季》。该剧由贾斯汀本森和艾伦穆尔黑德执导&#xff0c;汤姆希德勒斯顿、索菲娅迪马蒂诺、欧文威尔逊等主演&#xff0c;于2023年10月上线。 这部剧延续了第一季的故事情节&…

kafka的单机、集群部署安装

kafka的单机、集群部署安装 Kafka 的部署可以分为单机部署和集群部署。以下是详细的单机和集群部署步骤。 单机部署 Kafka 单机部署 Kafka 通常用于开发和测试环境。下文中涉及相关端口,若开启防火墙则需要开放对应的端口, 以下是详细步骤: 1. 安装 Java Kafka 依赖于 …

Map 数据结构

一、概念 Set 是一种叫【字典(是一些元素的集合&#xff0c;以 [ 键&#xff0c;值 ] 的形式储存)】的数据结构。 二、 1、属性和操作方法 size 返回 Map 的元素的个数。set() 增加一个新元素&#xff0c;返回当前的 Map。get() 返回键名对象…