kahadb设计
Kahadb设计思想
简介
- hakadb是activemq的持久化数据库,作为消息队列的存储,每个消息有一个消息ID,提供了对消息的快速的查找,更新,以及消息的事物支持,以及意外磬机之后的恢复。丰富的功能决定了他在存储结构上与redis中简单的双端队列不同。
kahadb三大部分
- 主要由索引(B-Tree Index),数据(PageFile),日志(Journal)组成。为了实现消息的快速定位更新,通过b-tree来索引数据,主要对应目录中的;为了数据的写入效率,数据都是顺序存储在文件中,这部分工作被抽象到了PageFile类;Journal负责了操作日志,用于写入和恢复最终都是决定与Journal
kahadb之Journal
核心类
Journal 读写日志的facade
- write方法,向日志系统写入日志。返回Location。
- read方法,根据Location从之日系统中读取日志
Location 日志系统中定位日志Record
- 由日志的DataFileId,offset,size,type组成,用来定位日志
DataFile 日志文件的存储文件
日志都存储在db-{1,2,3,...n}.log文件中,每个这个文件都由DataFile类来封装,其中1,2,3..就是DataFileId,还有一些长度和文件指针的信息
DataFileAppender 多线程下优化了批量写入
- 两个线程,一个队列,把并发写变成批量单线程写入,具体实现略
DataFileAccessorPool和DataFileAccessor
- 封装了对日志的读操作,暂时略,对理解整体结构没有大的影响。
读写实例
File dir = new File("target/tests/Test");
dir.mkdirs();
Journal dataManager = new Journal();
dataManager.setDirectory(dir);
dataManager.start();
//写入日志
ByteSequence write = new ByteSequence("Hello world".getBytes());
Location location = dataManager.write(write, true);
//读取日志
ByteSequence read = dataManager.read(location);
System.out.println(new String(read.data));
存储结构
- 由头部28个字节,和数据组成
头部
- 四个字节Journal.BATCH_CONTROL_RECORD_SIZE, 固定的28
- 一个字节Journal.BATCH_CONTROL_RECORD_TYPE, 2
- 十一个字节,字符串 Journal.BATCH_CONTROL_RECORD_MAGIC, WRITE BATCH 这几个字节
- 四个字节记录批量写入了多少批的BATCH_SIZE ,不固定的int
- 八个字节校验和,后半部分写入日志的校验和
数据
- 四个字节的size,这个size是数据头部的长度+数据的长度
- 一个字节数据类型
- 若干字节的数据
日志文件的RecoveryCheck
- 在第一次加载日志文件的时候会做一次Recovery,主要是恢复一些上次写入的Offset,知道了存储结构以后其实按照这个结构读写就可以找到最后一次写的Offset,但是假如日志写入一半失败到了,导致部分存储结构不整齐了,但后续是好的,理想情况应该跳过这些坏的部分,让后面的可用。Recovery的时候对这种情况会重新在文件里搜索日志的头部的前16字节,不知为何是要搜这头部,搜到以后就把之前搜索过的区域标记为corruptedBlocks
kahadb之PageFile
核心类
PageFile
PageFile负责了消息的持久化存储。PageFile对外的主要接口有删除数据库,载入数据库,生成一个用于读写的Transaction,数据被存储在了
Page
PageFile如果是用于存储数据的文件,Page就是文件中的每一小段,为了减少IO,每个文件被分成4K大小的段,是一个Page。至于为什么4K大小可以减少磁盘IO的原因是,当用户程序请求要读1K的数据时候,操作系统会预读更多的数据,放到内核缓冲中,因为内核中的缓冲一页的大小是4K,所以应用程序一般都会和操作系统的PageCache对齐,这样充分利用操作系统的PageCache。Page最重要的一个属性是PageId,这个Id是在一个PageFile中顺序排列的,所以根据这个PageId就可以定位到PageFile文件中的Offset。
Transaction
Transaction负责了创建Page,在Page上读写,提交以及回滚操作
读写实例
File dir = new File("target/tests/Test");
dir.mkdirs();
PageFile pf = new PageFile(dir, "myfile");
pf.load();
//写入
Transaction tx = pf.tx();
Page<String> page = tx.allocate();
page.set("Hello world");
tx.store(page, StringMarshaller.INSTANCE, true);
tx.commit();
pf.unload();
pf.load();
//读取
tx = pf.tx();
tx.load(page.getPageId(), StringMarshaller.INSTANCE);
String hello = page.get();
存储结构
- 存储的时候包括{dbname}.data和{dbname}.redo {dbname}.free文件。data文件是保存真正消息的文件。当data文件META信息中的cleanShutdown为false的时候会通过redo文件来做recovery。
.data文件
头部
- 4K的第一页存放META信息
- META初始信息如下
fileType=org.apache.activemq.store.kahadb.disk.page.PageFile
pageSize=4096
freePages=-1
cleanShutdown=true
metaDataTxId=0
fileTypeVersion=1
lastTxId=0
- 需要说明一点的是这个信息在第一页中存储了两遍
BODY部分
- 一个字节的type 固定的是2
- 八个字节的transactionId
- 八个字节的下一个记录的位置
- 四个字节的校验和,不过是个保留字节,没什么用
- N个字节真正的数据
.redo文件
头部
- 八个字节的下一个TX的id 存储在第一页
- 八个字节的校验和 存储在第一页
- 四个字节的当前这个写入的记录数量 存储在第一页
BODY部分
- 8个字节PageId
- page数据与data文件中的body部分相同
- pageId和page数据是一页的大小4K
PageFile的多级缓存
- 可以看到当写入数据的时候分配新的Page,Page写入磁盘是比较消耗IO的,所以在一个Transaction上有一个freeList来保存空的Page,在PageFile也有freeList来加速新分配Page。同时为了加快读写Page的速度,PageFile中有一个PageCache
事物的回滚
- 事物只有在commit的时候才会调用PageFile的write方法,Transaction中的store只是把他逻辑保存在Transaction中,但是回滚的时候要把PageFile中申请的Page归还到freeList
kahadb设计的更多相关文章
- kafka系列教程2(设计构造及原理1)
kafka采用了一些非主流(unconventional)并经过实践的设计使其高效和可扩展.在实际使用中kafka显示出了相对于常见流行的消息系统的优越性.并且每天能够处理上百GB的新的数据. 类 ...
- KahaDB简介
ActiveMQ 5.3以后,出现了KahaDB.她是一个基于文件支持事务的消息存储器,是一个可靠,高性能,可扩展的消息存储器. 她的设计初衷就是使用简单并尽可能的快.KahaDB的索引使用一 ...
- 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑
阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- 设计爬虫Hawk背后的故事
本文写于圣诞节北京下午慵懒的午后.本文偏技术向,不过应该大部分人能看懂. 五年之痒 2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk.我花不少时间优化和推广它,得到的评价还算比较 ...
- 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车
阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...
- 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念
一.前言 DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...
- 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...
- 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文
阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...
随机推荐
- 转 Nmon 监控生成数据文件字段的介绍
##发现nomon 一个好用的功能 数据透视图 PIVOTCHART:这些参数被用来构建数据透视图.所需的参数:Sheetname,PageField,rowfield,columnfield,Dat ...
- request-statistics.lua
--[[ 实现请求统计,并且将单位时间内异常次数达到阀值的请求加入到黑名单中 --]] --获取共享内存 local limit_req_store = ngx.shared.limit_req_st ...
- spring cloud 之 Feign的使用
1.添加依赖 2.创建FeignClient 原理:Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中.生成代理时Fei ...
- python作业1.1,编写登录模块
实现功能: 1.用户输入账户密码 2.验证账户是否存在于黑名单,如果存在于黑名单,则执行1,否则往下执行 3.验证用户名和密码. 3.1.如果验证成功,则打印欢迎信息并退出程序: 3.2.如果用户名存 ...
- 线程同步(windows平台):互斥对象
一:介绍 互斥对象是系统内核维护的一种数据结构,保证了对象对单个线程的访问权. 二:函数说明 创建互斥对象: HANDLE CreateMutex( LPSECURITY_ ...
- lua输入函数名字符串执行函数
str = "testA()"loadstring(str)() function testA() ------end 使用loadstring即可执行后面在xlua用了下发现不能 ...
- [Activator-HelloAkka] Create our Actors
So far we have defined our Actor and its messages. Now let's create an instance of this actor. In Ak ...
- pycharm激活码------2017.11.之前有效
BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...
- Nginx反向代理、负载均衡功能
环境: [root@db02 ~]# uname -a Linux db02 -.el6.x86_64 # SMP Tue Mar :: UTC x86_64 x86_64 x86_64 GNU/Li ...
- 2017年10月22日 基础SQL语句&数据库创建主外键关系
1.SQL语句的注释 双减号:-- 或者/**/2.创建数据库create database 数据库名称(不允许以数字开头,不允许以符号开头,不要起汉语名字) 3.如何选中这个数据库use 数据库名 ...