kudu设计-tablet

1. 逻辑组成

在这里插入图片描述

tablet

tablet是kudu表的一个水平分区,类似于Hbase的region概念。每个tablet包含一个连续主键范围的记录,不同tablet的键范围不会有重叠,一个表的所有tablet就组成了这个表完整的键空间,充分利用kudu的分区功能,可以有效避免数据热点问题。

RowSet

每个tablet由若干个RowSet构成,一个RowSet由一组行数据组成,对于给定一个key的那一行记录,只会出现在一个RowSet里面(MenRowSet或DiskRowSet)。但是RowSet的键空间不是连续的,所以不同RowSet的键空间范围会有重叠,但键不会有重复。

mutation

对数据的插入、修改、删除统一叫做mutation

MemRowSet

MemRowSet是一个按主键排序的内存B-tree(一行数据对应这个B-tree的一个entry,即一个MRSRow实例),数据插入时都会先进入MemRowSet,然后数据就对查询可见了,而为了维持快照的一致性(可以理解为并发读写某行数据时候,可以读到自己正确的快照数据),那么就要求对每行数据的所有修改(叫做mutation)都需要保存下来,形成一个mutation链表,作为该行的redo log。当内存满后,MemRowSet会刷到磁盘中形成DiskRowSet,然后再创建新的MemRowSet。

DiskRowSet

MemRowSet刷到存盘形成DiskRowSet,而DiskRowSet真正存储为一系列的cfile;每个DiskRowSet中的每行记录都会对应一个"rowid" (DiskRowSet有点像数组,"rowid"对应一个数组下标且对使用者不可见),"rowid"与主键之间会有一个映射关系:

  1. 当主键为单列主键时,“rowid"其实就内置在存储主键列的cfile中,主键是排序存储的,所以每个主键默认对应着一个"rowid”,通过主键获得"rowid",然后再从其它cfile快速定位其它列,这个就是所谓的主键索引
    在这里插入图片描述
  2. 当主键为复合主键时,会有一个单独的索引文件(index cfile)保存着编码后的复合主键,这样就可以像单主键提供一样的功能。
    在这里插入图片描述

一行数据以列式格式储存到不同的cfile,读取一行完整记录时,虽然要扫描多个cfile,但是具有有相同的rowid,所以还是可以快速地获取到各个列的数据。

在逻辑上,每个DiskRowSet由三个部分组成,分别是:

在这里插入图片描述

Base data

MemRowSet刷到磁盘后形成的列式数据

UNDO records

可以对base data进行回滚到MemRowSet刷盘之前的历史记录

REDO records

数据刷新到磁盘后,对Base data所做的mutation集合 ,被应用于读取更新版本的数据

落盘后Base data和REDO delta进行的Major compation会生成新的Base data和新的UNDO records

DeltaMemStore

是一个内存并发BTree,节点的键由rowid与mutation时间戳组合而成,当在读取时,与MemRowSet中的mutation处理逻辑一样。当DeltaMemStore大小到一定程度会被刷到磁盘形成DeltaFile,然后重置自己为空。

DeltaFile

UNDO records 和 REDO records 存储为相同的文件格式,叫作DeltaFile,包含着一系列的mutation数据。

2. 读写过程

2.1 数据在MemRowSet中的读写

数据首次插入是会落到MemRowSet,随后的更新、删除、删除后重新插入这些操作会有一个链表按时间顺序把这些mutations保存起来,逻辑如下图:
在这里插入图片描述

每个mutation都会标记一个时间戳,用来用为MVCC的主要依据,当在tx时提交一个查询,

  1. 如果tx<tx1,表示tx1还没提交,会跳过该行数据
  2. 否则会把tx1时的行数据copy到scanner的缓冲区,然后遍历mutation链表,找到所有时间戳小于tx(表示发生在查询之前)的mutation与buffer中的行数据进行合并。

如果对单行更新得太频繁,那么每次在链表尾部插入mutation都是一个O(n)操作;另外读取数据的时候要遍历连接,这也会造成许多cpu缓存的丢失。

2.2 数据在DiskRowSet中的读写
2.2.1 更新过程:

数据刷新到磁盘后的修改删除操作不会再进MemRowSet,而是执行如下步骤:

  1. 根据主键结合元数据和布隆过滤器快速定位到行记录所在的DiskRowSet
  2. 寻找主键索引(index cfile)来确定行的rowid
  3. 然后mutation会进入DeltaMemStore,到时DeltaMemStore会刷到磁盘形成DeltaFile,所以DeltaMemStore和DeltaFile包含的内容相同,但是后者经过序列化压缩得更紧凑,这些DeltaFile被称作为REDO files,而里面的mutations被称作REDO records

HBase中采用了非原地更新的方式,将更新操作和删除操作转换成插入一条新数据的形式,虽然这样能够较快的实现更新与删除,但是将导致满足指定rowkey,列族、列名要求的数据有多个,并且可能分布在不同的storefile中。

2.2.2 读过程:
  1. 当想要在MemRowSet刷新之后立即读取最新版本的数据时,只需要扫描Base data即可
  2. 如果想对历史记录进行回溯查询,那么还是先读取base data,然后根据当前扫描器的时间戳会找到一系列的UNDO records与base data合并恢复历史的状态。
    在这里插入图片描述
  3. 在数据落盘一段时间后,数据可能变更过,所以会产生DeltaFiles,这个时候的扫描除了读取base data之外,还需要将REDO records进行合并得到新版本的数据
    在这里插入图片描述
3. RowSet内的Delta compaction

DeltaMemStore每次flush都会生成新的delta file,每次扫描都需要将delta文件与base data进行合并,读取性能会越来越差,所以kudu会有后台任务,负责将RowSet低效的物理储存布局转换为更高效的布局,这个过程叫做“delta compactions”,主要分为两种类型

3.1 Minor REDO delta compaction

不涉及base data,主要是为了减少delta文件数量
在这里插入图片描述

3.2 Major REDO delta compaction

除了可以减少delta文件数量之外,还能把REDO records转为UNDO records,因为major需要读取并重写base data,而base data一般比delta data大得多,所以major任务比minor任务消耗更大的性能。
在这里插入图片描述

因为两种compaction都是发生在RowSet内,而RowSet内维护着rowid,所以可以完全独立在后台运行,而不需要对compaction目标数据进行锁定,compaction后将结果与输入数据进行原子交换,再把compaction前的文件删除

4. RowSet之间的Merging compactions

随着tablet的数据增加,DiskRowSet也会逐渐累积起来,对下面几种情况会有性能影响:

  1. 随机访问(或根据主键更新),由于RowSet的键范围可能会有重叠,所以需要查询所有的RowSet键范围来确定指定的键可能存在哪些RowSet,通过bloom filter可以有效的过滤一些RowSet而减少物理扫描,但是额外对bloom filter的访问也会增加内存和cpu的消耗
  2. 范围扫描,这种情况下,有重叠键范围的RowSet都需要进行扫描,bloom filter不能像随机访问那样有效进行过滤。
  3. 排序扫描,从各个RowSet扫描到目标数据后,需要将各个RowSet的扫描结果进行汇总合并排序,RowSet越多,这个过程就会越耗性能。
    在这里插入图片描述
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值