RocksDB是FaceBook起初作为实验性质开发的,旨在充分实现快存上存储数据的服务能力。由Facebook的Dhruba Borthakur于2012年4月创建的LevelDB的分支,最初的目标是提高服务工作负载的性能,最大限度的发挥闪存和RAM的高度率读写性能。
Key和value是任意大小的字节流支持原子的读和写。除此外,RocksDB深度支持各种配置,可以在不同的生产环境(纯内存、Flash、hard disks or HDFS)中调优,RocksDB针对多核CPU、高效快速存储(SSD)、I/O bound workload做了优化,支持不同的数据压缩算法、和生产环境debug的完善工具。
RocksDB的主要设计点是在快存和高服务压力下性能表现优越,所以该db需要充分挖掘Flash和RAM的读写速率。例如360开源的Pika, 是由360 DBA 和基础架构组联合开发的类 Redis 存储系统,完全支持 Redis 协议,用户不需要修改任何代码,就可以将服务迁移至 Pika,Pika底层存储引擎用的就是Rocksdb。
---------------------
RocksDB需要支持高效的point lookup和range scan操作,需要支持配置各种参数在高压力的随机读、随机写或者二者流量都很大时性能调优,基于LSM树数据结构( log-structured merge-tree),由C++编写并官方提供C、C++、Java(官方提供的称为RocksJava)三种语言的API,社区提供了不少第三方API,如python、go等。
---------------------
尽管RocksDB不是一个SQL 数据库,但是有facebook有修改了代码的MyRocks存储引擎作为MySQL的存储引擎。和其他的NoSQL类似,RocksDB不提供关系型数据模型、不支持SQL查询,没有直接对辅助索引(secondary indexes)支持。
Rocksdb中引入了ColumnFamily(列族, CF)的概念,所谓列族也就是一系列kv组成的数据集。所有的读写操作都需要先指定列族。写操作先写WAL,再写memtable,memtable达到一定阈值后切换为Immutable Memtable,只能读不能写。后台Flush线程负责按照时间顺序将Immu Memtable刷盘,生成level0层的有序文件(SST)。后台合并线程负责将上层的SST合并生成下层的SST。Manifest负责记录系统某个时刻SST文件的视图,Current文件记录当前最新的Manifest文件名。 每个ColumnFamily有自己的Memtable, SST文件,所有ColumnFamily共享WAL、Current、Manifest文件,用户可以基于RocksDB构建自己的column families。很多应用程序把RocksDB当做库(libary),尽管他提供server或者CLI接口。
Memtable
可插拔 memtable,RocksDB 的 memtable 的默认实现是一个 skiplist。skiplist 是一个有序集,当工作负载使用 range-scans 并且交织写入时,这是一个必要的结构。然而,一些应用程序不交织写入和扫描,而一些应用程序根本不执行范围扫描。对于这些应用程序,排序集可能无法提供最佳性能。因此,RocksDB 支持可插拔的 API,允许应用程序提供自己的 memtable 实现。开发库提供了三个 memtable:skiplist memtable,vector memtable 和前缀散列(prefix-hash) memtable。Vector memtable 适用于将数据批量加载到数据库中。每个写入在向量的末尾插入一个新元素; 当它是刷新 memtable 到存储的时候,向量中的元素被排序并写出到 L0 中的文件。前缀散列 memtable 允许对 gets,puts 和 scans-within-a-key-prefix 进行有效的处理。
SSTFile(SSTTable)
RocksDB在磁盘上的file结构sstfile由block作为基本单位组成,一个sstfile结构由多个data block组成,其中data block就是数据实体block,meta block为元数据block,其中data block就是数据实体block,meta block为元数据block。sstfile组成的block有可能被压缩(compression),不同level也可能使用不同的compression方式。sstfile如果要遍历block,会逆序遍历,从footer开始。
RocksDB是一个嵌入式的K-V(任意字节流)存储。所有的数据在引擎中是有序存储,可以支持Get(key)、Put(Key)、Delete(Key)和NewIterator()。RocksDB的基本组成是memtable、sstfile和logfile。memtable是一种内存数据结构,写请求会先将数据写到memtable中,然后可选地写入logfile。logfile是一个顺序写的文件。当内存表溢出的时候,数据会flush到sstfile中,然后这个memtable对应的logfile也会安全地被删除。sstfile中的数据也是有序存储以方便查找。
---------------------
RocksDB支持将一个数据库实例分片为多个列族。类似HBase,每个DB新建时默认带一个名为"default"的列族,如果一个操作没有携带列族信息,则默认使用这个列族。如果WAL开启,当实例crash再恢复时,RocksDB可以保证用户一个一致性的视图。通过WriteBatch API,可以实现跨列族操作的原子性。
写流程:
rocksdb写入时,直接以append方式写到log文件以及memtable,随即返回,因此非常快速。
memtable/immute memtable触发阈值后, flush 到Level0 SST,Level0 SST触发阈值后,经合并操作(compaction)生成level 1 SST, level1 SST 合并操作生成level 2 SST,以此类推,生成level n SST.
读流程:
按照 memtable --> Level 0 SST–> Level 1 SST --> … -> Level n SST的顺序读取数据。这和记录的新旧顺序是一的。因此只要在当前级别找到记录,就可以返回。
因为RocksDB 改自LevelDB,现在来对比下他们优缺点:
---------------------
LevelDB 特点:
1) LevelDB是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,LevelDB不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。
2) LevleDB在存储数据时,是根据记录的key值有序存储的,就是说相邻的key值在存储文件中是依次顺序存储的,而应用可以自定义key大小比较函数。
3) LevelDB支持数据快照(snapshot)功能,使得读取操作不受写操作影响,可以在读操作过程中始终看到一致的数据。
4) LevelDB还支持数据压缩等操作,这对于减小存储空间以及增快IO效率都有直接的帮助。
RocksDB 对LevelDB的优化:
1) 增加了column family,这样有利于多个不相关的数据集存储在同一个db中,因为不同column family的数据是存储在不同的sst和memtable中,所以一定程度上起到了隔离的作用。
2) 采用了多线程同时进行compaction的方法,优化了compact的速度。
3) 增加了merge operator,优化了modify的效率。
4) 将flush和compaction分开不同的线程池,能有效的加快flush,防止stall。
5) 增加了对write ahead log(WAL)的特殊管理机制,这样就能方便管理WAL文件,因为WAL是binlog文件。
---------------------
RocksDB的典型场景(低延时访问):
1)需要存储用户的查阅历史记录和网站用户的应用
2)需要快速访问数据的垃圾检测应用
3)需要实时scan数据集的图搜索query
4)需要实时请求Hadoop的应用
5)支持大量写和删除操作的消息队列
下一节我们将介绍SSDB的原理和用途,以及在redis冷热分离的应用。
领取专属 10元无门槛券
私享最新 技术干货