怎么进行SOFAJRaft 实现原理的分析

发布时间:2021-12-03 17:10:45 作者:柒染
来源:亿速云 阅读:136

今天就跟大家聊聊有关怎么进行SOFAJRaft 实现原理的分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

从 Log 日志存储 LogStorage、Meta 元信息存储 RaftMetaStorage 以及 Snapshot 快照存储 SnapshotStorage 三个方面详述 SOFAJRaft 存储模块实现细节,直观刻画 SOFAJRaft Server 节点 Node 之间存储日志、Raft 配置和镜像流程。

SOFAStack
Scalable Open Financial Architecture Stack
是蚂蚁金服自主研发的金融级分布式架构,包含了构建金融级云原生架构所需的各个组件,是在金融场景里锤炼出来的最佳实践。

SOFAJRaft 是一个基于 Raft 一致性算法的生产级高性能 Java 实现,支持 MULTI-RAFT-GROUP,适用于高负载低延迟的场景。

前言

SOFAJRaft 是一个基于 Raft 一致性算法的生产级高性能 Java 实现,支持 MULTI-RAFT-GROUP,适用于高负载低延迟的场景

SOFAJRaft 存储模块分为:

  1. Log 存储记录 Raft 配置变更和用户提交任务日志;

  2. Meta 存储即元信息存储记录 Raft 实现的内部状态;

  3. Snapshot 存储用于存放用户的状态机 Snapshot 及元信息。

本文将围绕日志存储,元信息存储以及快照存储等方面剖析 SOFAJRaft 存储模块原理,阐述如何解决 Raft 协议存储问题以及存储模块实现:

怎么进行SOFAJRaft 实现原理的分析cdn.nlark.com/yuque/0/2019/png/156670/1556492476096-9300c652-29e2-4698-b5ef-435c294e00c6.png">

日志存储

Log 存储,记录 Raft 配置变更和用户提交任务的日志,把日志从 Leader 复制到其他节点上面。

LogStorage 存储实现

LogStorage 日志存储实现,定义 Raft 分组节点 Node 的 Log 存储模块核心 API 接口包括:

Log Index 提交到 Raft Group 中的任务序列化为日志存储,每条日志一个编号,在整个 Raft Group 内单调递增并复制到每个 Raft 节点。LogStorage 日志存储实现接口定义入口:

com.alipay.sofa.jraft.storage.LogStorage

RocksDBLogStorage 基于 RocksDB 实现

Log Structured Merge Tree 简称 LSM ,把一颗大树拆分成 N 棵小树,数据首先写入内存,内存里构建一颗有序小树,随着小树越来越大,内存的小树 Flush 到磁盘,磁盘中的树定期做合并操作合并成一棵大树以优化读性能,通过把磁盘的随机写转化为顺序写提高写性能,RocksDB 就是基于 LSM-Tree 数据结构使用 C++ 编写的嵌入式 KV 存储引擎,其键值均允许使用二进制流。RocksDB 按顺序组织所有数据,通用操作包括 get(key), put(key), delete(Key) 以及 newIterator()。RocksDB 有三种基本的数据结构:memtable,sstfile 以及 logfile。memtable 是一种内存数据结构--所有写入请求都会进入 memtable,然后选择性进入 logfile。logfile 是一种有序写存储结构,当 memtable 被填满的时候被刷到 sstfile 文件并存储起来,然后相关的 logfile 在之后被安全地删除。sstfile 内的数据都是排序好的,以便于根据 key 快速搜索。

LogStorage 默认实现 RocksDBLogStorage 是基于 RocksDB 存储日志,初始化日志存储 StorageFactory 根据 Raft节点日志存储路径和 Raft 内部实现是否调用 fsync 配置默认创建 RocksDBLogStorage 日志存储。基于 RocksDB 存储实现 RocksDBLogStorage 核心操作包括:

com.alipay.sofa.jraft.storage.RocksDBLogStorage

LogManager 存储调用

日志管理器 LogManager 负责调用 Log 日志存储 LogStorage,对 LogStorage 调用进行缓存管理、批量提交、检查优化。Raft 分组节点 Node 初始化/启动时初始化日志存储 StorageFactory 构建日志管理器 LogManager,基于日志存储 LogStorage、配置管理器 ConfigurationManager、有限状态机调用者 FSMCaller、节点性能监控 NodeMetrics 等 LogManagerOptions 配置选项实例化 LogManager。根据 Raft 节点 Disruptor Buffer 大小配置生成稳定状态回调 StableClosure 事件 Disruptor 队列,设置稳定状态回调 StableClosure 事件处理器 StableClosureEventHandler 处理队列事件,其中 StableClosureEventHandler 处理器事件触发的时候判断任务回调 StableClosure 的 Log Entries 是否为空,如果任务回调的 Log Entries 为非空需积攒日志条目批量 Flush,空则检查 StableClosureEvent 事件类型并且调用底层存储 LogStorage#appendEntries(entries) 批量提交日志写入 RocksDB,当事件类型为SHUTDOWN、RESET、TRUNCATE_PREFIX、TRUNCATE_SUFFIX、LAST_LOG_ID 时调用底层日志存储 LogStorage 进行指定事件回调 ResetClosure、TruncatePrefixClosure、TruncateSuffixClosure、LastLogIdClosure 处理。

当 Client 向 SOFAJRaft 发送命令之后,Raft 分组节点 Node 的日志管理器 LogManager 首先将命令以 Log 的形式存储到本地,调用 appendEntries(entries, done) 方法检查 Node 节点当前为 Leader 并且 Entries 来源于用户未知分配到的正确日志索引时需要分配索引给添加的日志 Entries ,而当前为 Follower 时并且 Entries 来源于 Leader 必须检查以及解决本地日志和  Entries 之间的冲突。接着遍历日志条目 Log Entries 检查类型是否为配置变更,配置管理器 ConfigurationManager 缓存配置变更 Entry,将现有日志条目 Entries 添加到 logsInMemory 进行缓存,稳定状态回调 StableClosure 设置需要存储的日志,发布 OTHER 类型事件到稳定状态回调 StableClosure 事件队列,触发稳定状态回调 StableClosure 事件处理器 StableClosureEventHandler 处理该事件,处理器获取任务回调的 Log Entries 把日志条目积累到内存中以便后续统一批量 Flush,通过 appendToStorage(toAppend) 操作调用底层LogStorage 存储日志 Entries。同时 Replicator 把此条 Log 复制给其他的 Node 实现并发的日志复制,当 Node 接收集群中半数以上的 Node 返回的“复制成功”的响应将这条 Log 以及之前的 Log 有序的发送至状态机里面执行。

怎么进行SOFAJRaft 实现原理的分析

LogManager 调用日志存储 LogStorage 实现逻辑 

元信息存储

Metadata 存储即元信息存储,用来存储记录 Raft 实现的内部状态,譬如当前任期 Term、投票给哪个 PeerId 节点等信息。

RaftMetaStorage 存储实现

RaftMetaStorage 元信息存储实现,定义 Raft 元数据的 Metadata 存储模块核心 API 接口包括:

Raft 内部状态任期 Term 是在整个 Raft Group 里单调递增的 long 数字,用来表示一轮投票的编号,其中成功选举出来的 Leader 对应的 Term 称为 Leader Term,Leader 没有发生变更期间提交的日志都有相同的 Term 编号。PeerId 表示 Raft 协议的参与者(Leader/Follower/Candidate etc.), 由三元素组成: ip:port:index,其中 ip 是节点的 IP, port 是端口, index 表示同一个端口的序列号。RaftMetaStorage 元信息存储实现接口定义入口:

com.alipay.sofa.jraft.storage.RaftMetaStorage

LocalRaftMetaStorage 基于 ProtoBuf 实现

Protocol Buffers 是一种轻便高效的结构化数据存储格式,用于结构化数据串行化或者说序列化,适合做数据存储或 RPC 数据交换格式,用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。用户在 .proto 文件定义 Protocol Buffer 的 Message 类型指定需要序列化的数据结构,每一个 Message  都是一个小的信息逻辑单元包含一系列的键值对,每种类型的 Message 涵盖一个或者多个唯一编码字段,每个字段由名称和值类型组成,允许 Message 定义可选字段 Optional Fields、必须字段 Required Fields、可重复字段 Repeated Fields。

RaftMetaStorage 默认实现 LocalRaftMetaStorage 是基于 ProtoBuf  Message 本地存储 Raft 元数据,初始化元信息存储 StorageFactory 根据 Raft 元信息存储路径、 Raft 内部配置以及 Node 节点监控默认创建 LocalRaftMetaStorage 元信息存储。基于 ProtoBuf 存储实现 LocalRaftMetaStorage 主要操作包括:

怎么进行SOFAJRaft 实现原理的分析

LocalRaftMetaStorage 基于 ProtoBuf 本地存储 Raft 元信息实现入口:

com.alipay.sofa.jraft.storage.impl.LocalRaftMetaStorage

快照存储

当 Raft 节点 Node 重启时,内存中状态机的状态数据丢失,触发启动过程重新存放日志存储 LogStorage 的所有日志重建整个状态机实例,此种场景会导致两个问题:


因此通过引入 Snapshot 机制来解决此三个问题,所谓快照 Snapshot 即对数据当前值的记录,是为当前状态机的最新状态构建"镜像"单独保存,保存成功删除此时刻之前的日志减少日志存储占用;启动的时候直接加载最新的 Snapshot 镜像,然后重放在此之后的日志即可,如果 Snapshot 间隔合理,整个重放到状态机过程较快,加速启动过程。最后新节点的加入先从 Leader 拷贝最新的 Snapshot 安装到本地状态机,然后只要拷贝后续的日志即可,能够快速跟上整个 Raft Group 的进度。Leader 生成快照有几个作用:

Snapshot 存储,用于存储用户的状态机 Snapshot 及元信息:

SnapshotStorage 存储实现

SnapshotStorage 快照存储实现,定义 Raft 状态机的 Snapshot 存储模块核心 API 接口包括:

LocalSnapshotStorage 基于本地文件实现

SnapshotStorage 默认实现 LocalSnapshotStorage 是基于本地文件存储 Raft 状态机镜像,初始化元快照存储 StorageFactory 根据 Raft 镜像快照存储路径和 Raft 配置信息默认创建 LocalSnapshotStorage 快照存储。基于本地文件存储实现 LocalSnapshotStorage 主要方法包括:

SnapshotExecutor 存储管理

快照执行器 SnapshotExecutor 负责 Raft 状态机 Snapshot 存储、Leader 远程安装快照、复制镜像 Snapshot 文件,包括两大核心操作:状态机快照 doSnapshot(done) 和安装快照 installSnapshot(request, response, done)。StateMachine 快照 doSnapshot(done) 获取基于临时镜像 temp 文件路径的 Snapshot 存储快照编写器 LocalSnapshotWriter,加载 __raft_snapshot_meta 快照元数据文件初始化编写器;构建保存镜像回调SaveSnapshotDone 提供 FSMCaller 调用 StateMachine 的状态转换发布 SNAPSHOT_SAVE 类型任务事件到 Disruptor 队列,通过 Ring Buffer 方式触发申请任务处理器 ApplyTaskHandler 运行快照保存任务,调用 onSnapshotSave() 方法存储各种类型状态机快照。远程安装快照 installSnapshot(request, response, done) 按照安装镜像请求响应以及快照原信息创建并且注册快照下载作业 DownloadingSnapshot,加载快照下载 DownloadingSnapshot 获取当前快照拷贝器的阅读器 SnapshotReader,构建安装镜像回调 InstallSnapshotDone 分配 FSMCaller 调用 StateMachine 的状态转换发布 SNAPSHOT_LOAD 类型任务事件到 Disruptor 队列,也是通过 Ring Buffer 触发申请任务处理器 ApplyTaskHandler 执行快照安装任务,调用 onSnapshotLoad() 操作加载各种类型状态机快照。

SnapshotExecutor 状态机快照和远程安装镜像实现逻辑:

怎么进行SOFAJRaft 实现原理的分析

看完上述内容,你们对怎么进行SOFAJRaft 实现原理的分析有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

推荐阅读:
  1. 如何进行SylixOS普通定时器精度分析
  2. 如何进行RocketMQ事务消息实现

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

sofajraft

上一篇:ADO.NET怎么通过拖拽形式实现数据库连接

下一篇:ADO.NET对象操作步骤是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》