RocksDB基础介绍

2020/09/20 rocksdb 共 4430 字,约 13 分钟

翻译 https://github.com/facebook/rocksdb/wiki

中文blog https://rocksdb.org.cn/doc/Leveled-Compaction.html

RocksDB

介绍

RocksDB最初在Facebook上是一种存储引擎,用于处理各种存储介质上的服务器工作负载,最初侧重于快速存储(尤其是闪存)。它是一个C ++库,用于存储键和值,它们是任意大小的字节流。它支持点查找和范围扫描,并提供不同类型的ACID保证。

在可定制性和自适应性之间取得平衡。RocksDB具有高度灵活的配置设置,可以将其设置为在各种生产环境中运行,包括SSD,硬盘,ramfs或远程存储。它支持各种压缩算法以及用于生产支持和调试的良好工具。另一方面,还努力限制旋钮的数量,提供足够好的开箱即用性能,并在适用的情况下使用一些自适应算法。

RocksDB借鉴了开源leveldb项目中的重要代码以及Apache HBase的构想。初始代码来自开源leveldb 1.5。它还基于RocksDB之前在Facebook上开发的代码和想法。

##

设计目标和特征

  • 专为希望在本地或远程存储系统上存储多达TB数据的应用服务器而设计。
  • 优化用于在快速存储中存储中小型键值-闪存设备或内存中
  • 它在具有多个内核的处理器上运行良好

性能

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

生产支持

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

兼容性

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

架构

RocksDB是键值存储接口的存储引擎库,其中键和值是任意字节流。RocksDB组织所有数据的排序顺序和常用操作Get(key)NewIterator()Put(key, val)Delete(key),和SingleDelete(key)

RocksDB的三个基本构造是memtable,sstfile和logfile。

memTable是一个存储器内数据结构-新的写入被插入的memTable和任选地写入到日志文件。该日志文件是存储顺序排列的书面文件。当memTable中填满,它被刷新到一个sstfile存储和相应的日志文件可以安全地删除。sstfile中的数据已排序,以方便轻松查找键。

默认sstfile的格式如下

<beginning_of_file>
[data block 1]
[data block 2]
...
[data block N]
[meta block 1: filter block]                  (see section: "filter" Meta Block)
[meta block 2: index block]
[meta block 3: compression dictionary block]  (see section: "compression dictionary" Meta Block)
[meta block 4: range deletion block]          (see section: "range deletion" Meta Block)
[meta block 5: stats block]                   (see section: "properties" Meta Block)
...
[meta block K: future extended block]  (we may add more meta blocks in the future)
[metaindex block]
[Footer]                               (fixed size; starts at file_size - sizeof(Footer))
<end_of_file>

细节 https://github.com/facebook/rocksdb/wiki/Rocksdb-BlockBasedTable-Format

rocksdb-arch

rocksdb-detail-14-638

RocksDB基础介绍

https://github.com/facebook/rocksdb/wiki/RocksDB-Basics

Leveled Compaction

https://rocksdb.org.cn/doc/Leveled-Compaction.html

Block Cache

相比LevelDB引入的新的特性

性能

  • 多线程压缩
  • 多线程内存插入
  • 减少数据库互斥量保持
  • 优化的基于级别的压实样式和通用压实样式
  • 前缀Bloom过滤器
  • 记忆布隆过滤器
  • 单绽放过滤器覆盖整个SST文件
  • 写锁优化
  • 改进的Iter :: Prev()性能
  • 在SkipList搜索过程中较少的比较器调用
  • 使用大页面分配可分配内存。

特征

  • 列族
  • 事务和WriteBatchWithIndex
  • 备份和检查点
  • 合并运算符
  • 压实过滤器
  • RocksDB Java
  • 手动压实与自动压实并行运行
  • 永久缓存
  • 散装
  • 正向迭代器/尾部迭代器
  • 一次删除
  • 删除范围内的文件
  • 引脚迭代器键/值

替代数据结构和格式

  • 纯表格式(仅用于内存)
  • 基于向量和基于哈希的内存表格式
  • 基于时钟的缓存(即将推出)
  • 可插拔信息日志
  • 使用Blob注释事务日志写入(用于复制)

可调整性

  • 限速
  • 可调减速和停止阈值
  • 选择保持所有文件打开
  • 选择将所有索引和Bloom过滤器块保留在块缓存中
  • 多种WAL恢复模式
  • Fadvise提示以进行预读并避免在OS页面缓存中进行缓存
  • 固定内存中L0文件的索引和Bloom筛选器的选项
  • 更多压缩类型:zlib,lz4,zstd
  • 压缩字典
  • 校验和类型:xxhash
  • 每个级别使用不同的级别大小乘数和压缩类型。

可管理性

  • 统计
  • 线程局部分析
  • 命令行工具中的更多命令
  • 用户定义的表属性
  • 事件监听器
  • 更多数据库属性
  • 动态选项变更
  • 从字符串或映射中获取选项
  • 永久性选项文件

ROCKSDB的调优参数

读放大,写放大,和空间放大

RocksDB 和 LevelDB 通过后台的 compaction 来减少读放大(减少 SST 文件数量)和空间放大(清理过期数据),但也因此带来了写放大(Write Amplification)的问题。

- 写放大。实际写入 HDD/SSD 的数据大小和程序要求写入数据大小之比。正常情况下,HDD/SSD 观察到的写入数据多于上层程序写入的数据

在这三个因子里面取得平衡

MemTable

  • write_buffer_size | state.backend.rocksdb.writebuffer.size 单个 memtable 的大小,默认是64MB。当 memtable 大小达到此阈值时,就会被标记为不可变。一般来讲,适当增大这个参数可以减小写放大带来的影响,但同时会增大 flush 后 L0、L1 层的压力,所以还需要配合修改 compaction 参数,后面再提。

  • max_write_buffer_number | state.backend.rocksdb.writebuffer.count memtable 的最大数量(包含活跃的和不可变的),默认是2。当全部 memtable 都写满但是 flush 速度较慢时,就会造成写停顿,所以如果内存充足或者使用的是机械硬盘,建议适当调大这个参数,如4。

  • min_write_buffer_number_to_merge | state.backend.rocksdb.writebuffer.number-to-merge 在 flush 发生之前被合并的 memtable 最小数量,默认是1。举个例子,如果此参数设为2,那么当有至少两个不可变 memtable 时,才有可能触发 flush(亦即如果只有一个不可变 memtable,就会等待)。调大这个值的好处是可以使更多的更改在 flush 前就被合并,降低写放大,但同时又可能增加读放大,因为读取数据时要检查的 memtable 变多了。经测试,该参数设为2或3相对较好。

Block/Block Cache

block 是 sstable 的基本存储单位。block cache 则扮演读缓存的角色,采用 LRU 算法存储最近使用的 block,对读性能有较大的影响。

  • block_size | state.backend.rocksdb.block.blocksize block 的大小,默认值为4KB。在生产环境中总是会适当调大一些,一般32KB比较合适,对于机械硬盘可以再增大到128~256KB,充分利用其顺序读取能力。但是需要注意,如果 block 大小增大而 block cache 大小不变,那么缓存的 block 数量会减少,无形中会增加读放大。

  • block_cache_size | state.backend.rocksdb.block.cache-size block cache 的大小,默认为8MB。由上文所述的读写流程可知,较大的 block cache 可以有效避免热数据的读请求落到 sstable 上,所以若内存余量充足,建议设置到128MB甚至256MB,读性能会有非常明显的提升。

Compaction

  • target_file_size_base | state.backend.rocksdb.compaction.level.target-file-size-base L1层单个 sstable 文件的大小阈值,默认值为64MB。每向上提升一级,阈值会乘以因子 target_file_size_multiplier(但默认为1,即每级sstable最大都是相同的)。显然,增大此值可以降低 compaction 的频率,减少写放大,但是也会造成旧数据无法及时清理,从而增加读放大。此参数不太容易调整,一般不建议设为256MB以上。

  • max_bytes_for_level_base | state.backend.rocksdb.compaction.level.max-size-level-base L1层的数据总大小阈值,默认值为256MB。每向上提升一级,阈值会乘以因子 max_bytes_for_level_multiplier(默认值为10)。由于上层的大小阈值都是以它为基础推算出来的,所以要小心调整。建议设为 target_file_size_base 的倍数,且不能太小,例如5~10倍。

  • level_compaction_dynamic_level_bytes | state.backend.rocksdb.compaction.level.use-dynamic-size 这个参数之前讲过。当开启之后,上述阈值的乘法因子会变成除法因子,能够动态调整每层的数据量阈值,使得较多的数据可以落在最高一层,能够减少空间放大,整个 LSM Tree 的结构也会更稳定。对于机械硬盘的环境,强烈建议开启

文档信息

Search

    Table of Contents