Multi-Raft 架构, 数据Shard分区,数据迁移

news2024/11/13 15:41:33

Raft 与 Multi Raft

PingCAP TiKV课程笔记课程链接

数据是以region(也叫Raft Group)为单位进行存储的。一个region默认会有3个副本,存在不同的TiKV Node上。副本中的一个节点为leader。所有的读写流量只走leader,leader定期向follower发送心跳,进行日志复制。

Region内部是一个kv map,按照key排序存储。相邻的region数据紧密相连。一个region的最大size为96M,一旦超出就自动存入新的region。

多个region/raft group就叫multi-raft

Raft 回顾

日志复制:

1. propose: 收到请求, 生成raft log (包含了请求内容以及编号(region#, log_index节点内部的日志编号))

2. append: 将日志存入本地的rocksdb中(专门存raft log),持久化raft log。

3. replicate:向其他follower传播,follower收到后也写入自己本地的rocksdb raft中持久化。

4. 当大多数节点都返回append成功的消息给leader后,leader就发出commited 命令,并且apply到真正的数据库上(把日志取出来,运用,即写到rocksdb kv中)。其他follower在收到commit命令后也将日志转移到自己的apply pool,之后持久化到rocksdb kv.

Leader选举

时间在raft看来是一段一段的term。term内是一段稳定的状态。

当election timeout了,进入选举。

选举成功,变为leader,发送heartbeat timeout。

选举的活锁问题

资料参考:分布式一致性协议之Raft的实现详解-腾讯云开发者社区-腾讯云

leader被选出来,某个其他节点又启动一轮选举

选主过程中,可能出现多个节点同时发起选主的情况,这样导致选票瓜分,无法选出主,在下一轮选举中依旧如此,导致系统状态无法往前推进。Raft通过随机超时解决这个“活锁”问题。

安全性

  • Raft协议中有哪些重要的安全性质?如何保证这些安全性质?

    • 选举安全性: Election Safety

      • Follower在一个任期内只投一次票, 只能投任期比自己新,日志至少要和自己一样的candidate

      • 必须获得超半数投票成为leader

    • 日志 Append-Only

      • 只有leader有 append entries请求发送权力

      • Leader只可追加log,不可覆盖log

      • 一致性检查:每条log包含(term, index)

    • 日志匹配特性 Log Matching

      • 保证日志唯一性,

      • 两个不同机器,若分别有(term, index)相同的log,则log内容必须相同

      • 两个不同机器,若分别有(term, index)相同的log,该log之前的所有entries也要相同

    • Leader 完备性 Leader Completeness

      • Leader必须具备最新提交log

      • Candidate竞选投票时会携带最新提交日志,Follower会用自己的日志和Candidate做比较,如果Follower的日志比Candidate还新,那么拒绝这次投票

      • 新:

        • 如果Term不同,选择Term值最大的

        • 如果Term相同,选择Index值最大的

    • 状态及安全性 State Machines Safety

      • 一个log被复制到超半数节点才算提交成功

      • Leader只能提交当前term的日志

成员变更

成员变更解释

任何一个节点收到了成员变更配置 ConfChange,只要把它持久化了,就可以直接生效,无需和传统日志一样需要先 commit,然后等待 apply 时应用。

保证变更前后的 quorum 存在交集,即保证了整个集群自始至终只会存在一个 leader,以此来保证正确性。Joint Consensus 通过一个中间阶段保证每一步变更的 quorum 比如存在交集

一次读写请求怎么完成

数据的写入

raftstore pool是线程池,接受用户写请求,序列化为日志之后持久化到rocksdb raft,replicate到其他节点,log转移到apply pool(也是一个线程池),最终修改rocksdb kv里的实际内容。

写入成功不代表能够读到,原因在于apply操作的滞后性。

数据的读取

复习快照隔离级别:保证读请求不会出现幻读,并发写请求只有一个生效。

有两个问题:

1. 数据一致性:考虑apply滞后

        解决方法: ReadIndex Read, 先记录最近一次提交的编号(ReadIndex),再等待最近一次apply(ApplyIndex)与ReadIndex相等。

2.读取过程中成员变更:考虑leader宕机/成员变更

        解决方法:在使用ApplyIndex读取前要先发一次心跳,如果仍然是leader就放心读

改进2的解决方法,避免多次网络操作询问自己是否是leader:

        Lease Read: 通过计算绝对不可能变更leader的时间段(上次心跳到不发心跳到election timeout)

Follower Read 分摊leader压力:

follower接到请求,问leader最新commit的log编号CommitIndex,知道了leader提交到哪了。看自己本地的ApplyIndex,如果没赶上就等,直到赶上leader的复制进度CommitIndex。好处是有可能leader提交比follower慢呢,这样follower read就能快点拿到读取结果。

范围搜索

Multi-Raft的调度

相关资料:

思路很清晰的博客系列,以后多多阅读大佬的blog

很好的学习资料: TiKV源码解析multi raft部分

Place Driver

PD的作用是region管理(负责数据副本在region中的调度)和TSO全局时钟的分配。

1. 路由功能:负责查找元数据

2. 给大量高并发的请求分配TSO全局时钟,并保证单调递增

3. 收集集群信息(比如检查热点进行region迁移)

4. 提供label功能支持高可用

数据分区算法:hash/range

Region的定义,这里使用TiKV为例:

message Region {
    optional uint64 id                  = 1 [(gogoproto.nullable) = false];
    optional bytes  start_key           = 2;
    optional bytes  end_key             = 3;
    optional RegionEpoch region_epoch   = 4;
    repeated Peer   peers               = 5;
}
message RegionEpoch {
    optional uint64 conf_ver    = 1 [(gogoproto.nullable) = false];
    optional uint64 version     = 2 [(gogoproto.nullable) = false];
}
message Peer {
    optional uint64 id          = 1 [(gogoproto.nullable) = false];
    optional uint64 store_id    = 2 [(gogoproto.nullable) = false];
}

比较重要的Raft类型

PeerState

message RaftLocalState {
    optional eraftpb.HardState hard_state        = 1;
    optional uint64 last_index                  = 2;
}
message RaftApplyState {
    optional uint64 applied_index               = 1;
    optional RaftTruncatedState truncated_state = 2;
}
enum PeerState {
    Normal       = 0;
    Applying     = 1;
    Tombstone    = 2;
}
message RegionLocalState {
    optional PeerState state        = 1;
    optional metapb.Region region   = 2;
}

Raft硬状态:1. 当前任期号 2. 已投票给候选人ID 3. 日志索引

LocalState last index指最后一个Log Index

SnapShot: 

pub enum SnapState {
    Relax,
    Generating(Receiver<Snapshot>),
    Applying(Arc<AtomicUsize>),
    ApplyAborted,
}

在Raft算法中,快照(Snapshot)的处理是对系统性能和响应时间非常重要的一个方面。因为快照操作涉及到将当前状态机的状态持久化存储,这可能包括大量的数据,因此通常是耗时的操作。为了确保快照处理不会阻塞整个Raft线程,需要采用一些策略来优化这个过程。

`PeerStorage`的快照状态管理(`SnapState`枚举)就是这种优化的一个例子。这里的策略包括:

- **Relax**: 表示没有快照操作正在进行,系统处于正常状态。

- **Generating(Receiver<Snapshot>)**: 表示快照正在生成中。此状态使用`Receiver<Snapshot>`来异步接收生成的快照数据。这允许快照生成过程在后台进行,不会阻塞主Raft进程。

- **Applying(Arc<AtomicUsize>)**: 表示快照正在应用中。快照应用是一个将快照数据加载到状态机中的过程,这同样可能是一个耗时操作。通过使用`Arc<AtomicUsize>`,可以在不同线程中安全地共享和管理快照的应用状态,同时允许这个过程异步执行。

- **ApplyAborted**: 表示快照应用过程被中断或放弃。这可能发生在系统决定放弃当前的快照应用过程,可能是因为接收到了一个更新的快照,或者因为其他原因需要停止当前的快照应用。

Peer

Peer里完成propose, ready等操作

command类型:

1. 只读,如果leader在lease有效期内,就能直接提供local read。

2. transfer read: 是否follower有足够新的log

3. Change Peer调用RawNode

propose之前会将callback(回调)存到PendingCmd里面,以便后续完成propose返回客户端

handle_raft_ready:负责将entries写入storage,发送messages, apply committed_entries以及advance

Multi Raft

对于一个store需要管理多个region副本

region_peers: HashMap<u64, Peer>

RawNode tick函数驱动Raft,需要注册一个Raft Tick

tick回调回进行 on_raft_ready的处理:

  1. Store 会遍历所有的 ready Peers,调用 handle_raft_ready_append,我们会使用一个 WriteBatch 来处理所有的 ready append 数据,同时保存相关的结果。
  2. 如果 WriteBatch 成功,会依次调用 post_raft_ready_append,这里主要用来处理Follower 的消息发送(Leader 的消息已经在 handle_raft_ready_append 里面完成)。
  3. 然后,Store 会依次调用 handle_raft_ready_apply,apply 相关 committed entries,然后调用 on_ready_result 处理最后的结果。

Server: 

对网络IO的处理,TiKV网络层,封装 message (header + body),编码

流程和socket网络接口有点像:

1. bind 端口,生成一个用于交互的对象

2. 使用TcpStream和客户端交互

3. TcpStream处理回调

对于受到的message,都有对应的处理线程

模模糊糊理解了一些!继续学习

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

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

相关文章

谷歌应用上架,如何选择IP?

在讨论IP对于谷歌上架的重要性或影响时&#xff0c;需要明确一点&#xff1a;开发者账号质量可以直接影响上架成功率&#xff0c;而IP是影响账号质量的重要因素之一。因此&#xff0c;IP对于谷歌上架的重要性&#xff0c;不言而喻。 我们都清楚&#xff0c;谷歌是不允许一个用户…

vue+element 前端实现增删查改+分页,不调用后端

前端实现增删查改分页&#xff0c;不调用后端。 大概就是对数组内的数据进行增删查改分页 没调什么样式&#xff0c;不想写后端&#xff0c;当做练习 <template><div><!-- 查询 --><el-form :inline"true" :model"formQuery">&l…

PHP的IntlChar类:处理Unicode字符的强大工具

PHP的IntlChar类&#xff1a;处理Unicode字符的强大工具 在处理多语言和国际化应用程序时&#xff0c;Unicode字符的解码是必不可少的一环。PHP的IntlChar类为我们提供了强大的工具来解码Unicode字符。本文将深入探讨PHP的IntlChar类&#xff0c;介绍其功能、用法和优势&#x…

鸿蒙:@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

在实际应用开发中&#xff0c;应用会根据开发需要&#xff0c;封装自己的数据模型。对于多层嵌套的情况&#xff0c;比如二维数组&#xff0c;或者数组项class&#xff0c;或者class的属性是class&#xff0c;他们的第二层的属性变化是无法观察到的。这就引出了Observed/Object…

基于python+vue的幼儿园管理系统flask-django-php-nodejs

随着信息时代的来临&#xff0c;过去的传统管理方式缺点逐渐暴露&#xff0c;对过去的传统管理方式的缺点进行分析&#xff0c;采取计算机方式构建幼儿园管理系统。本文通过课题背景、课题目的及意义相关技术&#xff0c;提出了一种活动信息、课程信息、菜谱信息、通知公告、家…

视频批量爬虫下载工具|可导出视频分享链接|抖音视频提取软件

便捷的视频批量爬虫软件操作指南 抖音视频下载界面图解 主要功能&#xff1a; 关键词批量提取视频和单独视频提取&#xff0c;提取后下载功能。 功能解析&#xff1a; 1. 关键词批量采集视频的解析 对特定关键词进行搜索和视频提取&#xff0c;例如输入“汽车配件”&#x…

基于深度学习的心律异常分类系统设计——算法设计

基于深度学习的心律异常分类系统——算法设计 第一章 研究背景算法流程本文研究内容 第二章 心电信号分类理论基础心电信号产生机理MIT-BIH 心律失常数据库 第三章 心电信号预处理心电信号噪声来源与特点基线漂移工频干扰肌电干扰 心电信号读取与加噪基于小波阈值去噪技术的应用…

LeetCode刷题记录:(13)N皇后(难题不难)

leetcode传送通道 传说中的N皇后&#xff0c;不难&#xff0c;进来了就看完吧 注释序号代表鄙人写代码的顺序和思考逻辑&#xff0c;供参考 class Solution {// 1.定义结果数组List<List<String>> result new ArrayList<>();public List<List<String&…

.NET EF Core(Entity Framework Core)

文章目录 EF Core与其他ORM比较EF Core与EF比较Migration数据库迁移反向工程Migrations其他命令修改表结构 EF Core操作数据库插入数据查询数据修改、删除其他数据库 EF Core实体的配置Data Annotation配置方式Fluent API配置方式Fluent API 通过代码查看EF Core的sql语句方法1…

分布式链上随机数和keyless account

1. 引言 相关论文见&#xff1a; Aptos团队2024年论文 Distributed Randomness using Weighted VRFs 相关代码实现见&#xff1a; https://github.com/aptos-labs/aptos-core&#xff08;Rust&#xff09; 在链中生成和集成共享随机数&#xff0c;以扩展应用和强化安全。该…

基于python+vue体育场馆设施预约系统flask-django-php-nodejs

时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;体育场馆设施预约系统当然不能排除在外。整体设计包括系统的功能、系统总体结构、系统数据结构和对系统安全性进行设计&#xff1b;最后要对系统…

Tomcat启动报错 因为在清除过期缓存条目后可用空间仍不足

在Tomcat部署路径下的./conf/context.xml配置文件的标签内添加如下内容&#xff1a; <Resources cachingAllowed"true" cacheMaxSize"100000" />

图解 LFU 缓存淘汰算法以及在 Redis 中的应用(附带个人完整代码实现)

文章目录 LFU 算法理论介绍算法实现数据结构查询操作插入/更新操作 Redis 缓存淘汰算法缓存污染难题Redis LFU缓存淘汰策略 本篇博客的主要内容&#xff1a; 以图解的方式&#xff0c;介绍 LFU 算法的一种实现&#xff1b;介绍 LFU 算法在 Redis 中的应用。 LFU 算法 理论介…

Docker 搭建私人仓库

docker 搭建私人仓库有下面几种方式&#xff1a; 1、docker hub 官方私人镜像仓库2、本地私有仓库 官方私人镜像仓库搭建很简单(就是需要有魔法&#xff0c;否则就异步到第二种方法吧)&#xff0c;只需要 login、pull、tag、push 几种命令就完事了。而本地私人镜像仓库则比较麻…

探究BufferedOutputStream的奥秘

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java IO相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

[音视频学习笔记]六、自制音视频播放器Part1 -新版本ffmpeg,Qt +VS2022,都什么年代了还在写传统播放器?

前言 参考了雷神的自制播放器项目&#xff0c;100行代码实现最简单的基于FFMPEGSDL的视频播放器&#xff08;SDL1.x&#xff09; 不过老版本的代码参考意义不大了&#xff0c;我现在准备使用Qt VS2022 FFmpeg59重写这部分代码&#xff0c;具体的代码仓库如下&#xff1a; …

本地化语音识别、视频翻译和配音工具:赋能音频和视频内容处理

随着人工智能技术的飞速发展&#xff0c;语音识别、视频翻译和配音等任务已经变得更加容易和高效。然而&#xff0c;许多现有的工具和服务仍然依赖于互联网连接&#xff0c;这可能会导致延迟、隐私问题和成本问题。为了克服这些限制&#xff0c;我们介绍了一种本地化、离线运行…

RCE漏洞

RCE漏洞概述 远程命令执行/代码注入漏洞&#xff0c;英文全称为Reote Code/CommandExecute&#xff0c;简称RCE漏洞。PHPJava等Web开发语言包含命令执行和代码执行函数,攻击者可以直接向后台服务器远程执行操作系统命今或者运行注入代码&#xff0c;进而获取系统信息、控制后台…

社交媒体的未来:探讨Facebook的发展趋势

引言 在数字化时代&#xff0c;社交媒体已经成为人们日常生活中不可或缺的一部分。作为全球最大的社交媒体平台之一&#xff0c;Facebook一直在不断地追求创新&#xff0c;以满足用户日益增长的需求和适应科技发展的变革。本文将探讨Facebook在未来发展中可能面临的挑战和应对…

10W字解析 SpringBoot技术内幕文档,实战+原理齐飞,spring事务实现原理面试

第3章&#xff0c;Spring Boot构造流程源码分析&#xff0c;Spring Boot的启动非常简单&#xff0c;只需执行一个简单的main方法即可&#xff0c;但在整个main方法中&#xff0c;Spring Boot都做了些什么呢&#xff1f;本章会为大家详细讲解Spring Boot启动过程中所涉及的源代码…