RocksDB 概述

1. 简介

RocksDB最初在Facebook作为各种存储介质上的服务器工作负载的存储引擎,最初专注于快速存储(尤其是闪存)。它是一个C++库,用于存储键和值,它们是任意大小的字节流。它支持点查找和范围扫描,并提供不同类型的 ACID 保证。
在可定制性和自我适应性之间取得了平衡。RocksDB 具有高度灵活的配置设置,可以调整为在各种生产环境中运行,包括 SSD、硬盘、RAMF 或远程存储。它支持各种压缩算法和用于生产支持和调试的良好工具。另一方面,还努力限制旋钮的数量,提供足够好的开箱即用性能,并在适用的情况下使用一些自适应算法。
RocksDB借鉴了开源leveldb项目中的重要代码以及Apache HBase的想法。最初的代码是从开源 leveldb 1.5 分叉而来的。它还建立在RocksDB之前在Facebook开发的代码和想法之上。

假设和目标

性能:

RocksDB 的主要设计点是,它应该具有快速存储和服务器工作负载的性能。它应该支持高效的点查找以及范围扫描。它应该可配置为支持高随机读取工作负载、高更新工作负载或两者的组合。其体系结构应支持针对不同工作负载和硬件轻松调整权衡。

产品支持:

RocksDB 的设计方式应使其内置支持有助于在生产环境中进行部署和调试的工具和实用程序。如果存储引擎还不能自动适应应用程序和硬件,我们将提供一些参数来允许用户调整性能。

兼容性:

此软件的较新版本应向后兼容,以便在升级到较新版本的 RocksDB 时无需更改现有应用程序。除非使用新提供的功能,否则现有应用程序也应该能够恢复到最近的旧版本。请参阅 RocksDB 不同版本之间的兼容性。

3. 高级架构

RocksDB 是一个键值存储接口的存储引擎库,其中键和值是任意字节流。RocksDB 按排序顺序组织所有数据,常见的操作是Get(key)NewIterator()Put(key, val)Delete(key)SingleDelete(key)
RocksDB 的三个基本构造是 memtable、sstfile 和 logfile。内存表是一种内存中数据结构 - 新的写入入到内存表中,并可选择写入日志文件(也称为。提前写入日志(WAL))。日志文件是存储上按顺序写入的文件。当内存表填满时,它会刷新到存储上的 sstfile,并且可以安全地删除相应的日志文件。对 sst 文件中的数据进行排序,以便于轻松查找键。
在这里插入图片描述

特点

色谱柱系列
RocksDB 支持将一个数据库实例分区为多个列族。所有数据库都是使用名为“default”的列系列创建的,该列系列用于未指定列系列的操作。

RocksDB 保证用户在列族之间获得一致的视图,包括在启用 WAL 或启用原子刷新时的崩溃恢复之后。它还支持通过 API 进行原子跨列系列操作。WriteBatch

更新
API 向数据库插入单个键值。如果数据库中已存在该键,则将覆盖以前的值。API 允许在数据库中以原子方式插入、更新或删除多个键值。数据库保证单个调用中的所有键值都将插入到数据库中,或者不会将它们中的任何键值插入到数据库中。如果数据库中已存在这些键中的任何一个,则将覆盖以前的值。删除范围API 可用于删除范围中的所有键。PutWriteWrite

获取、迭代器和快照
键和值被视为纯字节流。键或值的大小没有限制。API 允许应用程序从数据库中获取单个键值。API 允许应用程序从数据库中检索一堆密钥。通过调用返回的所有键值彼此一致。GetMultiGetMultiGet

数据库中的所有数据都按排序顺序进行逻辑排列。应用程序可以指定指定键的总顺序的键比较方法。API 允许应用程序对数据库执行范围扫描。可以查找指定的密钥,然后应用程序可以从该点开始一次扫描一个密钥。该 API 还可用于对数据库中的键进行反向迭代。创建数据库时会创建数据库的一致时间点视图。因此,通过 返回的所有键都来自数据库的一致视图。IteratorIteratorIteratorIteratorIterator

快照 API 允许应用程序创建数据库的时间点视图。和 API 可用于从指定的快照读取数据。从某种意义上说,a 和 a 都提供了数据库的时间点视图,但它们的实现是不同的。短期/前台扫描最好通过迭代器完成,而长时间运行/后台扫描最好通过快照完成。An 保留与数据库的时间点视图对应的所有基础文件的引用计数 - 在释放 之前不会删除这些文件。A 另一方面,不会阻止文件删除;相反,压缩过程了解 的存在,并承诺永远不会删除任何现有 .GetIteratorSnapshotIteratorIteratorIteratorSnapshotSnapshotsSnapshot

Snapshots不会在数据库重新启动后持久化:重新加载 RocksDB 库(通过服务器重新启动)会释放所有预先存在的 .Snapshots

提交

RocksDB支持多操作事务。它支持乐观和悲观模式。

前缀迭代器

大多数 LSM 树引擎无法支持高效的范围扫描 API,因为它需要查看多个数据文件。但是,大多数应用程序不会对数据库中的密钥范围进行纯随机扫描;相反,应用程序通常在键前缀内扫描。RocksDB利用了这一点。应用程序可以配置 以启用基于键前缀的筛选。设置后,前缀的哈希值也会添加到 Bloom 中。指定键前缀 (in ) 的 将使用布隆过滤器来避免查看不包含具有指定键前缀的键的数据文件。请参阅前缀搜索。Options.prefix_extractorOptions.prefix_extractorIteratorReadOptions

持久化

RocksDB有一个预写日志(WAL)。所有写入操作(和)都存储在称为内存表的内存缓冲区中,也可以选择性地插入到WAL中。重新启动时,它会重新处理日志中记录的所有事务。PutDeleteMerge

WAL可以配置为存储在与存储SST文件的目录不同的目录中。对于您可能希望将所有数据文件存储在非持久性快速存储中的情况,这是必需的。同时,您可以通过将所有事务日志放在较慢但持久的存储上来确保不会丢失数据。

每个都有通过 设置的标志,该标志指定是否应将 插入到事务日志中。还可以指定在声明要提交的 之前是否对事务日志发出调用。PutWriteOptionsPutWriteOptionsfsyncPut

在内部,RocksDB 使用批处理提交机制将事务批处理到日志中,以便它可以使用单个调用提交多个事务。fsync
数据校验和
RocksDB 使用校验和来检测存储中的损坏。这些校验和适用于每个 SST 文件块(大小通常介于 之间)。块一旦写入存储,就永远不会被修改。RocksDB 还维护一个完整文件校验和(参见完整文件校验和和校验和切换),并选择性地维护每个键值校验和。4K128K

RocksDB 动态检测并利用 CPU 校验和卸载支持。

多线程压缩
在存在正在进行的写入的情况下,需要压缩以提高空间效率、读取(查询)效率和及时删除数据。压缩会删除已删除或覆盖的键值绑定,并重新组织数据以提高查询效率。如果已配置,压缩可能会在多个线程中发生。

整个数据库存储在一组 sst 文件中。当内存表已满时,其内容将写出到 LSM 树的级别 0 (L0) 中的文件中。RocksDB 在将内存表刷新到 L0 中的文件时会删除内存表中的重复和覆盖键。在压缩中,一些文件会定期读入并合并以形成更大的文件,通常会进入下一个 LSM 级别(例如 L1,直到 Lmax)。

LSM 数据库的总体写入吞吐量直接取决于压缩的速度,尤其是当数据存储在 SSD 或 RAM 等快速存储中时。RocksDB 可以配置为发出来自多个线程的并发压缩请求。据观察,与单线程压缩相比,当数据库位于 SSD 上时,多线程压缩的持续写入速率可能会增加多达 10 倍。

压实样式
“级别样式压缩”和“通用样式压缩”将数据存储在数据库中固定数量的逻辑级别中。较新的数据存储在 0 级 (L0) 中,较旧的数据存储在编号较高的级别中,最高为 Lmax。L0 中的文件可能具有重叠键,但其他级别的文件通常形成每个级别的单个排序运行。

级别样式压缩(默认)通常通过最小化每个压缩步骤中涉及的文件来优化磁盘占用空间与逻辑数据库大小(空间放大):将 Ln 中的一个文件与 Ln+1 中的所有重叠文件合并,并用 Ln+1 中的新文件替换它们。

通用样式压缩通常通过一次合并可能多个文件和级别来优化写入磁盘的总字节数与逻辑数据库大小(写入放大),这需要更多的临时空间。通用通常会导致较低的写入放大,但比级别样式压缩更高的空间和读取放大。

FIFO 样式压缩在过时会丢弃最旧的文件,并可用于类似缓存的数据。在 FIFO 压缩中,所有文件都处于级别 0。当数据的总大小超过配置的大小(压缩选项FIFO::max_table_files_size)时,我们将删除最旧的表文件。

我们还使开发人员能够开发和试验自定义压缩策略。出于这个原因,RocksDB 有适当的钩子来关闭内置的压缩算法,并有其他 API 来允许应用程序运行自己的压缩算法。,如果已设置,则禁用本机压缩算法。API 允许外部组件查看数据库中的每个数据文件,并决定要合并和压缩哪些数据文件。调用所需的压缩文件。API 允许应用程序删除被视为过时的数据文件。Options.disable_auto_compactionGetLiveFilesMetaDataCompactFilesDeleteFile

元数据存储
清单日志文件用于记录所有数据库状态更改。压缩过程会添加新文件并从数据库中删除现有文件,并通过将这些操作记录在清单中来使这些操作持久化。

避免摊位
后台压缩线程还用于将可记忆内容刷新到存储上的文件。如果所有后台压缩线程都忙于执行长时间运行的压缩,则突然的写入可能会迅速填满内存表,从而停止新的写入。通过将 RocksDB 配置为保留一小组明确保留的线程,可以避免这种情况,其唯一目的是将可记忆因素刷新到存储。

压实过滤器
某些应用程序可能希望在压缩时处理密钥。例如,具有对生存时间 (TTL) 的固有支持的数据库可能会删除过期的密钥。这可以通过应用程序定义的压缩过滤器来完成。如果应用程序想要连续删除早于特定时间的数据,则可以使用压缩筛选器删除已过期的记录。RocksDB 压缩过滤器为应用程序提供了修改键值或完全删除键作为压缩过程的一部分的控制。例如,应用程序可以在压缩过程中持续运行数据清理程序。

只读模式
可以在只读模式下打开数据库,在该模式下,数据库保证应用程序不会修改数据库中的任何内容。这会导致更高的读取性能,因为经常遍历的代码路径完全避免了锁定。

数据库调试日志(又名.信息日志)
默认情况下,RocksDB 会将详细日志写入名为 LOG* 的文件。这些主要用于调试和分析正在运行的系统。用户可以选择不同的日志级别(请参阅)。此 LOG 可以配置为按指定的周期滚动。日志记录接口是可插拔的。用户可以插入不同的记录器。请参阅记录器。DBOptions.info_log_level

数据压缩
RocksDB 支持 lz4、zstd、snappy、zlib 和 lz4_hc 压缩,以及 Windows 下的 xpress。RocksDB 可以配置为支持最底层数据的不同压缩算法,即数据所在的位置。典型的安装可能会为最底层的级别配置 ZSTD(或 Zlib,如果不可用),为其他级别配置 LZ4(如果不可用,则配置 Snappy)。请参阅压缩。90%

完整备份和复制
RocksDB 提供了一个备份 API,.您可以在此处阅读更多相关信息: 如何备份 RocksDBBackupEngine

RocksDB 本身不是复制的,但它提供了一些辅助功能,使用户能够在 RocksDB 之上实现他们的复制系统,请参阅复制助手。

在同一过程中支持多个嵌入式数据库
RocksDB 的一个常见用例是应用程序本质上将其数据集划分为逻辑分区或分片。此技术有利于应用程序负载平衡和从故障中快速恢复。这意味着单个服务器进程应该能够同时操作多个 RocksDB 数据库。这是通过名为 的环境对象完成的。此外,线程池还与 .如果应用程序希望在多个数据库实例之间共享公共线程池(用于后台压缩),则应使用相同的对象来打开这些数据库。EnvEnvEnv

同样,多个数据库实例可以共享同一个块缓存或速率限制器。

块缓存 – 压缩和未压缩数据
RocksDB 使用 LRU 缓存为块提供读取服务。块缓存分为两个单独的缓存:第一个缓存未压缩的块,第二个缓存 RAM 中的压缩块。如果配置了压缩块缓存,用户可能希望启用直接 I/O,以防止在操作系统页面缓存中冗余缓存相同的数据。

表缓存
表缓存是缓存打开的文件描述符的构造。这些文件描述符适用于 sstfiles。应用程序可以指定表缓存的最大大小,或将 RocksDB 配置为始终保持所有文件打开,以实现更好的性能。

I/O 控制
RocksDB允许用户以不同的方式配置SST文件的I / O。用户可以启用直接 I/O,以便 RocksDB 完全控制 I/O 和缓存。另一种方法是利用一些选项来允许用户提示应如何执行 I/O。他们可以建议 RocksDB 调用要读取的文件,在附加的文件中调用定期范围同步,启用直接 I/O 等…有关更多详细信息,请参阅 IO。

可堆叠数据库
RocksDB 具有内置的包装器机制,可以在代码数据库内核之上添加功能作为层。此功能由 API 封装。例如,生存时间功能由核心 RocksDB API 实现,而不是核心 RocksDB API 的一部分。这种方法使代码保持模块化和干净。StackableDBStackableDB

内存表:
可插拔内存表:
RocksDB 的 memtable 的默认实现是一个 skiplist。skiplist 是一个排序集,当工作负载将写入与范围扫描交错时,这是必要的构造。但是,某些应用程序不交错写入和扫描,而某些应用程序根本不执行范围扫描。对于这些应用程序,排序集可能无法提供最佳性能。出于这个原因,RocksDB的memtable是可插拔的。提供了一些替代实现。三个内存表是该库的一部分:一个skiplist memtable,一个向量memtable和一个前缀-哈希memtable。矢量可忆因表适用于将数据批量加载到数据库中。每次写入都会在向量的末尾插入一个新元素;当需要刷新内存表以存储时,向量中的元素被排序并写出到 L0 中的文件中。前缀哈希内存表允许有效地处理获取、放置和键内扫描前缀。虽然 memtable 的可插拔性不是作为公共 API 提供的,但应用程序可以在私有分支中提供自己的 memtable 实现。

可记忆流水线
RocksDB 支持为数据库配置任意数量的内存表。当内存表已满时,它将成为不可变的内存表,后台线程开始将其内容刷新到存储。同时,新的写入继续累积到新分配的内存表中。如果新分配的内存表已填充到其限制,则也会将其转换为不可变的内存表,并插入到刷新管道中。后台线程继续将所有流水线的不可变内存表刷新到存储。这种流水线增加了 RocksDB 的写入吞吐量,尤其是当它在慢速存储设备上运行时。

内存刷新期间的垃圾回收:
将内存表刷新到存储时,将执行内联压缩过程。垃圾的清除方式与压实相同。同一密钥的重复更新将从输出流中删除。同样,如果较早的放置被较晚的删除隐藏,则放置根本不会写入输出文件。对于某些工作负载,此功能大大减少了存储和写入放大上的数据大小。

合并运算符
RocksDB 原生支持三种类型的记录:记录、记录和记录。当压缩过程遇到合并记录时,它会调用称为合并运算符的应用程序指定方法。合并可以将多个“放置”和“合并”记录合并为一个记录。此强大的功能允许通常执行读取-修改-写入的应用程序完全避免读取。它允许应用程序将操作意图记录为合并记录,并且 RocksDB 压缩过程将该意图延迟应用于原始值。此功能在合并运算符中有详细说明PutDeleteMerge

数据库标识
在创建数据库时创建的全局唯一 ID,默认情况下存储在数据库文件夹的 IDENTITY 文件中。(可选)它只能存储在清单文件中。建议存储在清单文件中。

5. 工具

有许多有趣的工具用于支持生产中的数据库。该实用程序转储 sst 文件中的所有键值以及其他信息。该工具可以放置,获取,扫描数据库的内容。 也可以转储的内容,也可以用来改变数据库配置的级别数。有关详细信息,请参阅管理和数据访问工具。sst_dumpldbldbMANIFEST

6. 测试

有一堆单元测试可以测试数据库的特定功能。命令运行所有单元测试。单元测试触发 RocksDB 的特定功能,并非旨在大规模测试数据正确性。该测试用于大规模验证数据的正确性。请参阅压力测试。您还可以利用那里的模糊测试基础设施将模糊器添加到此目录中,模糊器在Google的OSS-Fuzz上运行,错误将报告给RocksDB开发人员。make checkdb_stress

7. 性能

RocksDB 的性能通过名为 的实用程序进行基准测试。 是 RocksDB 源代码的一部分。此处介绍了使用闪存存储的一些典型工作负载的性能结果。您还可以在此处找到内存中工作负载的 RocksDB 性能结果。db_benchdb_bench

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值