RocksDB

472 阅读4分钟

RocksDB是 Facebook 开源的一个高性能持久化 KV 存储,越来越多的新生代数据库,都不约而同地选择 RocksDB 作为它们的存储引擎。

RocksDB特性

RocksDB 相应的随机读写性能大约在 20 万次 / 秒左右,Redis是50 万次 / 秒左右,性能是一个级别水平。

Redis 是一个内存数据库,并不是一个可靠的存储。数据写到内存中就算成功了,它并不保证安全地保存到磁盘上。而 RocksDB 它是一个持久化的 KV 存储,它需要保证每条数据都要安全地写到磁盘上,这也是很多数据库产品的基本要求。

一个存储系统,它的读写性能主要取决于什么?取决于它的存储结构,也就是数据是如何组织的。利用LSM-Tree,写磁盘变成顺序写,不同于树、哈希结构随机写。

LSM-Tree

  1. 结构:
image.png
  1. 写操作:
  • 这条操作命令会被写入到磁盘的 WAL 日志中(图中右侧的 Log),这是一个顺序写磁盘的操作,性能很好。这个日志是用来故障恢复的。

  • 然后数据会被写入到内存中的 MemTable 中,这个 MemTable 就是一个按照 Key 组织的跳表(SkipList)。写 MemTable 是个内存操作,速度也非常快。数据写入到 MemTable 之后,就可以返回写入成功了。LSM-Tree 在处理写入的过程中,直接就往 MemTable 里写,并不去查找这个 Key 是不是已经存在了。

  • MemTable 有一个固定的上限大小,一般是 32M。MemTable 写满之后,就被转换成 Immutable MemTable,然后再创建一个空的 MemTable 继续写。这个 Immutable MemTable,也就是只读的 MemTable,它和 MemTable 的数据结构完全一样,唯一的区别就是不允许再写入了。

  • Immutable MemTable 也不能在内存中无限地占地方,会有一个后台线程,不停地把 Immutable MemTable 复制到磁盘文件中,然后释放内存空间。每个 Immutable MemTable 对应一个磁盘文件,MemTable 的数据结构跳表本身就是一个有序表,写入的文件也是一个按照 Key 排序的结构,这些文件就是 SSTable。把 MemTable 写入 SSTable 这个写操作,因为它是把整块内存写入到整个文件中,这同样是一个顺序写操作。

  • SSTable 被分为很多层,越往上层,文件越少,越往底层,文件越多。每一层的容量都有一个固定的上限,一般来说,下一层的容量是上一层的 10 倍。当某一层写满了,就会触发后台线程往下一层合并,数据合并到下一层之后,本层的 SSTable 文件就可以删除掉了。合并的过程也是排序的过程,除了 Level 0(第 0 层,也就是 MemTable 直接 dump 出来的磁盘文件所在的那一层。)以外,每一层内的文件都是有序的,文件内的 KV 也是有序的,这样就比较便于查找了。

  1. 读操作
  • 先去内存中的 MemTable 和 Immutable MemTable 中找
  • 然后再按照顺序依次在磁盘的每一层 SSTable 文件中去找,只要找到了就直接返回。

这样的查找方式其实是很低效的,有可能需要多次查找内存和多个文件才能找到一个 Key,但实际的效果也没那么差,因为这样一个分层的结构,它会天然形成一个非常有利于查找的情况:越是被经常读写的热数据,它在这个分层结构中就越靠上,对这样的 Key 查找就越快。

  1. 删除
  • 将要删除的键值对标记为已删除。(当要删除一个键值对时,可以创建一个包含该键的Tombstone并将其插入到LSM树中。此后,每次在查询LSM树时,都需要检查Tombstone是否存在,并将其视为键值对已被删除。)
  • 在写入新数据时,将标记为已删除的键值对覆盖掉。
  • 定期执行合并操作,将已删除的键值对从LSM树中完全删除。

需要注意的是,删除操作并不是实时生效的,因为标记为已删除的键值对仍然存在于LSM树中,直到执行合并操作。


此文章为3月Day24学习笔记,内容来源于极客时间《后端存储实战课》