如何从0到1实现一个基于bitcask的kv存储引擎

谈谈在Bitcask中用读写锁实现并发控制的性能表现 可以看到,对于存储引擎,IO才是最大的瓶颈。那么为什么MySQL要实现MVCC呢。MySQL一般是读多写少,所以做MVCC收益比较大。另外MySQL是有数据缓存在内存的,可能对于大多数读取操作来说,根本不需要磁盘IO去读取。这样一来,又是一大波优化。但是当我们把目光拉会到bitcask,读写操作都需要经过磁盘,批次写只是延迟写入,我认为这样只是降低了写操作的比例,因为几个写操作合并成一个写入磁盘了。本质上没多大差别。所以这也符合了我一开始心中的想法,读写锁,也没那么不堪。 阅读详情

愿景

​ 今年大部分业余时间都在nutsdb的开源贡献上,nutsdb是基于bitcask模型实现的持久化存储引擎,提供了诸如list,set等多种丰富的数据结构。近来很多小伙伴,其中也有一些我的好朋友陆陆续续加入到这个项目上来。为了帮助小伙伴们快速熟悉整个项目,我会把之前写的一些文章分享给他们,但是我觉得这样可能还是不太够,因为之前做的是关于性能优化的事情,文章是偏向于性能优化方面的思考。对于bitcask整体架构的解释,实现,感觉写着墨不多,意识到这一点之后,我就想写一篇文章来解释一下bitcask的核心概念,并且花了几个小时的时间写下了一个简单版本的demo(写unit test测试之后,几百行代码只有一个小bug,小窃喜)。在帮助大家了解了核心概念之后,就算是有了一个基本的入门了,后面可以更快的参与到项目中来。这是我写这篇文章的初衷,也同时欢迎更多的小伙伴参与到这个项目中来。

这篇文章会结合bitcask论文以及我的代码实现进行分析,主要是讲的是“怎么做”,对于“为什么”可能侧重并不多。另外该bitcask实现我已经开源到我的github上,可以在github上看到更多实现细节,链接:https://github.com/elliotchenzichang/tiny-bitcask ,欢迎star。

整体架构

​ 该怎么开始这个故事呢,我思虑良久,决定从db的整体架构开始阐述,然后在自底向上的讲述每一个部分的实现细节。为什么是自底向上呢?因为从下往上讲可以从点到线,从线到面,慢慢的拨开云雾,看见一整个db的实现,会有一种世界在面前缓缓打开的感觉。另外,如果是从上到下来看结合代码讲的时候,可能有一些代码会变得不好解释。

​ 言归正传,如上面所说我们要实现一个基于Bitcask模型的kv存储引擎,那么对于持久化存储引擎而言,数据的最终归宿是磁盘。而我们知道,程序是运行在内存中的,所以存储引擎提供需要做的就是以某种方式把用户给的数据存进磁盘,也以某种方式将用户的数据从磁盘里面拿出来使用。至于这些方式的设计的是否高效,就是存储引擎设计的艺术所在。其实粗略来看,存储引擎的整体架构整体如下图,内存中放置索引,可以直接(比如bitcask)或者间接(比如leveldb的SST的索引形式)的找到数据,磁盘中存储用户的数据,可以是同构的数据文件(比如bitcask全是data_file),也可以是异构的数据文件(比如leveldb的WAL log和SST)。

1

bitcask采用的是一种比较简单的形式,如下图所示,内存中会记录每条数据在磁盘中的位置,以及key和value的长度,这样就可以直接通过一次系统调用在数据存放的位置把它拿出来了。

image-20221107175652214

大概讲述了整体的架构之后我们来看看代码实现中主要的对象有哪些,自底向上的看。

  1. Entry:代表db中一条数据的信息。
  2. Storage:与文件系统打交道的对象,包括了写入,读取数据。
  3. Index,索引,记录一条数据的具体信息,主要是数据在磁盘中的位置。
  4. db,db的实体。包含了db的各种操作,包括读取,写入数据。

接下来我们看看具体的实现,下面解析会结合代码分析,在代码的关键部分我已经写好了注释。系好安全带,发车了!

1. 数据的编码与解码

​ 首先我们要讲的是,一条数据是以怎么样的形式存进磁盘的。磁盘才不理你是放进来的是什么东西,他只知道在他身上存放的是一堆二进制,至于那些二进制是什么,由放进来的应用程序来定义。大概逻辑如下图所示,应用程序需要自己实现对磁盘数据写入和读出时候的编码和解码。image-20221120001820998

​ 在kv存储引擎中一条数据在磁盘中的是如下图所示。整体上来看我们会有一个meta,key,value,key和value就不必多说了,就是真实的数据部分。那么meta是什么呢?meta是这条数据的元数据,也就是起到描述作用的数据,比如key有多长,value有多长,在什么位置,以及写入数据的时间,其实这个时间戳可以理解为数据的版本,可以是物理时间,也可以是逻辑时间(逻辑时间需要自己实现)。meta的crc部分是做数据校验用的,因为磁盘有时候会出现一些意外,比如一个比特位上的数据发生了变化,从存储1变成0或者从0到1,在或者磁盘数据丢失,也是可能的,所以要加上crc在读出数据的时候再读计算出crc的值和存在磁盘里的crc做比较,如果不一致说明数据出现了问题。

image-20221120003433613

​ 下面是代码实现的节选,其中包含了Entry和Meta这两个主要数据结构的定义,以及数据编码的实现。在写入数据的时候,我们会将一个内存中的Entry对象Encode编码成字节数组然后将字节数据存进磁盘中,在读取数据的时候再将拿到的字节数组解码,这样就组成了我们的数据编解码过程。

// Entry代表数据。
type Entry struct {
   
   
	key   []byte
	value []byte
	meta  *Meta
}

// Meta是元数据
type Meta struct {
   
   
	crc       uint32
	position  uint64
	timeStamp uint64
	keySize   uint32
	valueSize uint32
}

//这个方法的功能是将一个Entry对象编码成byte数组
func (e *Entry) Encode() []byte {
   
   
  // size是meta+key+value的长度。
	size := e.Size()
	buf := make([]byte, size)
  //以小端字节序将数字写入到字节数组中
	binary.LittleEndian.PutUint64(buf[4:12], e.meta.position)
	binary.Lit
用 Rust 从 01 实现一个最简化的 KV 存储引擎 本文将从 下层的数据编码 到 上层的 kv 数据读写接口实现 完整介绍如何实现一个最简化的 kv 存储引擎,适合 Bitcask 存储模型和 Rust 语言的入门。本文的完整代码已开源在:GitHub - Morgan279/miniDB: A mini kv database demo that using simplified bitcask storage model with rust implementation....... 阅读详情

相关推荐

从零实现一个 k-v 存储引擎

写这篇文章的目的,是为了帮助更多的人理解 rosedb,我会从零开始实现一个简单的包含 PUT、GET、DELETE 操作的 k-v 存储引擎,你可以将其看做是一个简易版本的 rosedb,就叫它 minidb 吧(mini 版本的 rosedb)。 无论你是 Go 语言初学者,还是想进阶 Go 语言,或者是对 k-v 存储感兴趣,都可以尝试自己动手实现一下,我相信一定会对你帮助很大的。 说到存储,其实解决的一个核心问题就是,怎么存放数据,怎么取出数据。在计算机的世界里,这个问题会更加的多样化。 计算机当

roseduan 的个人博客 1154

BitCask 持久化hash存储引擎 原理介绍

十年前的持久化hash存储引擎 bitcask

天行健,地势坤 1910

开发板的使用

一、开发板使用学习大纲。 1、开发板组成、核心板资源,底板资源。 2、开发板连接、调试工具、串口参数配置。 3、开发板启动过程。 4、文件传输 1)使用串口传输。 上传/下载 2)使用网口传输。 上传/下载 5、临时/永久配置开发板IP地址。 6、开发板启动脚本。 二、开发板的组成。 核心板: CPU处理器: 芯片:S5P6818(三星) 内核: ARM cortex-A53 -> 八核处理器 运行内存:512MB*2=1G nandflash:4G 底板: 电源线:5V 串口...

qq_45633736的博客 2640

存储架构|Bitcask 引擎的设计,秒!

坚持思考,就会很酷Bitcask 是什么?Bitcask 是一种很有趣的存储模型的设计,这是一种底层格式为日志模样的 kv 存储。Bitcask 起源于 Riak 分布式数据库,Bitca...

架构师小秘圈 573

Java转Go日记(六十七): Go必学项目:从零实现基于bitcaskkv存储引擎(三):数据库启动流程

本文介绍了Bitcask存储引擎的启动流程,主要包括加载数据文件和构建内存索引两个关键步骤。启动时需处理用户配置项校验,创建必要的数据目录。引擎通过扫描目录下的数据文件(按文件ID排序),识别活跃文件和旧文件。索引构建过程需严格按文件ID顺序处理,遍历文件中的每条记录,根据记录类型更新内存索引。文中还定义了DB结构体来管理引擎实例状态,包括文件锁、索引等核心组件。对于空数据库或损坏目录也有相应处理机制。

fashi的博客 982

Riak KV性能优化:提升分布式存储吞吐量的10个关键策略

Riak KV作为一款高性能的分布式Key/Value存储系统,在大规模数据场景下的吞吐量表现直接影响业务响应速度。本文将分享10个经过实践验证的性能优化策略,帮助你充分释放Riak KV的存储潜力,显著提升系统吞吐量与稳定性。 ## 1. 合理配置后端存储引擎 选择适合业务场景的存储引擎性能优化的基础。Riak KV提供了多种后端实现: - **LevelDB后端**:[src/riak_

gitblog_00711的博客 1138

数据库k/v存储模型浅析——Hash,B树,LSM

1.基于哈希的存储引擎BitCask 常见模型是BitCask 并发下的数据库文件读写: 本来想使用FileLock,但是后来发现 FileLock是进程间的,并不能用于同一个JVM多个线程之间的同步: File locks are held on behalf of the entire Java virtual machine.* They are not s...

weixin_30414635的博客 321

CouloyDB 开源项目快速入门指南

CouloyDB 开源项目快速入门指南 项目概述 CouloyDB 是一个旨在平衡性能与存储成本的存储引擎,提供了一个不同于Redis等内存KV存储的选择,特别适用于某些场景。它基于bitcask模型实现,而Kuloy则是基于CouloyDB构建的兼容Redis协议的KV存储服务,支持一致性哈希集群和动态扩展。 目录结构及介绍 以下是CouloyDB的基本目录结构及其简介: CouloyDB/...

gitblog_00022的博客 433

FlyDB集群部署指南:轻松搭建分布式存储系统

FlyDB是一款基于Bitcask论文实现的高性能键值存储引擎,采用Golang开发。本指南将带你快速掌握FlyDB集群的部署方法,通过简单几步即可搭建一个稳定高效的分布式存储系统,满足企业级应用对数据存储的高可用、高扩展需求。 ## 一、准备工作:环境与依赖 在开始部署FlyDB集群前,请确保你的环境满足以下要求: - **操作系统**:Linux(推荐Ubuntu 20.04+或Cent

gitblog_00468的博客 897

Go 存储系列:Hash存储引擎 Bitcask

Bitcask 是一种底层格式为日志模样的 kv 存储,就是只追加,保证文件是一直顺序写入的,写入性能非常好大部分接触的KV存储引擎是可能都是Redis。Redis的所有数据都是装在内存的,也可以根据配置持久化在磁盘里面,但是读都是从内存里面读的,这意味着redis的读写速度都非常快。但是这有一个限制,那就是单机Redis存储的数据不能大于内存本身。而Bitcask的最大限制是内存必须装得下所有的key,因为Bitcask的value是存在磁盘上的。

CoLiuRs 1603

从零实现kv存储V1.0:array初版

本节开始,逐步实现基于内存的kv存储引擎

Ricardo2的博客 740

rosedb01--Bitcask 简单实现

Bitcask 是一种简单而高效的键值存储机制,主要通过顺序写入和合并操作来优化性能。存储索引:如何高效存储索引信息,减少内存和磁盘空间的使用。高效构建内存哈希表:如何利用提示文件(hint file)等方式加速内存哈希表的构建。

m0_72618948的博客 1228

bitcask论文翻译/笔记

Bitcask的起源与Riak分布式数据库的历史紧密相连。在Riak的K/V集群中,每个节点都使用了可插拔的本地存储;几乎任何结构的K/V存储都可以用作每个主机的存储引擎。这种可插拔性使得Riak的处理能够并行化,从而可以在不影响代码库其他部分的情况下改进和测试存储引擎。有很多类似的本地K/V存储系统,包括但不限于Berkeley DB、Tokyo Cabinet和Innostore。读取或写入每个项目的低延迟高吞吐量,尤其是在写入随机项目的传入流时处理比RAM大得多的数据集的能力,无退化。

weixin_42367537的博客 2008

BitCask:基于日志结构哈希表的高性能 KV 引擎

BitCask 是分布式数据库 RIAK KV存储引擎,同时也是世界上最高效的 KV 存储引擎之一,其基于日志结构哈希表(Log-Structured Hash Table)实现

凌桓丶的博客 1364

推荐开源项目:Bitcask - 快速键值数据的Log-Structured Hash Table

推荐开源项目:Bitcask - 快速键值数据的Log-Structured Hash Table 1、项目介绍 Bitcask一个基于Erlang语言实现的高效Key/Value存储系统,它设计用于快速读取和写入大量键值对的数据场景。这个开源项目采用了Log-Structured Hash Table的数据结构,旨在提供简洁、高性能的解决方案,尤其适用于分布式系统和NoSQL数据库。 2、项...

gitblog_00088的博客 451

Riak存储引擎bitcask与leveldb测试

测试工具使用basho_benchgithub地址:https://github.com/basho/basho_bench测试集群共四台X86PCCPU:Intel(R) Core(TM)2 Duo CPU E7500Mem:4GSATA:500Gsystem:Ubuntu Server X64Riak Version:1.0Bitcask B...

weixin_34146805的博客 307

《大规模分布式存储系统》——基础篇

分布式存储系统按照所存储的数据对象不同,分为四类:分布式文件系统(存储图片、音频、视频等非结构化的Blob对象、定长块以及大文件等)、分布式表格系统(存储关系较为复杂的半结构化数据)、分布式键值系统(存储关系简单的半结构化数据)和分布式数据库(存储结构化数据)等。

艰难困苦如同欢乐,终将成为人生最后的财富 2602

从零实现KV存储项目实战

从零实现KV存储项目实战

m0_60259116的博客 985

智能多代理视频生成框架:构建自动化视频创作平台的完整指南

在当今数字内容创作爆炸式增长的时代,视频生成技术正经历着从传统手动制作向AI自动化转型的革命性变革。ViMax作为一款先进的智能代理视频生成框架,通过创新的多智能体架构实现了从创意到视频的完整自动化流程,为开发者提供了构建高质量AI视频生成应用的完整解决方案。这一开源项目将导演、编剧、制片人和视频生成器等多个角色整合为一体,重新定义了视频创作的边界。 ## 技术架构解析:多智能体协同工作机制

gitblog_00063的博客 412

CAN轴控制流【6041,6040

【代码】CAN轴控制流【6041,6040

cfqq1989的博客 1737

CIE 1931 LV2010.zip_CIE 1931 LV2010_CIE 做图_labview CIE 1931_labv

CIE1931色度图,利用labview绘制彩色CIE1931色度坐标图

上一篇: 记录在一次bufio.Reader的错误使用中引起的思考
下一篇: 同样是1亿数据,为什么nutsdb扛不住,而badgerdb可以?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值