BitCask 持久化hash存储引擎 原理介绍
文章目录
- 前言
- 引擎背景
- 引擎原理
- 1. 磁盘数据结构
- 2. 内存数据结构
- 3. 读流程
- 4. 数据合并
- 总结
前言
最近工作中部分项目中,对存储引擎的需求希望高性能的写、点查,并不需要Range。这里看到大家总会提到BitCask
这个存储引擎方案,并不是很了解,特此做一个总体的学习记录。
引擎背景
BitCask
是分布式数据库Riak
有存储引擎上的一些需求,但是当时(2010年左右)业界并没有一个能够满足需求的引擎,包括但不限于Berkeley DB
, Tokyo Cabinet
, Innostore
等。所以BitCask
便应运而生,主要为了解决以下一些需求:
- 读/写 的低延时
- 随机写场景下的高吞吐
- 支持数据量远大于内存的持久化存储
- 异常恢复机制,能够快速recovery且不丢数据
- 便捷得数据备份机制
- 支持易理解的数据结构
- 大并发/大数据量下的引擎稳定性保障
- 支持平滑迁移到
Riak
除了最后一条定制化需求之外,对于今天我们的存储引擎来说其实都是一些最基本的需求,因为没有强Range性能需求,所以这一些基本要求也是可以理解的,无非就是引擎的稳定性和性能。然而,当时业界并没有这样的一个存储引擎,所以Riak
的开发者们也就只能撸起袖子自己搞了。google的bigtable中提出的LSM-tree对读性能并不友好,所以也不满足。
因为没有Range,他们便从hash数据结构入手来提供O(1)的点查,由借鉴了Log-Structure Merged 数据结构中的log-merging思想,来提供强大的写入性能。
引擎原理
1. 磁盘数据结构
BitCask磁盘数据结构非常简单,一个BitCask实例就是一个文件系统目录。需要保证同一时刻只有一个进程会访问这个目录,进程写入的数据更新仅仅会落在一个Active data file中,当这个文件达到了一个给定的阈值,会创建一个新的active data file,而之前的接受写入的文件会被标记为只读。
进程写入key/value到active data file的过程时追加写方式,也就是类似于一个文件writer,这个过程会转化成磁盘上的顺序写,所以写入性能肯定会很高。
每一个磁盘上的entry数据格式如下:
crc : 当前entry的数据校验
tstamp: 时间戳
ksz: key size
value_sz : value size
key : key的内容
value : value的内容
如果想要删除数据,也是写入一个deletion的 tombstone标记,后续的log-merging会清理。
所以,每一个磁盘上的datafile 中的entry最后都追加成这样的形态:
2. 内存数据结构
之前说了,bitcask保证低延时的情况下也是为了提升读写吞吐的,他们为了让读性能远超LSM-tree的这样的数据结构,采用了hash表作为内存索引数据结构。
内存数据结构叫做keydir
,形态如下:
这个hash表映射的key都是定长的,这个key在hash表中的’value’ 存储了几个字段:
- file_id : 这个key所属的datafile id
- value_sz : value size
- value_pos: value在 data file中的偏移地址
- tstamp: 时间戳
这个内存数据结构仅仅保存最新的key-value数据信息,同一个key的旧数据还会存储在旧的data file中,在后续的log-merging过中会被清理。
3. 读流程
如下图:
总共分为四步:
- 从内存的hash表中找到之前写入的key,取出这个key数据所在的file_id
- 拿着file-id找到对应的data file
- 根据value_pos 找到datafile上的指定entry
- 从entry的末尾向前读取value_sz 的数据,即为key的value数据
现在,从Get的流程中我们很明显的能够看到bitcask 设计上存在的一些问题:
- 内存索引 中hash表中存放的是所有写入的key,也就是一个机器能够存放的总数据量是有限的
- 因为没有持久化索引,所以机器异常恢复的时候需要遍历磁盘上所有的data file,来构建内存hash索引
- 没有读缓存,即读的过程中value都需要从磁盘加载,这里bitcask的开发者说是考虑到成本太高,也就没有做了。。。那个时候的内存应该还挺贵的,记得10年的能买得起的笔记本电脑内存应该还处于2G以下,那个时候笔记本架构普遍在大几千:)
但是这个并不影响bitcask在当时的性能优势,第一个数据量问题其实能够达到超过内存10倍的持久化存储能力就满足 Riak
的需求了这里他们也没有再多说。第二个问题则就是时间上的问题,或者可以多线程recovery来重放,他们也能接受。。。
4. 数据合并
之前说了,为了提升写吞吐,bitcask采用了追加写方式,包括删除操作也是一个追加的过程。因为是追加写,也就有了GC来清理过期数据。
数据合并的过程大体如下,也很简单:
就是根据内存中的lastest hash表中的key数据,遍历所有older data files,只保留最新版本的key数据,将entry写入到一个新的merged data file中。因为这个文件可能会很大,所以会生成一个hint file来索引这个merged data file的内容。当然,hint file中的每一个entry也是对应merged data file中的每一个entry,只是并没有存储value,而是存储了value的偏移地址来加速读取。
这个merged data file和hint file 除了能够清理过期数据,释放空间之外还能够在机器异常恢复之后加速内存中hash 索引的重建(毕竟都是lastest version,也就不需要再重新遍历所有的数据了)
总结
总的来说,bitcask就是一个简单的持久化hash引擎。随着硬件的飞速发展,DRAM的价格越来越便宜,磁盘的性能不断飙升,且价格也在不断降低。到现在,甚至操作系统的I/O栈和网络协议栈都因为硬件的极致性能而成为瓶颈,而bitcask在那个时候构建在文件系统之上的持久化层相比于现在已经远远达不到性能要求了。
现在来看,内存数据结构不会有太大的变化,还是hash表。但底层只能基于新硬件来构建引擎,并且引擎层跳过操作系统I/O栈自己来管理硬件,在此基础上的hash引擎在当代才能够被称为高性能的hash引擎。
当然,还需要有类似rocksdb开发者们的卓越编码能力以及对操作系统细节的深刻理解和应用才能让引擎的性能在当下的硬件上发挥到极致。
相关文章:

C# Socket系列三 socket通信的封包和拆包
通过系列二 我们已经实现了socket的简单通信 接下来我们测试一下,在时间应用的场景下,我们会快速且大量的传输数据的情况! 1 class Program2 {3 static void Main(string[] args)4 {5 TCPListener tcp n…

Java项目:CRM客户管理系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能包括: 用户管理,系统管理,客户管理,客户服务,客户关怀, 销售机会,统计管理等等。 二、项目运行 环境配置&#x…

Android 获取标题栏的高度
2019独角兽企业重金招聘Python工程师标准>>> 通过获取内容区域的 rect 的 top 值就是状态栏和标题栏的高度,也就可以得到标题栏的高度了, [java] view plaincopy int contentTop getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTo…

力扣—— 三维形体投影面积
在 N * N 的网格中,我们放置了一些与 x,y,z 三轴对齐的 1 * 1 * 1 立方体。 每个值 v grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上。 现在,我们查看这些立方体在 xy、yz 和 zx 平面上的投影。 投影就像影子,将…

一图带你入门Linux 存储I/O栈
发现了一个内核大佬 的 Linux 存储I/O栈,很清晰!!! 原地址如下: http://ilinuxkernel.com/?p1559 【侵删】

Java项目:在线美食网站系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能:用户的注册登录,美食浏览,美食文化,收藏百 科,趣味问答,食谱等等功能等等。 二、项目运行 环境配置:…

性能测试中传——lr理论基础(四)
转载于:https://blog.51cto.com/fuwenchao/1346435

滑动定位的三种方法,以及热启动(五)
from init_driver.Init_driver import init_driverdriver init_driver()# 坐标-->坐标,定位滑动 driver.swipe(309, 1353, 537, 511, duration3000)# 元素-->元素,定位滑动 start_ele driver.find_element_by_xpath("//*[contains(text, 通…

TitanDB GC详细实现原理 及其 引入的问题
文章目录1. 为什么要有GC2. GC的触发条件3. GC的核心逻辑1. blob file形态2. GC Prepare3. GC pick file4. GC run4. GC 引入的问题5. Titan的测试代码通过本篇,能够从TitanDB的源代码中看到 key/value 分离之后引入的一些复杂性,这个复杂性很难避免。 …

Java项目:医院住院管理系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能包括: 住院病人管理,住院病房管理,医生管理,药品管理,仪 器管理等等。 二、项目运行 环境配置: Jdk1.8 Tomcat8.…

1m网速是什么意思,1m带宽是什么意思
1M网速下载速度应是多少?我怎么才50多KB?? 建议: 一般来说是90到100算正常。最高能达到120 带究竟该有多快 揭开ADSL真正速度之谜 常常使用ADSL的用户,你知道ADSL的真正速度吗?带着这个疑问我们将问题一步一步展开。…

泛型实体类List绑定到repeater
泛型实体类List<>绑定到repeater 后台代码: private void bindnewslist(){long num 100L;List<Model.news> news _news.GetList(out num);this.newslist.DataSource news;this.newslist.DataBind();} 说明:Model.news是实体类,…

Qt4.8.5移植
这两天搞了Qt移植 因为不小心 耽误了挺多时间 但是也比较好的掌握了 现在记录一下 准备工具: tslib-1.16 qt-everywhere-opensource-src-4.8.5.tar 下载路径: tslib-1.16下载: https://github.com/kergoth/tslib/releases/download/1.16/t…

Rocksdb 通过ingestfile 来支持高效的离线数据导入
文章目录前言使用方式实现原理总结前言 很多时候,我们使用数据库时会有离线向数据库导入数据的需求。比如大量用户在本地的一些离线数据,想要将这一些数据导入到已有的数据库中;或者说NewSQL场景中部分机器离线,重新上线之后的数…

Java项目:企业人事管理系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能介绍:员工管理,用户管理,部门管理,文档管理, 职位管理等等。 二、项目运行 环境配置: Jdk1.8 Tomcat8.5 mysql Eclispe (I…

XCODE 6.1.1 配置GLFW
最近在学习opengl的相关知识。第一件事就是配环境(好烦躁)。了解了一下os x下的OpenGL开源库,主要有几个:GLUT,freeglut,GLFW等。关于其详细的介绍可以参考opengl网站(https://www.opengl.org/wiki/Related_toolkits_and_APIs)。由…

SpringCloud远程调用为啥要采用HTTP,而不是RPC?
通俗的说法就是:比如说现在有两台服务器A和B,一个应用部署在A服务器上,另一个应用部署在B服务器上,如果A应用想要调用B应用提供的方法,由于他们不在一台机器下,也就是说它们不在一个JVM内存空间中,是无法直接调用的,需要通过网络进行调用,那这个调用过程就叫做RPC。建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket ,套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
vs快捷键及常用设置(vs2012版)
vs快捷键: 1、ctrlf F是Find的简写,意为查找。在vs工具中按此快捷键,可以查看相关的关键词。比如查找哪些页面引用了某个类等。再配合查找范围(整个解决方案、当前项目、当前文档等),可以快速的找到问题所在…

python_day10
小甲鱼python学习笔记 爬虫之正则表达式 1.入门(要import re) 正则表达式中查找示例: >>> import re >>> re.search(rFishC,I love FishC.com) <re.Match object; span(7, 12), matchFishC> >>> #单纯的这种…

Graphics2D API:Canvas操作
在中已经介绍了Canvas基本的绘图方法,本篇介绍一些基本的画布操作.注意:1、画布操作针对的是画布,而不是画布上的图形2、画布变换、裁剪影响后续图形的绘制,对之前已经绘制过的内容没有影响。

关于Titandb Ratelimiter 失效问题的一个bugfix
本文简单讨论一下在TitanDB 中使用Ratelimiter的一个bug,也算是一个重要bug了,相关fix已经提了PR到tikv 社区了pull-210。 这个问题导致的现象是ratelimiter 在titandb Flush/GC 生成blobfiled的过程中无法生效,也就是无法限制titandb的主要…

Java项目:前台预定+后台管理酒店管理系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能介绍: 前台用户端:用户注册登录,房间展示,房间分类,房间 按价格区间查询,房间评论,房间预订等等 后台管…

Solr初始化源码分析-Solr初始化与启动
用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究。但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机制弄…

iOS :UIPickerView reloadAllComponets not work
编辑信息页面用了很多选择栏,大部分都用 UIPickerView 来实现。在切换数据显示的时候, UIPickerView 不更新数据,不得其解。Google 无解,原因在于无法描述自己的问题,想想应该还是代码哪里写错了。 写了个测试方法&…

单相计量芯片RN8209D使用经验分享(转)
单相计量芯片RN8209D使用经验分享转载于:https://www.cnblogs.com/LittleTiger/p/10736060.html

git 对之前的commit 进行重新签名 Resign
在向开源社区提交PR的时候如果之前的提交忘记添加sign (个人签名/公司签名),则社区的DCO检查会失败。 关于通过DCO检查能够确保以下几件事情生效: 你所提交的贡献是由你自己完成或者 你参与了其中,并且有权利按照开源…
【原创】linux命令bc使用详解
最近经常要在linux下做一些进制转换,看到了可以使用bc命令,如下: echo "obase10;ibase16;CFFF" | bc 用完以后就对bc进行了进一步的了解, man bc里面有详细的使用说明。 1.是什么,怎么用 bc - An arbitrary precision calculator language 一…

Java项目:学生信息管理系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能包括: 用户的登录注册,学生信息管理,教师信息管理,班级信 息管理,采用mvcx项目架构,覆盖增删改查,包括学…

MVC學習網站
http://www.cnblogs.com/haogj/archive/2011/11/23/2246032.html

数据导出Excel表格
public String exportInfoFr(String path,String name,String startdate,String enddate,SysUser user){List<Map<String, Object>> list this.esEntPermitErrDao.findListObjectBySql("select 字段值1,字段值2,字段值3,字段值4,字段值5 from 表名 where 字段…