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

  • 封装了对日志的读操作,暂时略,对理解整体结构没有大的影响。
 

读写实例

 
  1. File dir = new File("target/tests/Test");
  2. dir.mkdirs();
  3. Journal dataManager = new Journal();
  4. dataManager.setDirectory(dir);
  5. dataManager.start();
  6. //写入日志
  7. ByteSequence write = new ByteSequence("Hello world".getBytes());
  8. Location location = dataManager.write(write, true);
  9. //读取日志
  10. ByteSequence read = dataManager.read(location);
  11. 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上读写,提交以及回滚操作

 

读写实例

 
  1. File dir = new File("target/tests/Test");
  2. dir.mkdirs();
  3. PageFile pf = new PageFile(dir, "myfile");
  4. pf.load();
  5. //写入
  6. Transaction tx = pf.tx();
  7. Page<String> page = tx.allocate();
  8. page.set("Hello world");
  9. tx.store(page, StringMarshaller.INSTANCE, true);
  10. tx.commit();
  11. pf.unload();
  12. pf.load();
  13. //读取
  14. tx = pf.tx();
  15. tx.load(page.getPageId(), StringMarshaller.INSTANCE);
  16. String hello = page.get();
 

存储结构

  • 存储的时候包括{dbname}.data和{dbname}.redo {dbname}.free文件。data文件是保存真正消息的文件。当data文件META信息中的cleanShutdown为false的时候会通过redo文件来做recovery。
 

.data文件

 

头部

  • 4K的第一页存放META信息
  • META初始信息如下
 
  1. fileType=org.apache.activemq.store.kahadb.disk.page.PageFile
  2. pageSize=4096
  3. freePages=-1
  4. cleanShutdown=true
  5. metaDataTxId=0
  6. fileTypeVersion=1
  7. 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设计的更多相关文章

  1. kafka系列教程2(设计构造及原理1)

    kafka采用了一些非主流(unconventional)并经过实践的设计使其高效和可扩展.在实际使用中kafka显示出了相对于常见流行的消息系统的优越性.并且每天能够处理上百GB的新的数据.   类 ...

  2. KahaDB简介

    ActiveMQ 5.3以后,出现了KahaDB.她是一个基于文件支持事务的消息存储器,是一个可靠,高性能,可扩展的消息存储器.     她的设计初衷就是使用简单并尽可能的快.KahaDB的索引使用一 ...

  3. 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑

    阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...

  4. 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成

    阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...

  5. 设计爬虫Hawk背后的故事

    本文写于圣诞节北京下午慵懒的午后.本文偏技术向,不过应该大部分人能看懂. 五年之痒 2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk.我花不少时间优化和推广它,得到的评价还算比较 ...

  6. 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车

     阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...

  7. 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念

    一.前言     DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...

  8. 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文

    阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...

  9. 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文

    阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...

随机推荐

  1. python开头——文件声明 详解

    一.解释器声明 1.声明方式 linux #!/usr/bin/python windowns #!c:/python27/python.exe 放在首行 2.作用 告诉电脑,要用/usr/bin下面 ...

  2. 论文笔记 | Self-organized Text Detection with Minimal Post-processing via Border Learning

    论文链接:http://openaccess.thecvf.com/content_ICCV_2017/papers/Wu_Self-Organized_Text_Detection_ICCV_201 ...

  3. html自定义垂直导航菜单(加强版--自定义传入menu参数,支持JSONArray、JSArray、JSONObject、JSObject)

    在上一篇中我简单写了个html自定义垂直导航菜单,缺点很明显,里面的数据是固定死的,不能动态更改数据. 这里我重写了一个修改版的垂直二级导航菜单,将原先的menuBox.init(config);修改 ...

  4. (转)图解SSH原理

    图解SSH原理 原文:https://www.jianshu.com/p/33461b619d53 http://blog.51cto.com/forlinux/1352900---------SSH ...

  5. cloudermanager安装时database connection出现Unexpected error. Unable to verify database connection(图文详解)

    不多说,直接上干货! http://www.aboutyun.com/forum.php?mod=viewthread&tid=20455&extra=&page=2 欢迎大家 ...

  6. 在ZYNQ-7000平台上利用PS点亮PL上的LED灯

    在ZYNQ-7000平台上利用PS点亮PL上的LED灯 1.实验方案 图1    实验方案系统框图 2.具体步骤 2.1.vivado工程建立 ①打开vivado集成开发环境,点击“Create Pr ...

  7. WPF 父子窗体联动

    问题: 近段时间,由于项目上的一些原因,设计到在WPF项目使用引用COM组件的问题,部分WPF元素浮动在COM组件之上,并且实现拖.停靠.放大等功能(子窗体不要求等比缩放,只要位置跟随主窗体即可),如 ...

  8. pycharm激活码------2017.11.之前有效

    BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  9. 检测SQL Server表占用空间大小SQL

    检测SQL Server表占用空间大小SQL,要先选择需要查询的数据库,然后点击执行下面脚本. ),ROWS ),reserved ) ,Data ) ,index_size ) ,Unused ) ...

  10. C#学习笔记9

    1.多播委托:由与delegate关键字声明的委托,在编译后默认继承Delegate与MulticastDelegate类型,所以声明的委托自然就含有多播委托的特性,即一个委托变量可以调用一个方法链( ...