本文是《从零实现 KV 存储》课程的面试要点总结,相当于只要你学习了课程,以下提到的内容都是你自己完成的。对课程感兴趣的同学可以进这个链接查看详情:https://w02agegxg3.feishu.cn/docx/Ktp3dBGl9oHdbOxbjUWcGdSnn3g
项目概述
基于 Bitcask 模型,兼容 Redis 数据结构和协议的高性能 KV 存储引擎 设计细节
结果
我开发的项目是一个基于 Bitcask 存储模型的 KV 数据库。bitcask 是一种高性能的持久化存储引擎,其基本原理是采用了预写日志的数据存储方式,每一条数据在写入时首先会追加写入到数据文件中,然后更新内存索引,内存索引存储了 Key 和 Value 在磁盘上的位置,读取数据时,会先从内存中根据 key 找到对应 Value 的位置,然后再从磁盘中取出实际的 Value。
基于这种模型,其读写性能都非常高效快速,因为每次写入实际上都是一次顺序 IO 操作,然后更新内存,每次读取也是直接从内存中找到对应数据在磁盘上的位置。
这个问题的答案因人而异,可以根据自己的情况来回答,例如:
对数据库存储系统实现的好奇心,看到了对应的 Bitcask 的论文,想要自己去实现
弥补 redis 的缺陷,因为 redis 是一种基于内存的数据库,在数据量较大的情况下,对内存的压力会非常大,而 Bitcask 可以规避这个缺点,显著降低内存使用量
参加数据库比赛,针对性的设计了一种存储引擎
现有的存储引擎例如基于 B+ 树,读性能稳定,但是写数据是随机 IO,性能较差,LSM Tree 写性能优秀,但是读性能不稳定,读放大、写放大、空间放大问题严重;而 Bitcask 存储模型的读写性能则非常的稳定快速。
缓存系统
KV 数据库可用作缓存系统的后端存储,以提供快速的数据访问和响应能力。由于 Bitcask 存储模型具有高性能和低读写放大的特性,它适合存储频繁访问的热数据,提供快速的缓存读取操作。
日志存储
KV 数据库可以作为日志存储系统使用,将日志数据持久化到磁盘上的日志文件中。Bitcask 存储模型的追加写入方式使得日志的写入操作非常高效,确保了日志的可靠存储和后续分析。
Key 小 Value 大的 KV 数据存储
Bitcask 将 key 和对应的索引都维护在了内存当中,这样如果 key 较小的话,那么内存当中能够维护的数据量就更多,并且 Value 是在磁盘上存储的,因此可利用磁盘更大的空间来存储 Value。
优点
这是由于 Bitcask 存储模型文件的追加写入特性,充分利用顺序 IO 的优势。
写入的数据不需要在磁盘上排序,Bitcask 的日志结构文件设计在写入过程中减少了磁盘磁头的移动。
数据访问涉及对内存中的索引数据结构进行直接查找,这使得即使数据集非常大,查找数据也非常高效。
内存索引数据结构直接指向数据所在的磁盘位置,不需要多次磁盘寻址来读取一个值,有时甚至不需要寻址,这归功于操作系统的文件系统缓存以及 WAL 的 block 缓存。
写入操作最多需要一次对当前打开文件的尾部的寻址,然后进行追加写入,写入后会更新内存。这个流程不会受到数据库数据量大小的影响,因此性能稳定。
在大多数系统中,备份可能非常复杂。Bitcask 通过其只追加写入一次的磁盘格式简化了此过程。任何按磁盘块顺序存档或复制文件的工具都将正确备份或复制 Bitcask 数据库。
支持批处理操作,这些操作是原子、一致和持久的。批处理中的新写入操作在提交之前被缓存在内存中。如果批处理成功提交,批处理中的所有写入操作将持久保存到磁盘。如果批处理失败,批处理中的所有写入操作将被丢弃。
即一个批处理操作中的所有写入操作要么全部成功,要么全部失败。
缺点
始终将所有 key 保留在内存中,这意味着您的系统必须具有足够的内存来容纳所有的 key。
数据库启动时,会加载所有的数据,并且会重放所有的操作,以此来构建内存索引,如果数据量较大,这个过程可能会非常漫长
实现了 Bitcask 论文中提到的 Merge 方案,Merge 实际上就是对磁盘数据空间进行清理的操作,其基本执行流程是遍历所有的数据,并将有效的数据进行重写,然后使用新的文件替换旧的文件,以此达到回收空间的效果。
追问:
采用了预写日志的方式,和其他大多数系统一样,WAL 通常是保证事务原子性和持久性的关键,在 Bitcask 存储模型中,比较特殊的是 WAL 文件本身就是数据文件,所以天然可以保证原子性,我们在写入的时候加上了一个完成的标识,并且给每一批次的数据都附了一个全局递增的 id,只有全部提交完成了,这个批次的数据才算完成,否则都不会进行加载。
LevelDB 是经典的 LSM Tree 存储模型,其基本架构大致分为了 WAL、memtable、SSTable,数据写入首先会到 wal 中保证持久化,然后更新到内存的 memtable 中,如果 memtable 满了,则 flush 到磁盘的 sstable 中。
读数据会从 memtable 查找,如果没找到,则从磁盘上的多级 sstable 中查找,读性能不稳定。
BoltDB 是 B+ 树存储模型,读性能稳定,但是写入是随机 IO,性能较差。
Redis 是一种纯内存的数据结构服务,也可以持久化到磁盘中,但其实际上是一种面向内存的 KV 存储,数据量受到内存容量的影响。
而 Bitcask 存储模型,写性能和 LSM 模型相当,读性能也很稳定,读写都是一次磁盘 IO 操作即完成,并且相较于 Redis,Value 是不会存储到内存中,节省了内存空间,并且性能能够和 Redis 维持在一个数量级。
注:以上是我个人能够想到的一些东西,但在实际场景中,可能问的问题会更多,大家如果有相关的经验,可以在这里留言分享!
本文分享自 roseduan写字的地方 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!