哈希表索引、SStable和LSM-Tree

最简单的数据库

从最基本的层面来看,数据库的核心功能应该只有两个:存储数据并在我们查询时返回那些数据

在我们本文的讨论过程中我们可以假设一个最简单的数据引擎:
我们在磁盘中存储一个db文件,任何写入操作都会在该文件末尾进行追加(也就是写入相同键时不会覆盖之前的值)。至于读取,我们需要返回最后一个键对应的值。

db_set(){
	echo "$1,$2">>database
}

db_get(){
	grep "^$1," database| sed -e "s/^$1,//"|tail -n 1
}

这种数据库的写入性能应该是无所挑剔的,但问题也很明显,我们的读取操作都是o(n)的

哈希表索引

为了高效查找数据库中特定键的对应值,我们需要额外维护一个新的数据结构:索引。所有索引的基本想法都是保留额外的元数据,作为‘路标’帮助定位想要的数据
索引不会影响数据内容,只会影响查询性能,对于写入,任何类型的索引都会降低写入速度,因为我们都需要在写入时更新索引

Key-Value存储与大多数编程语言所内置的字典结构都十分相似,通常采用hash map来实现,这里我们不做详细描述。采用hash表索引的最简单策略就是:保存内存中的hashmap,把每个键一一映射到数据文件中特定的字节偏移量。

在这里插入图片描述
理论上应该没有问题,但可能需要进一步进行优化。

  • 对文件进行顺序追加必然导致大量数据冗余,如何解决?
    一般的解决方式是用后台线程,对文件进行定时的压缩合并,对于相同的键,只保留最新的值。
  • 那么删除数据呢?
    删除数据在对应的数据上标记一个墓碑,在进行合并日志段时,一旦发现标记墓碑,就会丢弃该记录。
  • crashSafe:
    由于是对文件进行追加写,内存中的索引文件会丢失但是具体的数据文件不会。我们可以通过扫描磁盘文件重新建立索引,但由于是O(n)操作,在文件过大时会消耗大量时间。

既然采用了hash索引为甚么不在更新数据时进行原地更新覆盖,而是继续追加写呢?

  • 顺序写要比随机写性能高很多,在旋转式磁盘上很容易理解这一点,实际上SSD上也适用
  • 如果覆盖,我们无法在崩溃恢复时判断当前值是否是最新值
  • 避免出现碎片化问题

hash索引的问题

  • hash索引要求要能将所有的索引加载进内存。尽管理论上hash索引一部分存放在磁盘中仍然可以工作,但是磁盘上的hashmap表现很差,因为访问hash索引存在大量的随机访问,不适用局部性原理,可能会导致磁盘和内存的不断替换
  • 区域查询效率太低,由于索引不是顺序的,区域查询只能使用逐个查找的方式查询每一个键

SSTable和LSMTree

Sorted String Table(SSTable)–是存储,处理和交换数据集的最流行的输出之一。正如名字本身所包含的意思一样,SSTable是一个简单的抽象,用来高效地存储大量的键-值对数据,同时做了优化来实现顺序读/写操作的高吞吐量。

  • SStable在功能上只是对hash加入了一个按键值排序。
  • 由于是排序数据,我们不必像hash索引一样记录所有数据的位置,索引可以是稀疏的,例如对于段文件中的上千条数据,只保留一个索引

例如:对于数据键1~100000,我们每隔1000个数据保留一个索引,当查找5500时,对应索引应该是5000,之后向后查找500条(或者使用二分)。

使用方法似乎很好理解,麻烦的是构建和维护SStable。SStable基本工作流程是:

  • 写入时将内容插入内存中的排序数据结构(例如红黑树)
  • 当内存大于一定阈值时将其写入磁盘,作为磁盘的一部分
  • 如果接收到新的读取请求,要先尝试在内存中读取,其次是磁盘的最新排序部分,然后是次新的,依次类推
  • 后台进程周期性将各个排序部分归并,并且出现相同数据时只会保留最新值。

如果使用sstable,先进行内存写,所以我们也要考虑日志系统,类似innodb里redolog方式来保证持久性。

LSM-Tree 全名叫Log-Structured Merge Tree,最早建立在日志结构文件之上,现在基于合并和压缩排序文件原理的存储引擎都统称为LSM存储引擎。我们通常把LSM看成一种思想:保存在后台合并的一系列SStable

这种思想简单且有效:

  • 即使数据集远大于内存,LSM-tree也能正常工作
  • 由于键值有序,范围查询相比于hash表有很大优势
  • 由于写入是顺序的(归并是后台线程在空闲时间做的)LSM-tree可以提供非常高的写入吞吐量

优化:在LSM系统中查找一个不存在的键时会导致查询时间长,因为要从最新的数据一直往前查找,所以lsm一般会使用布隆过滤器进行优化

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值