掘金 后端 ( ) • 2024-04-27 09:17

theme: smartblue

前言:

bitcask是由一个做分布式存储的公司riak所提出,论文地址https://blog.csdn.net/qq_51898139

其目的是想搞一个读写低延迟的存储数据库。 其核心思想是通过对磁盘写入采取追加写达到写入低延迟,再在内存中构造数据索引达到读低延迟的策略。然后再一步步优化衍生的缺陷,例如数据冗余

架构总览:

image.png

该存储模型设计主要可分为三个模块,

内存索引区

磁盘存储区

磁盘合并区

内存索引区:

该区域主要是在内存中存放数据存放在磁盘中所对应的位置{key,pos} 对应位置主要是包括所在文件ID以及偏移量

索引的数据结构我们可以使用btree、skipList都是可以的。

因此我们在写数据的时候会先追加写入到文件当中,然后再将文件ID、偏移量存在内存作为索引。

在读数据时就可先读内存看是否存在,再根据索引去读取数据

在删除数据时一样将删除状态的数据去追加写入到文件中,在merge数据时再进行真正的清理,然后再在内存删除对应索引,这样在读数据也不会读到已经删除的数据

磁盘存储区:

在磁盘存储区主要包含两部分文件,active file + old files,一个活跃文件+多个旧的数据文件。写入时就只会在活跃文件中写入,当活跃文件的数据大小超过设定阈值时,它又会转变为oldfile然后创建新的active file进行写入操作。

磁盘合并区:

在磁盘合并区主要是对数据文件中的多余的无效数据进行清理,清理逻辑主要是依次读取数据文件将文件中key对应的fileIDoffset与内存中存储的做比对,能够对应上的说明是最新的数据,则保留下来。。

而bitcask合并时并不会真的把数据进行清理了,因为如果真的删除,那么对同一文件操作,会与用户的读写操作抢占锁,导致读写性能下降,因此采取的是读取原数据,然后将最新的数据去写到新的区(磁盘合并区),然后在下一次启动该db时再进行一个merge操作,删除冗余数据。

其次在磁盘合并区bitcask论文中还会存放hint文件,其中存放的是merge过的数据的索引位置,为什么要存放,后面再解释。

数据记录格式:

image.png

存在在文件中的数据编码格式一般可以是这个样子。

crc:在写入时对后面五个字段进行crc计算存入,然后在读取时我们就可以通过读取时间进行crc校验看存入的数据是否损坏

type:主要存放数据的类型 nomal or deleted,因为写入数据为追加写入,删除数据的记录也会追加写入,因此需要一个type记录该数据的类型,

keySize,valSize主要是为了解码时能够获取key,value的大小进而拿到key和value

key,value:存放数据kv对

启动流程:

image.png 在启动DB时,由于索引是存放在内存中,所以启动时还需要去读取一遍数据去加载索引到内存当中。

但是在这之前,需要先去merge区先去合并数据,将无效数据清除掉释放空间。而merge的数据可以通过hint文件去直接读索引加载。如果在merge时不写入hint文件,那么在此时加载索引时还需要重复去数据文件加载索引。相比之下会慢不少。

总结:

以上是我对bitcask大致的解析。当然在基于bitcask编写一个存储引擎时值得主要的关注点远不止这些,这些只是核心点。