RocksDB

常见 KV Store

常见kv存储有

  • 基于内存的 redis
  • 基于单机磁盘的 leveldb、rocksdb
  • 分布式(超过 TB 级别的) cassandra、hbase

RocksDB

安装

rocksdb 是 c++ 写的,由于官方没有提供对应平台的二进制库,不同平台编译的类库是不通用的,所以需要自己去相应的平台编译使用。如果使用 rocksdbjava 这个问题就好很多,但是 java api 总是落后于 c++ 版本的。

在安装 rocksdb 之前,需要理解一下什么是嵌入式的 kv-store。对于非嵌入式的 kv-store,比如 redis,想使用 redis 就需要先安装 redis-server,然后通过 redis-client 对数据进行读写。而对于嵌入式的 kv-store 来讲,是没有具体服务端的,直接用代码操作数据存储,也就是说只需要在你的项目中引入 rocksdb 的相关依赖(java 在 maven 中添加依赖),就可以在开发了。

C++

RocksDB Install

# 如果 ./configure 时报错 configure: error: C++ compiler cannot create executables,这种是缺少 c++ 组件
$ yum install -y gcc gcc-c++ gcc-g77 

# Install gflags
$ git clone https://github.com/gflags/gflags.git
$ cd gflags
$ git checkout v2.0
$ ./configure && make && sudo make install

# Install snappy:
$ sudo yum install -y snappy snappy-devel

# Install zlib:
$ sudo yum install -y zlib zlib-devel

# Install bzip2:
$ sudo yum install -y bzip2 bzip2-devel

# Install lz4:
$ sudo yum install -y lz4-devel

# Install ASAN (optional for debugging):
$ sudo yum install -y libasan

# Install zstandard:
$ wget https://github.com/facebook/zstd/archive/v1.1.3.tar.gz
$ mv v1.1.3.tar.gz zstd-1.1.3.tar.gz
$ tar zxvf zstd-1.1.3.tar.gz
$ cd zstd-1.1.3
$ make && sudo make install

# Install rocksdb
$ git clone https://github.com/facebook/rocksdb.git

$ cd rocksdb

# 编译静态库,release mode,获得librocksdb.a
$ make static_lib

# 编译动态库,release mode,获得librocksdb.so
$ make shared_lib

$ cp librocksdb.a /usr/lib
$ cp -r include/ /usr/include
$ cp librocksdb.so /usr/lib
$ sudo ldconfig

Java

RocksJava Basics

<dependency>
    <groupId>org.rocksdb</groupId>
    <artifactId>rocksdbjni</artifactId>
    <version>5.17.2</version>
</dependency>

管理工具

使用ldbsst_dump来管理 rocksdb,在安装了上述 c++ 依赖之后

# Linux
$ cd rocksdb
$ make ldb sst_dump
$ cp ldb /usr/local/bin/
$ cp sst_dump /usr/local/bin/

# OSX 
$ brew install rocksdb
# 对应的命令分别为
$ rocksdb_ldb
$ rocksdb_sst_dump

关于ldbsst_dump使用方法,可以参考官方文档https://github.com/facebook/rocksdb/wiki/Administration-and-Data-Access-Tool

examples

查看所有数据库的所有 keys

#!/bin/bash

export DATA_PATH=/hadoop/rockfs/data
export DB_INSTANCES=$(ls /hadoop/rockfs/data)

for i in $DB_INSTANCES; do 
  ldb --db=$DATA_PATH/$i/ scan 2>/dev/null; 
done

查看 SST file properties

# 注意 --file 需要指定绝对路径
$ sst_dump --file=$DATA_PATH/test --show_properties
from [] to []
Process /hadoop/rockfs/data/0006.sst
Sst file format: block-based
Table Properties:
------------------------------
  # data blocks: 26541
  # entries: 2283572
  raw key size: 264639191
  raw average key size: 115.888262
  raw value size: 26378342
  raw average value size: 11.551351
  data block size: 67110160
  index block size: 3620969
  filter block size: 0
  (estimated) table size: 70731129
  filter policy name: N/A
  # deleted keys: 571272
  
# 如果出现 sst_dump: error while loading shared libraries: libgflags.so.2: cannot open shared object file: No such file or directory
$ find / -name libgflags.so.2
/root/gflags/.libs/libgflags.so.2
/usr/local/lib/libgflags.so.2
# 可以看出依赖已经下载到了,只是没有被找到,手动指定下依赖库
$ vim /etc/ld.so.conf.d/usr-libs.conf
/usr/local/lib
$ sudo ldconfig

升级 gcc 到 8.1

http://mirror.hust.edu.cn/gnu 下载gmp-5.1.1.tar.bz2mpfr-3.1.5.tar.bz2mpc-1.1.0.tar.gzgcc-8.0.1.tar.gz

$ yum install -y m4

$ tar -xvf gmp-5.1.1.tar.bz2
$ cd gmp-5.1.1
$ ./configure --prefix=/usr/local/gmp-5.1.1 && make
$ make install

$ tar -xvf mpfr-3.1.5.tar.bz2
$ cd mpfr-3.1.5
$ ./configure --prefix=/usr/local/mpfr-3.1.5 --with-gmp=/usr/local/gmp-5.1.1 && make
$ make install

$ tar -zxvf mpc-1.1.0.tar.gz
$ cd mpc-1.1.0
$ ./configure --prefix=/usr/local/mpc-1.1.0 --with-gmp=/usr/local/gmp-5.1.1 --with-mpfr=/usr/local/mpfr-3.1.5 && make
$ make install

$ tar -zxvf gcc-8.0.1.tar.gz
$ export LD_LIBRARY_PATH=/usr/local/mpc-1.1.0/lib:/usr/local/gmp-5.1.1/lib:/usr/local/mpfr-3.1.5/lib:$LD_LIBRARY_PATH
$ cd gcc-8.0.1
$ ./configure --prefix=/usr/local/gcc-8.0.1 --enable-threads=posix --disable-checking --disable-multilib --enable-languages=c,c++ --with-gmp=/usr/local/gmp-5.1.1 --with-mpfr=/usr/local/mpfr-3.1.5 --with-mpc=/usr/local/mpc-1.1.0 && make
$ make install

LSM-Tree(Log-Structured-Merge Tree)

背景

LSM 通过消去随机的磁盘IO来提供比传统的 B+ 树或者 ISAM 更好的写操作吞吐量。本质问题是,不论HDD还是SSD,随机读写都比顺序读写要慢,尤其是机械磁盘,但是,如果我们是顺序写磁盘的话,那速度跟写内存是相当的:因为减少了寻道时间和旋转时间。而且顺序写的情况下,还能将数据先放到buffer,等待数量达到磁盘的一页时,再落盘,能进一步减少磁盘IO次数。

比如日志数据,他们是有严格的时间顺序的,因此完全可以顺序写入。当你想要查找数据的时候需要扫描所有的数据,类似grep,因此查找的速度就比较慢O(n)

对于数据量比较多的情况,提高读取性能的一般方式

  • 二分查找: 将文件数据按key排序保存,使用二分查找来完成特定key的查找,O(logN)
  • 哈希: 用哈希将数据分割为不同的bucket,当查询某个数据的时候通过哈希函数获取数据所在的bucket,然后遍历bucket中少量的数据。
  • B+树: 使用B+树或者ISAM等方法,可以减少外部文件的读取
  • 外部文件: 将数据保存为日志,并创建一个hash或者查找树映射相应的文件。

上面的方法通过按照固定的数据结构编排、存储数据,有效的提高了读取的性能,但是也因此导致增加了大量的随机IO,丧失了良好的写入性能,尤其在数据量很大的时候。比如更新HashB+ Tree的结构的时候,还需要移动其中的部分数据,导致随机IO。

那么当数据不是日志这种严格有序的数据,如何保证数据按照某个顺序排好序然后顺序写入磁盘,还能支持数据的快速检索?听起来貌似很矛盾,但LSM就是做这件事情的。

LSM 原理

LSM使用一种不同于上述四种的方法,保持了日志文件写性能,以及微小的读操作性能损失。本质上就是让所有的操作顺序化,避免对磁盘进行随机读写。如何做到呢?

LSM的思想,在内存中进行数据的增加和修改,达到指定的限制后再将这些修改操作批量写入到磁盘中,相比较于写入操作的高性能,读取需要查询两个地方的数据,内存中最近修改的操作和磁盘中历史的数据,先看是否在内存中,若没有命中,还要访问磁盘文件。

LSM的基本原理,将之前使用一个大的查找结构(造成随机读写,影响写性能),变换为将写操作顺序的保存到一些相似的有序文件sstable中,每个文件包含短时间内的一些改动。因为文件是有序的,所以之后查找也会很快。文件是不可修改的,他们永远不会被更新,新的更新操作只会写到新的文件中。读操作检查很有限的文件。而后台则通过周期性的合并这些文件来减少文件个数。

写入原理

当有新的更新操作,首先把他们写到内存缓存中,也就是memtable中,memtable使用树结构来保持key有序,为了保证数据不丢失,大部分实现,都会在操作写入内存之前先写WAL到磁盘。当memtable数据达到一定规模的时候会被flush到磁盘生成一个sstfile,在flush的过程,系统只进行了顺序磁盘读写,文件是不可修改的,对于数据的修改,则是通过写入新的文件覆盖旧文件中的数据。

所以当越多的数据被写入系统,就会产生越来越多的不可修改,有序的sstfile被顺序写入磁盘,每一个sstfile都代表了小的,按时间顺序的修改操作,也就是说新生成的sstfile中的修改会覆盖掉旧的sstfile

因为文件不可以被修改,旧文件中的有些数据可能已经无效了,因此系统需要周期性的执行合并操作(Compaction)。合并操作会选择一些文件,把它们合并到一起,合并的过程会把那些没有用的记录合并或者删除,除了丢与冗余和无效数据,合并之后会也大大减少sstfile的数量,这样就能够长期保证读取性能。因为每个sstfile内部都是有序的,因此sstfile的合并也是非常高效的。

读取原理

当来一个读取操作,系统会首先检查memtables,如果没有找到这个key,就会逆序(新的sst数据优先与旧的sst)一个个的检查sstfile,直到key被找到或者遍历完所有的sstfile。对于单个sstfile的查找则是O(logN),但当如果sstfile数量很多的情况下,最坏情况下可能每个sstfile都要被检查,因此整体的时间复杂度为O(k*logN)ksstfile的数量。

因此LSM的读操作比其他本地更新的结构慢,有一些技巧可以提高性能。

  • 最基本的方法就是页缓存,如LevelDB中的TableCache,将sstable按照LRU缓存缓存在内存中,减少二分查找的消耗。
  • 为每个文件创建索引,使用Block Index
  • 即便每个文件有索引,随着文件数量的增加,读操作依然会很慢。而且每次读操作还是要访问大量的文件,有没有一种方式能够快速的告诉我们我们想要的数据是不是在当前sstfile中,还不需要访问大量索引文件呢?答案是使用Bloom Filter,布隆过滤器如果告诉你key不在当前集合中,就百分之一百不会存在,但他告诉你在的话,却不一定在,有一定的概率实际上你想要查找的key并不在当前集合中,但这不影响Bloom Filter的高效,它避免的没有必要的文件读取。

所有的写操作都被分批处理,只写到顺序块上。另外,合并操作的周期操作会对IO有影响,读操作有可能会访问大量的文件(散乱的读)。这简化了算法工作的方法,我们交换了读和写的随机IO。这种折衷很有意义,我们可以通过软件实现的技巧像布隆过滤器或者硬件(大文件cache)来优化读性能。

Basic Compaction

总结

LSM是日志和传统的单文件索引(B+ treeHash Index)的中立,他提供一个机制来管理更小的独立的索引文件(sstable)。通过管理一组索引文件而不是单一的索引文件,LSMB+树等结构昂贵的随机IO变的更快,而代价就是读操作要处理大量的索引文件(sstable)而不是一个,另外还是一些IO被合并操作消耗。

参考

Terminology

Terminology

存储类型

RocksDB 有三个非常重要的结构memtablesstfilelogfile

  • memtable: 顾名思义是一个内存中的数据结构,memtable有分为两种,一种叫做active memtable,另一种叫做immutable memtable,当active memtable被写满就会变成immutable memtable,刷入到sstfile,成功保存到磁盘之后就可以将内存中的数据清空掉了。The format of a default sstfile
  • sstfile: sorted string table,有序字符串表,这个有序字符串就是数据的keysst是分层的,一层比一层大。上层的数据和下层数据的版本新于下层数据,当上层key命中后,不会查询下层的key,并且只有在compaction的时候才会删除旧版本的key
  • logfile: 当新的数据被写入时会被插入到memtable,通过选择开启WAL可以在写入之前先将数据操作写入logfile来保证内存写入数据的不丢失。logfile是一个磁盘上的顺序写入的日志文件。

Compaction

compaction主要包括两类:将内存中imutabledump 到磁盘上sst的过程称之为flush或者minor compaction。磁盘上的sst文件从低层向高层转储的过程称之为compaction或者是major compaction。对于minor compactionmajor compaction分别对应一组线程,通过参数rocksdb_max_background_flushes和rocksdb_max_background_compactions可以来控制。通过minor compaction,内存中的数据不断地写入的磁盘,保证有足够的内存来应对新的写入;而通过major compaction,多层之间的SST文件的重复数据和无用的数据可以迅速减少,进而减少sst文件占用的磁盘空间。对于读而言,由于需要访问的sst文件变少了,也会有性能的提升。由于compaction过程在后台不断地做,单位时间内compaction的内容不多,不会影响整体的性能,当然这个可以根据实际的场景对参数进行调整,compaction的整体架构可以参见图1。了解了compaction的基本概念,下面会详细介绍compaction的流程,主要包括两部分flush(minor compaction),compaction(major compaction),对应的入口函数分别是BackgroundFlush和BackgroundCompaction。

RocksDB Tuning

Amplification factors (放大因素)

其实对数据库系统的调优很大一部分工作是在写放大读放大空间放大这三个放大因子之间做取舍。

  • 写放大: 平均写入1个字节,引擎中在数据的声明周期内实际会写入n个字节(比如compaction操作会将数据合并压缩后再写一遍),其写放大率是n。也就是如果在业务方写入速度是10mb/s,在引擎端或者操作系统层面能观察到的数据写入速度是30mb/s,这时,系统的写放大率就是3。写放大过大会制约系统的实际吞吐。并且对于SSD来说,越大的写放大,也会导致SSD寿命缩短。
  • 读放大: 一个小的读请求,系统所需要读去n个页面来完成查询,其读放大率是n。逻辑上的读操作可能会命中引擎内部的cache或者文件系统cache,命中不了cache就会进行实际的磁盘IO,命中cache的读取操作的代价虽然很低,但是也会消耗 cpu。
  • 空间放大: 就是平均存储1个字节的数据,在存储引擎内部所占用的磁盘空间n个字节,其空间放大是n。比如写入10mb的数据,大小在磁盘上实际占用了100mb,这是空间放大率就是10。空间放大和写放大在调优的时候往往是互斥的,空间放大越大,那么数据就不需要频繁的compaction,其写放大就会降低;如果空间放大率设置的小,那么数据就需要频繁的compaction来释放存储空间,导致写放大增大。

Statistics

statistics是 RocksDB 用来统计系统性能和吞吐信息的功能,开启它可以更直接的提供性能观测数据,能快速发现系统的瓶颈或系统运行状态,由于统计信息在引擎内的各类操作都会设置很多的埋点,用来更新统计信息,但是开启statistics会增加5%~10%的额外开销。

** Compaction Stats **
Level Files  Size(MB) Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) Comp(cnt) Avg(sec) Stall(sec) Stall(cnt) Avg(ms)     KeyIn   KeyDrop
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
L0      2/0        15   0.5     0.0     0.0      0.0      32.8     32.8       0.0   0.0      0.0     23.0    1457      4346    0.335       0.00          0    0.00             0        0
L1     22/0       125   1.0   163.7    32.8    130.9     165.5     34.6       0.0   5.1     25.6     25.9    6549      1086    6.031       0.00          0    0.00    1287667342        0
L2    227/0      1276   1.0   262.7    34.4    228.4     262.7     34.3       0.1   7.6     26.0     26.0   10344      4137    2.500       0.00          0    0.00    1023585700        0
L3   1634/0     12794   1.0   259.7    31.7    228.1     254.1     26.1       1.5   8.0     20.8     20.4   12787      3758    3.403       0.00          0    0.00    1128138363        0
L4   1819/0     15132   0.1     3.9     2.0      2.0       3.6      1.6      13.1   1.8     20.1     18.4     201       206    0.974       0.00          0    0.00      91486994        0
Sum  3704/0     29342   0.0   690.1   100.8    589.3     718.7    129.4      14.8  21.9     22.5     23.5   31338     13533    2.316       0.00          0    0.00    3530878399        0
Int     0/0         0   0.0     2.1     0.3      1.8       2.2      0.4       0.0  24.3     24.0     24.9      91        42    2.164       0.00          0    0.00      11718977        0
Flush(GB): accumulative 32.786, interval 0.091
Stalls(secs): 0.000 level0_slowdown, 0.000 level0_numfiles, 0.000 memtable_compaction, 0.000 leveln_slowdown_soft, 0.000 leveln_slowdown_hard
Stalls(count): 0 level0_slowdown, 0 level0_numfiles, 0 memtable_compaction, 0 leveln_slowdown_soft, 0 leveln_slowdown_hard

** DB Stats **
Uptime(secs): 128748.3 total, 300.1 interval
Cumulative writes: 1288457363 writes, 14173030838 keys, 357293118 batches, 3.6 writes per batch, 3055.92 GB user ingest, stall micros: 7067721262
Cumulative WAL: 1251702527 writes, 357293117 syncs, 3.50 writes per sync, 3055.92 GB written
Interval writes: 3621943 writes, 39841373 keys, 1013611 batches, 3.6 writes per batch, 8797.4 MB user ingest, stall micros: 112418835
Interval WAL: 3511027 writes, 1013611 syncs, 3.46 writes per sync, 8.59 MB written

Parallelism options

LSM 架构的引擎,后台主要有两种线程,flushcompaction。在RocksDB中,两种线程有不同的优先级,flush优先级高,compaction优先级低。为了充分利用多核,RocksDB中的两种线程可以配置线程数。

  • max_background_flushes: 是后台memtabledump 成sstable的并发线程数。默认是1,但是当使用多个column family时,内部会存在多个memtable,可能会同时发生flush,如果线程是1,在写入量大的情况下,可能会导致flush不及时,出现无法写入的情况。
  • max_background_compactions: 是后台sstable flush的线程数量,因为一般 RocksDB 会有多个level,涉及多个sstable文件,并发compaction会加快compaction的速度,但是如果compaction过慢,达到soft_pending_compaction_bytes_limit会发生阻塞,达到hard_pending_compaction_bytes会停写。

General options

  • filter_policy: 这个就是每个sstablebloom filter,使用bloom filter可以大幅减少不必要的磁盘IO。在bits_per_key10的情况下,bloom filter错误率估计为1%,也就是存在如下情况:有1%的概率出现错误,key 实际上不存在于集合中,但是在bloom filter查询的结果错误的认为是存在的。这种情况导致会有1%的不必要的磁盘IO。bloom filter认为 key 不存在在集合中,就一定不存在。当然bits_per_key越大,bloom filter误判率越低,但是占用的内存和写放大会相应增加。
  • block_cache: 可以配置大小的LRU cache,用来缓存未经过压缩的block。由于访问cache需要加锁访问,当大部分数据都在cache中时,多线程并发访问cache可能会出现锁竞争的瓶颈,所以LRU cache还有一个shard_bits参数,将LRU cache分片,其实就是对锁进行拆分,不同分片的cache不会出现竞争。默认shard_bits是6,那么cacheshard数目就是2^6=64
  • allow_os_buffer: 操作系统buffer是用来缓存sstable文件的cachesstable在文件中是压缩的,所以操作系统buffer是对磁盘上的sstable文件blockcache
  • max_open_files: 最大打开文件数。RocksDB 对于打开文件的句柄也会放在cache中,当sstable文件过多,超过max_open_files限制后,会将cache中淘汰的文件句柄强制关闭,下次读取文件的时候再次打开。
  • table_cache_numshardbits: 和block_cache中的shard_bits作用一致,主要是为了拆分互斥锁。
  • block_size: RocksDB 中sstable文件的由block组成,block也是文件读写的最小逻辑单位,当读取一个很小的key,其实会读取一个block到内存,然后查找数据。默认的block_size大小为4KB。每个sstable文件都会包含索引的block,用来加快查找。所以block_size越大,index就会越少,也会相应的节省内存和存储空间,降低空间放大率,但是会加剧读放大,因为读取一个key实际需要读取的文件大小随之增加了。

Sharing cache and thread pool

有时候我们想在一个进程中运行多个 RocksDB 实例,RocksDB 为这些实例提供了一种共享block cachethread pool的方法。要共享block cache,需要为所有实例分配单个cache object

first_instance_options.block_cache = second_instance_options.block_cache = rocksdb::NewLRUCache(1GB)

这样两个实例就会共享总大小为1GBblock cache

Flushing options

RocksDB 中的写入在写WAL后会先写入memtablememtable达到特定大小后会转换成immutable membtale,然后会将数据从内存flush到磁盘的sstable

  • write_buffer_size: 配置单个memtable的大小,当memtable达到指定大小,会自动转换成immutable memtable并且新创建一个memtable
  • max_write_buffer_number: 指定一个 RocksDB 中memtableimmutable memtable总的数量。当写入速度过快,或者flush线程速度较慢,出现memtable数量超过了指定大小,请求会无法写入。
  • min_write_buffer_number_to_merge: immutable memtableflush之前先进行合并,比如参数设置为2,当一个memtable转换成immutable memtable后,RocksDB 不会进行flush操作,等到至少有2个后才进行flush操作。这个参数调大能够减少磁盘写的次数,因为多个memtable中可能有重复的key,在flush之前先merge后就避免了旧数据刷盘;但是带来的问题是每次数据查找,当memtable中没有对应数据,RocksDB 可能需要遍历所有的immutable memtable,会影响读取性能。

例如:

write_buffer_size = 512MB
max_write_buffer_number = 5
min_write_buffer_number_to_merge = 2

按上面的配置,如果数据写入速度是16MB/s,每32秒会生成一个新的memtable,每64秒会生成两个memtable进行mergeflush操作。如果flush速度很快,memtable占用的内存应该小于1.5G,当磁盘IO繁忙,flush速度慢,最多会有5个memtable,占用内存达到2.5G,后续就无法写入。

Level Style Compaction

Write stalls

RocksDB 在flushcompaction速度来不及处理新的写入,会启动自我保护机制,延迟写或者禁写。主要有几种情况:

Too many memtables

  • 写限速: 如果max_write_buffer_number大于3,将要flushmemtables大于等于max_write_buffer_number - 1write会被限速。
  • 禁写: memtable个数大于等于max_write_buffer_number,触发禁写,等到flush完成后允许写入
Stalling writes because we have 4 immutable memtables (waiting for flush), max_write_buffer_number is set to 5
Stopping writes because we have 5 immutable memtables (waiting for flush), max_write_buffer_number is set to 5

Too many level-0 SST files

  • 写限速: L0文件数量达到level0_slowdown_writes_trigger,触发写限速。
  • 禁写: L0文件数量达到level0_stop_writes_trigger,禁写。
Stalling writes because we have 4 level-0 files
Stopping writes because we have 20 level-0 files

Too many pending compaction bytes

  • 写限速: 等待compaction的数据量达到soft_pending_compaction_bytes,触发写限速。
  • 禁写: 等待compaction的数据量达到hard_pending_compaction_bytes,触发禁写。
    Stalling writes because of estimated pending compaction bytes 500000000
    Stopping writes because of estimated pending compaction bytes 1000000000
    

当出现write stall时,可以按具体的系统的状态调整如下参数:

  • 调大max_background_flushes
  • 调大max_write_buffer_number
  • 调大max_background_compactions
  • 调大write_buffer_size
  • 调大min_write_buffer_number_to_merge

Bloom filters and index

RocksDB 中使用bloom filter来尽可能避免不必要的sstable访问,在 RocksDB 中bloom filter有两种: block-based filterfull filter

block-based filter

这种filter是保存在每个block内部,一个sstable file有多个block。所以每次访问sstable需要先访问一次block索引,找到对应的block后加载bloom filter或者是在cache中获取对应的filter查询。

full filter

每个sstable文件只有一个filter,在访问sstable之前可以事先判断key的存在性,能够避免不存在key的索引访问。

一个典型的256MBSST文件的index/filter的大小在0.5~5MB,比系统内默认的block大很多倍,这种场景对于block cache不友好,LRU cache是按block来进行置换,一部分block失效会导致重复读取多次SST加载indexfilter

对于上面大SST文件的index或者filter block,RocksDB 支持两级index,切分index/filter。每次读取cache的粒度变小,cache更高效。

  • bloom_bits_per_key: 平均每个 key 需要的bloom filter空间。配置bloom filter的容量,默认是10,存在1%的判错概率。
  • cache_index_and_filter_blocks_with_high_priority: 可以配置 RocksDB 高优先 cache index和filter,优先剔除数据block
  • pin_l0_filter_and_index_blocks_in_cache: 使level 0中的SSTindexfilter常驻cache

配置实例

存储介质 flash

thread_pool = 4
options.options.compaction_style = kCompactionStyleLevel;
options.write_buffer_size = 67108864; // 64MB
options.max_write_buffer_number = 3;
options.target_file_size_base = 67108864; // 64MB
options.max_background_compactions = 4;
options.level0_file_num_compaction_trigger = 8;
options.level0_slowdown_writes_trigger = 17;
options.level0_stop_writes_trigger = 24;
options.num_levels = 4;
options.max_bytes_for_level_base = 536870912; // 512MB
options.max_bytes_for_level_multiplier = 8;

全内存

options.allow_mmap_reads = true;
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(10, true));
table_options.no_block_cache = true;
table_options.block_restart_interval = 4;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
options.level0_file_num_compaction_trigger = 1;
options.max_background_flushes = 8;
options.max_background_compactions = 8;
options.max_subcompactions = 4;
options.max_open_files = -1;
ReadOptions.verify_checksums = false

Snapshot

A snapshot captures a point-in-time view of the DB at the time it’s created. Snapshots do not persist across DB restarts.

Data Files

先看一下 RocksDB 存储在磁盘上的文件有哪些

$ ls -l /$ROCKSDB_DATA_DIR
-rw-r--r-- 1 root root  13K Sep  6 07:17 057373.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057374.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057375.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057376.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057377.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057378.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057379.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057380.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057381.sst
-rw-r--r-- 1 root root  13K Sep  6 07:17 057382.sst
-rw-r--r-- 1 root root   16 Sep  5 21:11 CURRENT
-rw-r--r-- 1 root root   37 Sep  5 21:11 IDENTITY
-rw-r--r-- 1 root root    0 Sep  5 21:11 LOCK
-rw-r--r-- 1 root root 267M Sep 17 09:01 LOG
-rw-r--r-- 1 root root 3.3M Sep  6 07:17 MANIFEST-000006
-rw-r--r-- 1 root root  31K Sep  5 21:11 OPTIONS-000024
-rw-r--r-- 1 root root  33K Sep  5 21:11 OPTIONS-000026

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,一毛也是爱

打开支付宝扫一扫,即可进行扫码打赏哦