rocksdb理解

rocksdb是在leveldb的基础上优化而得,解决了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的微妙之处。

rocksdb的column family

column family的具体使用场景,官方并没有给出非常好的说明,rocksdb支持跨column family的原子写操作,说明官方认为column family的数据之间还是有一定的关系的,而column family的数据文件是分割开的,包括sst文件和memtable都是不会共用的,所以官方还是希望不同column family的数据进行隔离。所以我觉着一个应用场景就是不同的数据混跑在同一个db上,这个仅是个人感觉,欢迎大家讨论。那么不同column family之间会怎样互相干涉呢?

Q:多column family的flush是怎么进行线程分布的?

A:可以共用一个线程池,所以写的多的会多占用线程。也可以分开配置线程池(指定不同的env),这样就会不互相干扰。

Q:多column family的内存是怎么分配的?

A:内存主要有两方面,第一方面是write buffer,第二方面是block cache。

write buffer是每个column family单独享有的,block cache可以配置成column family级别,也可以配置成整个db的column family共享一个block cache,也可以配置成多个db共享一个block cache。

rocksdb的文件类型

主要有以下几种类型sst文件,CURRENT文件,manifest文件,log文件,LOG文件和LOCK文件

sst文件存储的是落地的数据,CURRENT文件存储的是当前最新的是哪个manifest文件,manifest文件存储的是Version的变化,log文件是rocksdb的write ahead log,就是在写db之前写的数据日志文件,LOG文件是一些日志信息,是供调试用的,LOCK是打开db锁,只允许同时有一个进程打开db。

ColumnFamilyOptions

  这些option都是column family相关的,可以对不同的column family赋不同的值。

  inplace_update_support: 字面含义是是否支持在原位置更新,如果支持的话,那么原来的数据就被擦除了,所以snapshot和iterator保留当时的数据的逻辑就没法实现了

  num_levels: 记录的是version的level的数目,默认是7,即0~6

  target_file_size_base: level1的sst文件的大小,默认为2MB

  target_file_size_multiplier: level1以上的sst文件大小,乘数因子默认是1,即所有level的文件大小都是2MB

    level0的文件大小是由write_buffer_size决定的,level1的文件大小是由target_file_size_base决定的,level2及以上,size = target_file_size_base * (target_file_size_multiplier ^ (L - 1))

  max_bytes_for_level_base: level1的sst总的文件总和大小,默认是10MB

  max_bytes_for_level_multiplier: level2及以上的level的sst文件总和大小的乘数因子,默认是10,

    level0的sst文件总和大小是level0_stop_writes_trigger * write_buffer_size,因为level0的文件数目达到level0_stop_writes_trigger时候就会停止write。

    level1及以上的文件总和大小是max_bytes_for_level_base * (max_bytes_for_level_multiplier ^ (L - 1)),默认的level0是4MB * 24 = 96MB,level1是10MB,level2是100MB,level3是1G,level4是10G。。。

rocksdb原子操作的实现

  rocksdb的一个WriteBatch是原子操作,要么全部成功,要么全部失败,具体的实现原理是在整个log的写的过程中只会调用Write操作,最后会调用一次flush,所以如果中间发生机器crash,所有的都会失败,否则所有的都会成功。

rocksdb写和读放大

  rocksdb的写会写WAL(Write Ahead Log),如果sync的话,会写一次磁盘,然后会写memtable

  写rocksdb的时候有可能会卡住,详见下面的rocksdb的写stall

  rocksdb的读,会首先读memtable,如果memtable没有找到的话,会读下面level的数据,由于level0的多个sst会有交叠,所以每个sst都会通过filemeta判断在不在最小和最大的范围内,如果在就需要读这个sst的文件内容,来查看,其他level的sst文件不会有数据交叠的情况,所以只会有一个文件可能含有这个数据。

  可以看出来读放大还是比较严重的。rocksdb为了减少读放大,增加了cache.

  读cache

    rocksdb的读cache分为两部分:table cache和block cache。这两个都是LRUCache

    block cache存储的block,包括index block和filter block(通过options可以配置)

    table cache存储的是table,是整个文件的meta信息和Foot信息。table_cache_size的消耗内存的大小是有Options里面的max_open_files决定的。

  bloomfilter:

    bloomfilter的增加并不能减少写放大,因为bloomfilter是table范围的或者block范围的,而且bloomfilter是存储在文件中的,那么必须把这些从文件里面读出来后才能起到作用。

rocksdb的版本管理

rocksdb的版本相关的数据结构有Version、VersionStorageInfo、VersionBuilder、VersionEdit、SuperVersion和VersionSet。

VersionEdit描述的是版本的变更,其主要操作为AddFile和DeleteFile,分别表示,在某个level上增加文件和删除文件,都是版本变更的操作。

VersionBuilder是生成Version的工具,所以其有两个主要函数:

void Apply(VersionEdit* edit);
void SaveTo(VersionStorageInfo* vstorage);

分别是应用某个VersionEdit和将现在的版本Saveto某个VersionStorageInfo

VersionStorageInfo是Version的信息的存储结构,每一个Version的sst文件信息都保存在VersionStorageInfo。

Version是一个完整的版本。sst文件信息存储在VersionStorageInfo。可以在这个版本上Get数据。

SuperVersion是db的一个完整的版本包含的所有信息,包含当前的Memtable,imm和一个Version。也就是Version包含的是sst数据信息,SuperVersion包含的是Version的数据和memtable中的数据。

VersionSet是整个db的版本管理,并维护着manifest文件。每个column family的版本单独管理,在ColumnFamilyData这个数据结构里面有current Version。

rocksdb的Flush

Flush是指将memtable的数据导入到sst中,变成持久化存储,就不怕数据丢失了。

1.首先在memtable的add的时候,会检测是否memtable的大小达到了max write buffer,如果是就将should_flush_置为true,并会在WriteBatch的Handler里面调用CheckMemtableFull,将当前column family加入flush_scheduler。

2.在Write的时候,调用ScheduleFlushes,将需要flush的column family的memtable切换一个新的,同时将原来的memtable加入cfd的imm中,如果这个column family data的imm数量大于min_write_buffer_number_to_merge,并启动一个新的线程调用BGWorkFlush

由于真正的Flush过程是在另一个线程完成的,所以这个地方并不会block写过程

另外,如果total_log_size大于max_wal_log_size并且不是只有一个column family,也会触发flush,因为flush能将memtable持久化到磁盘上,同时对应的wal就可以删除了

rocksdb的compaction

rocksdb的compaction的触发条件有两类:

第一类是某一个level的数据太多

  1. VersionStorageInfo的compaction_score_的计算方法是level0的是当前文件数目/level0_file_num_compaction_trigger,其他层是该层当前文件大小总和/该层的所有文件大小总和最大值
  2. 基于level的存储的compaction总的来说,就是一次挑选某一个level的一个文件,然后将该文件和高level的多个相交文件merge,最后生成多个高level的文件。具体的细节是:每次会挑选compaction score最高的一个level,并在这个level中找到一个文件大小最大,并且上一个level的相交文件没有在compaction的一个文件

第二类是seek太多

疑问:

如果option里面soft_rate_limit设置的为0.0和1之间,compaction并不会触发,但是会触发write delay,这是为什么?

rocksdb的写stall

在DBImpl也就是db的实例里面有一个WriteController,同时在ColumnFamilySet里面也有这个WriteController的指针,这个数据结构会控制db的写stall行为。

在ColumnFamily进行SuperVersion变更的时候(增加新memtable,flush增加sst,compaction)都会查看需不需要stall Write,stall的条件是:

1)imm的数量大于等于option允许的最大数目

2)level0的文件的数量大于option允许的数目

如果没有满足上面两项,但是compaction score比较大会delay写

rocksdb的write ahead log(WAL)

  1. 每次写操作,rocksdb会先写write ahead log,然后才会写db
  2. write ahead log可以配置到单独的空间,并且可以配置WAL文件的单独的删除机制。这种原因是为了保存WAL文件,达到特殊的目的,比如,其他sst文件放在不可靠存储里面,而WAL放到可靠存储里面。

rocksdb的缺点

1.column family之间的隔离做的不是非常好,因为一个db只有一个WriteController,那么一旦一个db中的一个column family发生了阻塞,比如写太快,那么就会阻塞其他的column family的写。

2.多进程compaction和flush的效果我持怀疑态度,因为这两个主要是磁盘操作,多进程并不会有很好的效果。

时间: 2024-10-21 18:11:43

rocksdb理解的相关文章

融合RocksDB, Pregel, Foxx & Satellite Collections 怎样使数据库性能提升35%?

经过数月的研发测评,开源多模型数据库ArangoDB 终于发布了其 3.2 正式版,该版本消除了两个重大的障碍,添加了一个期待已久的功能,还集成了一个有趣的功能.此外,官方团队表示新版本将 ArangoDB 的性能平均提高了 35%.同时,与 3.1 版本相比,还减少了内存的占用.集群管理方面也有了大幅度的改进. 具体如下: RocksDB 存储引擎: 与 Facebook 的 RocksDB 存储引擎的集成,使得其成为架构中第一个可插拔的存储引擎,用户现在可以使用与磁盘一样多的数据.加上 Ro

融合RocksDB, Pregel, Fault-Tolerent Foxx & Satellite Collections 怎样使数据库性能提升35%?

摘要: 经过数月的研发测评,开源多模型数据库ArangoDB 终于发布了其 3.2 正式版,该版本消除了两个重大的障碍,添加了一个期待已久的功能,还集成了一个有趣的功能.此外,官方团队表示新版本将 ArangoDB 的性能平均提高了 35%.同时,与 3.1 版本相比,还减少了内存的占用.集群管理方面也有了大幅度的改进. 具体如下: RocksDB 存储引擎: 与 Facebook 的 RocksDB 存储引擎的集成,使得其成为架构中第一个可插拔的存储引擎,用户现在可以使用与磁盘一样多的数据.加

对LevelDB的“升级版”存储引擎RocksDB的调研成果

Google的leveldb是个很优秀的存储引擎,但还是有一些不尽人意的地方,比如leveldb不支持多线程合并,对key范围查找的支持还很简单,未做优化措施,等等.而Facebook的RocksDB是个更彪悍的引擎,实际上是在LevelDB之上做的改进,在用法上与LevelDB非常的相似,两者的对比可以参考下面的参考资料1. 这里之所以要调研rocksdb是因为rocksdb中加入了prefix bloomfilter的实现,能够支持对范围查找的优化,对我目前的项目很有参考意义,下面是我调研和

看图了解RocksDB

摘要: 它是一个高性能的Key-Value数据库.设计了完善的持久化机制,同时保证性能和安全性.能够良好的支持范围查询,因为K-V记录就是按照Key来排序的. 下图为写入的流程: 可以看到主要的三个组成部分,内存结构memtable,类似事务日志角色的WAL文件,持久化的SST文件. 它是一个高性能的Key-Value数据库.设计了完善的持久化机制,同时保证性能和安全性.能够良好的支持范围查询,因为K-V记录就是按照Key来排序的. 下图为写入的流程: 可以看到主要的三个组成部分,内存结构mem

Python——深入理解urllib、urllib2及requests(requests不建议使用?)

深入理解urllib.urllib2及requests            python Python 是一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年,Python 源代码同样遵循 GPL(GNU General Public License)协议[1] .Python语法简洁而清晰,具有丰富和强大的类库. urllib and urllib2 区别 urllib和urllib2模块都做与请求URL相关的操作,但

关于SVM数学细节逻辑的个人理解(三) :SMO算法理解

第三部分:SMO算法的个人理解 接下来的这部分我觉得是最难理解的?而且计算也是最难得,就是SMO算法. SMO算法就是帮助我们求解: s.t.   这个优化问题的. 虽然这个优化问题只剩下了α这一个变量,但是别忘了α是一个向量,有m个αi等着我们去优化,所以还是很麻烦,所以大神提出了SMO算法来解决这个优化问题. 关于SMO最好的资料还是论文<Sequential Minimal Optimization A Fast Algorithm for Training Support Vector

2.2 logistic回归损失函数(非常重要,深入理解)

上一节当中,为了能够训练logistic回归模型的参数w和b,需要定义一个成本函数 使用logistic回归训练的成本函数 为了让模型通过学习来调整参数,要给出一个含有m和训练样本的训练集 很自然的,希望通过训练集找到参数w和b,来得到自己得输出 对训练集当中的值进行预测,将他写成y^(I)我们希望他会接近于训练集当中的y^(i)的数值 现在来看一下损失函数或者叫做误差函数 他们可以用来衡量算法的运行情况 可以定义损失函数为y^和y的差,或者他们差的平方的一半,结果表明你可能这样做,但是实际当中

理解信息管理系统

1.信息与数据的区别是什么? 数据是记录客观事物,可鉴别的符号,而信息是具有关联性和目的性的结构化,组织化的数据.数据经过处理仍是数据,而信息经过加工可以形成知识.处理数据是为了便于更好的解释,只有经过解释,数据才有意义,才可以成为信息.可以说信息是经过加工以后,对客观世界产生影响的数据. 2.信息与知识的区别是什么? 信息是具有关联性和目的性的结构化,组织化的数据,知识是对信息的进一步加工和应用,是对事物内在规律和原理的认识.信息经过加工可以形成知识. 3.举一个同一主题不同级别的数据.信息.

深度理解div+css布局嵌套盒子

1. 网页布局概述 网页布局的概念是把即将出现在网页中的所有元素进行定位,而CSS网页排版技术有别于传统的网页排版方法,它将页面首先在整体上使用<div>标记进行分块,然后对每个快进行CSS定位以及设置显示效果,最后在每个块中添加相应的内容.利用CSS排版方法更容易地控制页面每个元素的效果,更新也更容易,甚至页面的拓扑结构也可以通过修改相应的CSS属性来重新定位.  2. 盒子模型 盒子模型是CSS控制页面元素的一个重要概念,只有掌握了盒子模型,才能让CSS很好地控制页面上每一个元素,达到我们