TiDB存储引擎TiKV揭秘

目录

一、TiKV 介绍

二、RocksDB

三、TiKV 与 RocksDB 架构

        3.1 用户数据保存

        3.2 TiKV 中 Region


一、TiKV 介绍

        TiKV 是一个分布式事务型的键值数据库,提供了满足 ACID 约束的分布式事务接口,并且通过 Raft 协议保证了多副本数据一致性以及高可用。TiKV 作为 TiDB 的存储层,为用户写入 TiDB 的数据提供了持久化以及读写服务,同时还存储了 TiDB 的统计信息数据。

        与传统的整节点备份不同,TiKV 参考了 Spanner 设计了 multi-raft-group 的副本机制。将数据按照 key 的范围划分成大致相等的切片(region),每一个切片会有多个副本(默认3个),其中一个副本是 leader,提供读写服务。TiKV 通过 PD 对这些 Region 以及副本进行调度,以保证数据和读写负载都均匀的分散在各个 TiKV 上,这样的设计保证了整个集群资源的充分利用并且可以随着机器数量的增加水平扩展。

         任何持久化的存储引擎,数据终归要保存在磁盘上,TiKV 也不例外。但是 TiKV 没有选择直接向磁盘上写数据,而是把数据保存在 RocksDB 中,具体的数据落地由 RocksDB 负责。

二、RocksDB

        TiKV 为何选择 RocksDB 来存储数据呢?

        这个选择的原因是开发一个单机存储引擎工作量很大,特别是要做一个高性能的单机引擎,需要做各种细致的优化,而 RocksDB 是由 Facebook 开源的一个非常优秀的单机 KV 存储引擎,可以满足 TiKV 对单机引擎的各种要求。这里可以简单的认为 RocksDB 是一个单机的持久化 Key-Value Map。

        RocksDB 是由 Facebook 基于 LevelDB 开发的一款提供键值存储与读写功能的 LSM-tree 架构引擎。用户写入的键值对会先写入磁盘上的 WAL(Write Ahead Log),然后再写入内存中的跳表。LSM-tree 由于将用户的随机修改(插入)转化为对 WAL 的顺序写,因此具有比 B 树类存储引擎更高的写吞吐。

        内存中的数据达到一定阈值后,会刷到磁盘上生成 SST 文件(Sorted String Table),SST 又分为多层(默认最多6层),每一层的数据达到一定阈值后会挑选一部分 SST 合并到下一层,每一层的数据是下一层的10倍(因此 90% 的数据存储在最后一层)。      

        操作流程如下:

  1. 新写入的数据首先被写入 memtable,而非直接写入磁盘。这种设计极大地减少了磁盘 I/O,降低了写入延迟,尤其适合需要频繁写入和快速响应的应用场景。
  2. memtable 有固定的内存容量限制,由参数 write_buffer_size 控制。当 memtable 的大小接近或达到这一限制时,RocksDB 会触发以下动作:
    1. 转换为 Immutable Memtable:当前 memtable 被标记为不可变(Immutable),新的写入操作会被导向到一个新的 memtable。
    2. Flush 到 SSTable:后台线程将 Immutable Memtable 中的数据序列化并写入磁盘,形成一个 SSTable(Sorted String Table),这是一个持久化的、经过排序的键值对集合。
    3. WAL 更新:在 memtable 数据写入磁盘的过程中,RocksDB 会维护 Write Ahead Log (WAL, 也称预写日志),确保即使在崩溃或意外关机的情况下,尚未持久化的 memtable 数据也能通过回放 WAL 重建。
  3. RocksDB 支持多列族(Column Family),每个列族都有自己独立的 memtable。这意味着不同的数据集可以有不同的存储配置和访问模式,进一步提升了存储灵活性和查询效率。

三、TiKV 与 RocksDB 架构

        RocksDB作为TiKV的核心存储引擎,用于存储Raft日志以及用户数据。每个TiKV实例中有两个RocksDB,一个用于存储Raft日志(通常被称为 raftdb),另一个用于存储用户数据以及MVCC信息(通常被称为 kvdb)。

         为什么需要两个 RocksDB呢?

        在 TiKV 中,使用两个 RocksDB 实例对应的是其内部的存储结构设计。具体来说,TiKV 将数据分为两部分存储:KV 数据(键值对数据)和 Raft Log 数据,分别使用两个独立的 RocksDB 实例进行管理。这种设计的目的是为了清晰分离不同性质的数据,并针对性地进行优化,确保系统的高效运行。

        将二者分离的主要目的如下:

  • 隔离负载:不同类型的操作,有不同的性能要求和访问模式,分开存储可以避免互相干扰,提高整体系统的稳定性和效率。
  • 精细化管理:针对各自的特点进行定制化的配置和优化,如调整压缩算法、缓存策略、自如放大控制等,以适应各自的工作负载。
  • 简化故障恢复:在节点故障或数据迁移时,可以独立地处理 KV 数据和 Raft Log,简化恢复流程,提高恢复速度。

        3.1 用户数据保存

        上面提到 RocksDB 支持多列族(Column Family),TiKV 使用 RocksDB 保存数据时使用了四个列族,分别是:raft、lock、default和write。

        Raft 列族:用于存储各个 Region 的元信息。仅占极少空间,可以无需关注。

        lock 列族:用于存储悲观事务的悲观锁以及分布式事务的一阶段 Prewrite 锁。当用户的事务提交之后,lock Column Family 中对应的数据会很快删除掉,因此大部分情况下,lock Column Family 中的数据也很少。如果 lock Column Family  中数据大量增加,说明有大量事务等待提交,系统出现了故障或 bug。

        write 列族:用于存储用户真实写入的数据以及 MVCC 信息,当用户写入了一行数据时,如果改行长度小于 255 字节,那么会被存储 write 列中,否则的话该行会被存入 default 列中。由于 TiDB 的非 unique 索引存储的 value 为空,unique 索引存储的 value 为主键索引,因此二级索引只会占用 write Column Family 的空间。

        default 列族:用于存储超过 255 字节长度的数据。

        3.2 TiKV 中 Region

        为了实现存储的水平扩展,数据将被分散在多台机器上。对于一个 KV 系统,将数据分散在多台机器上有两种比较典型的方案:

  • Hash:按照 Key 做 Hash,根据 hash 值选择对应的存储节点
  • Range:按照 Key 分 Range,某一段连续的 Key 都保存在一个存储节点上

        TiKV 选择了第二种方式,将整个 Key-Value 空间分成很多段,每一段是一系列连续的 Key,将每一段叫做一个 Region,可以用[StartKey, EndKey)这样一个左闭右开区间来描述。每个Region 中保存的数据量默认维持在 96MiB(可通过配置修改)。

        数据按照 Key 切分成很多 Region,每个 Region 的数据只会保存在一个节点上面(暂不考虑多副本)。TiDB 系统会有一个组件 (PD) 来负责将 Region 尽可能均匀的散布在集群中所有的节点上,这样一方面实现了存储容量的水平扩展(增加新的节点后,会自动将其他节点上的 Region 调度过来),另一方面也实现了负载均衡(不会出现某个节点有很多数据,其他节点上没什么数据的情况)。同时为了保证上层客户端能够访问所需要的数据,系统中也会有一个组件 (PD) 记录 Region 在节点上面的分布情况,也就是通过任意一个 Key 就能查询到这个 Key 在哪个 Region 中,以及这个 Region 目前在哪个节点上(即 Key 的位置路由信息)。

        TiKV 是以 Region 为单位做数据的复制,也就是一个 Region 的数据会保存多个副本,TiKV 将每一个副本叫做一个 Replica。Replica 之间是通过 Raft 来保持数据的一致,一个 Region 的多个 Replica 会保存在不同的节点上,构成一个 Raft Group。其中一个 Replica 会作为这个 Group 的 Leader,其他的 Replica 作为 Follower。默认情况下,所有的读和写都是通过 Leader 进行,读操作在 Leader 上即可完成,而写操作再由 Leader 复制给 Follower。

        以 Region 为单位做数据的分散和复制,TiKV 就成为了一个分布式的具备一定容灾能力的 KeyValue 系统,不用再担心数据存不下,或者是磁盘故障丢失数据的问题。 

往期经典推荐

TiDB 数据库调度(PD)揭秘-CSDN博客

深入浅出 TiDB MVCC:揭秘分布式数据库中的多版本并发控制-CSDN博客

深入浅出 Drools 规则引擎-CSDN博客

MySQL文件系统解密:binlog、redolog与undolog如何守护数据安全与一致性_mysqlbin 解密-CSDN博客

走进 Mybatis 内核世界:理解原理,释放更多生产力-CSDN博客

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

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

相关文章

APP看广告变现,实现躺赚!!

想实现躺赚吗?开发一款APP,轻松对接广告联盟,收益丰厚! 朋友们,你们是否想过如何让自己的手机变得更有价值?现在,有一款APP能让你轻松实现躺赚!只需简单注册企业级营业执照和开通对…

Vue3项目中快速引入ElementUI框架

ElementUI介绍 ElementUI是一个强大的PC端UI组件框架,它不依赖于vue,但是却是当前和vue配合做项目开发的一个比较好的ui框架,其包含了布局(layout),容器(container)等各类组件,基本上…

算法学习——LeetCode力扣补充篇9(912. 排序数组、21. 合并两个有序链表、33. 搜索旋转排序数组、103. 二叉树的锯齿形层序遍历)

算法学习——LeetCode力扣补充篇9 912. 排序数组 912. 排序数组 - 力扣(LeetCode) 描述 给你一个整数数组 nums,请你将该数组升序排列。 示例 示例 1: 输入:nums [5,2,3,1] 输出:[1,2,3,5] 示例 2&…

基于ubuntu22.04系统安装nvidia A100驱动与NVLink启用

1、官方仓库 针对驱动包下载认准nvidia官网 dpkg -i nvidia-driver-local-repo-ubuntu2204-550.54.15_1.0-1_amd64.deb apt update apt search nvidia-driver-5502、安装 根据步骤1apt search nvidia-driver-550查出版本:此驱动包封在nvidia-driver-local-repo-ub…

Qt | 事件第二节

Qt | 事件第一节书接上回 四、事件的接受和忽略 1、事件可以被接受或忽略,被接受的事件不会再传递给其他对象,被忽略的事件会被传递给其他对象处理,或者该事件被丢弃(即没有对象处理该事件) 2、使用 QEvent::accept()函数表示接受一个事件,使用 QEvent::ignore()函数表示…

快速排序题目SelectK问题

力扣75.颜色分类 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 必须在不使用库内置的 sor…

普发Pfeiffer TPG252 TPG256A SingleGaugeTPG261-262使用说明手侧

普发Pfeiffer TPG252 TPG256A SingleGaugeTPG261-262使用说明手侧

卷积神经网络的结构组成与解释(详细介绍)

文章目录 前言 1、卷积层 2、激活层 3、BN层 4、池化层 5、FC层(全连接层) 6、损失层 7、Dropout层 8、优化器 9、学习率 10、卷积神经网络的常见结构 前言 卷积神经网络是以卷积层为主的深层网络结构,网络结构包括有卷积层、激活层、BN层、…

模板初阶的学习

目录: 一:泛型模板 二:函数模板 三:类模板 1:泛型模板 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。 以交换函数为列进行讲解: void Swap(…

微服务中的重要模块

为什么要有微服务? 微服务提高开发效能,避免业务的重复理解,代码重复开发,增加开发效能和代码复用性。 在实际的工作中许多不同的业务有着共同的功能需求,如果我们每遇到一次这种需求就重新去理解构建一次的话会花费大…

【深度学习】【机器学习】用神经网络进行入侵检测,NSL-KDD数据集,基于机器学习(深度学习)判断网络入侵,网络攻击,流量异常【3】

之前用NSL-KDD数据集做入侵检测的项目是: 【1】https://qq742971636.blog.csdn.net/article/details/137082925 【2】https://qq742971636.blog.csdn.net/article/details/137170933 有人问我是不是可以改代码,我说可以。 训练 我将NSL_KDD_Final_1.i…

Day42:动态规划 LeedCode 01背包 416. 分割等和子集

01背包 1.确定dp数组以及下标的含义 dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。 那么可以有两个方向推出来dp[i][j] 2.确定递推公式 不放物品i:由dp[i - 1][j]推出,即背…

十大排序——9.桶排序

这篇文章我们来介绍一下桶排序 目录 1.介绍 2.代码实现 3.总结与思考 1.介绍 桶排序和计数排序一样,都不是基于比较进行排序的。 下面通过一个例子来理解一下桶排序吧。 首先,给你一个无序数组[ 20,18,28,66,25,31,67,30 ],然后&#…

Maven POM元素解析(二)

一、parent <parent>元素包含定位此项目将从中继承的父项目所需的信息。注意&#xff1a;此元素的子元素不是插值的&#xff0c;必须作为文字值给定。 ElementTypeDescriptiongroupIdString要从中继承的父项目的组id。artifactIdString要从中继承的父项目的项目id。ver…

【Entity Framework】你知道如何处理无键实体吗

【Entity Framework】你知道如何处理无键实体吗 文章目录 【Entity Framework】你知道如何处理无键实体吗一、概述二、定义无键实体类型数据注释 三、无键实体类型特征四、无键实体使用场景五、无键实体使用场景六、无键使用示例6.1 定义一个简单的Blog和Post模型&#xff1a;6…

高分二号卫星(GF-2):中国遥感科技的新高度

​高分二号卫星&#xff08;GF-2&#xff09;是中国在高分辨率地球观测领域的重要成就&#xff0c;其引入了先进的成像技术和灵活的数据获取模式&#xff0c;为地球资源监测、环境保护、城市规划等领域提供了强大的数据支持。本文将深入介绍高分二号卫星的技术特点、成像能力以…

Day 27 39. 组合总和 40.组合总和II 131.分割回文串

组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明&#xff1a; 所有数字&#xff08;包括 target&#xff09;都是正整数。解集不能…

自定义类型: 结构体 (详解)

本文索引 一. 结构体类型的声明1. 结构体的声明和初始化2. 结构体的特殊声明3. 结构体的自引用 二. 结构体内存对齐1. 对齐规则2. 为啥存在对齐?3. 修改默认对齐值 三. 结构体传参四. 结构体实现位段1. 什么是位段?2. 位段的内存分配3. 位段的应用4. 位段的注意事项 ​ 前言:…

什么是上位机?入门指南

什么是上位机&#xff1f; 上位机&#xff08;SCADA&#xff0c;Supervisory Control and Data Acquisition&#xff09;是一种软件系统&#xff0c;用于监控和控制工业过程中的设备。它通常与传感器、执行器和其他自动化设备一起工作&#xff0c;以实时地监视过程状态、收集数…

【精读文献】Scientific data|2017-2021年中国10米玉米农田变化制图

论文名称&#xff1a;Mapping annual 10-m maize cropland changes in China during 2017–2021 第一作者及通讯作者&#xff1a;Xingang Li, Ying Qu 第一作者单位及通讯作者单位&#xff1a;北京师范大学地理学部 文章发表期刊&#xff1a;《Scientific data》&#xff08…