CC00009.kudu——|Hadoop&OLAP_Kudu.V09|——|kudu.v09|表设计.V2|

七、Handling mutations against on-disk files
### --- Handling mutations against on-disk files

~~~     更新或者删除已经flush到disk的数据,不会操作MemRowSet。
~~~     它的处理过程是这样的:为了确定update/delete的key在哪个RowSet里,系统将巡视所有RowSet。
~~~     这个处理首先使用一个区间tree,去定位一组可能含有这key的RowSet。
~~~     然后,使用boom filter判断所有候选RowSet是否含有此key。
~~~     如果某一些RowSet同时通过了如上两个check,系统将在这些RowSet里寻找主键对应的rowid。
~~~     一旦确定了数据所在的RowSet,mutation将拿到主键对应的rowid,
~~~     然后mutation会被写入到一个称为DeltaMemStore的内存结构中。
~~~     一个DiskRowSet里就一个DeltaMemStore,DeltaMemStore是一个并行BTree,
~~~     BTree的key是使用rowid和mutation的timestamp混合成的。
~~~     查询时,符合条件的mutation被执行后得到快照timestamp对应数据,
~~~     执行方式与新数据插入后的mutation类似(MemRowSet)。
~~~     当DeltaMemStore存入的数据很大后,同样也会执行flush到disk,落地为DeltaFile文件:
### --- DeltaFile的信息类型与DeltaMemStore是一致的,只是被压实和序列化在密集型的磁盘里。

~~~     为了把数据从base data更新成最新的数据,查询时需要执行这些DeltaFile里的mutation事务,
~~~     这些DeltaFile集合称作REDO文件,而file里这些mutation称作REDO record。
~~~     与存于MemRowSet里的mutation类似,当读取比base data更新版本的数据时,
~~~     它们需要被一次应用(执行)。
~~~     一条数据的delta信息可能包含在多个DeltaFile文件,
~~~     这种情况下,DeltaFile是有序的,后边的变更会优先于前边的变更。
~~~     注意,mutation存储结构没必要包含整行的数据。
~~~     如果在一行中,仅仅只有一列数据被更新,那么mutation结构只会包含这一列的更新信息。
~~~     不读取或者重写无关的列,这样更新数据操作就快而有效率。
八、Summary of delta file processing
### --- 总结一下,每个DiskRowSet逻辑上分三部分:

~~~     Base data:MemRowSet flush到DiskRowSet时的最新数据,数据是列式存储的。 
~~~     UNDO records:历史数据,用来回滚到Base data之前一些历史版本数据。 
~~~     REDO records:Base data之后的一些更新数据,可以用来得到最新版本的数据。 
~~~     UNDO record 和REDO record存储格式是一样的,都称为DeltaFile。
九、Delta Compactions
### --- Delta Compactions

~~~     当DeltaFile里的mutation堆积越来越多,读取RowSet数据效率就越来越低,
~~~     最坏情况,读取最新版本数据需要遍历所有REDO record并与base data merge。
~~~     换一句话说,如果数据被更新了太多次,为了得到最新版本的数据,
~~~     就需要执行这么多次的mutation。
~~~     为了提高读取性能,Kudu在后台将低效率的物理布局转化成更加高效的布局,
~~~     且转化后具有同样的逻辑内容。这种转化称为:delta compaction。
~~~     # 它的目标如下:

~~~     减少delta files数量。
~~~     RowSet flush的delta files文件越多,为了读取最新版本数据所要读取的独立的delta files就越多。
~~~     这个工作不适于放在内存中(RAM),因为每次读取都会带有delta file的磁盘寻址,
~~~     会遭受性能损失。
~~~     将REDO records迁移成UNDO records。
~~~     如上所述,一个RowSet包含了一个base data,且是按列存储的,往后一段是UNDO records,
~~~     往前一段是REDO records。
~~~     大部分查询都是为了获取最新版本的数据,因此我们需要最小化REDO records数量。
~~~     回收old UNDO records。UNDO recods只需要保存用户设定最早时间点后的数据,
~~~     这个时间之前的UNDOrecord都可以从磁盘中移除。
~~~     注意:BigTable的设计是timestamp绑定在data里,没有保留change信息(insert update delete);
~~~     而kudu的设计是timestamp绑定在change里,而不是data。
~~~     如果历史的UNDO record被删除,
~~~     那么将获取不到某行数据或者某列数据是什么时候插入或者更新的。
~~~     如果用户需要这个功能,他们需要保存插入或者更新的timestamp列,就跟传统关系型数据库一样。
十、Types of Delta Compaction
### --- Types of Delta Compaction

~~~     delta campaction分minor和major两种。
~~~     Minor delta compactoin: Minor compaction是多个delta file的compaction,
~~~     不会包含base data,compact生成的也是delta file。
### --- Major delta compaction: Major compaction是对base data和任意多个delta file的compact。

~~~     Major compaction比minor compaction更耗性能,因为它需要读取和重写base data,
~~~     并且base data比delta data大很多(因为base data存了一行数据,
~~~     而delta data是对某一些column的mutation,需要注意的base data是列式存储的,delta data不是)。
~~~     Major compaction可以对DiskRowSet里的任意多个或者一个column进行compact。
~~~     如果只有一列数据进行了多次重要的更新,那么compact可以只针对这一列进行读取和重写。
~~~     在企业级应用中会经常遇到这种情况,例如更新订单的状态、更新用户的访问量。
~~~     两种类型的compaction都维护RowSet里的rowid。因为它们完全在后台执行,且不会带锁。
~~~     compact的结果文件会采用原子swapping的方式被引入进RowSet。
~~~     Swap操作结束后,compact前的那些老文件将会被删除。
十一、Merging compactions
### --- 随着越来越多的数据写入tablet,DiskRowSet数量也会累积的越来越多。如此这般将会降低kudu性能:

~~~     # 随机访问(通过主键获取或者更新一条数据),
~~~     这种情况下,每个RowSet只要它的key范围包含了这个主键,
~~~     将各自去定位主键的位置。Boom filter可以缓解一定数量的物理寻址,
~~~     但是特大的bloom filter访问会影响到CPU,并且同样会增加内存消耗。
~~~     # 查询一定key范围数据(例如查询主键在A与B之间的数据),
~~~     此时,每个RowSet,只要它的key范围与提供的范围重叠,将各自去寻址,不使用bloom filter。
~~~     专门的索引结构可能会有帮助,但是同样会消耗内存。

~~~     # 排序查询,
~~~     如果用户要求查询的结果与主键有相同顺序,那么查询结果集必须经过一个merge过程。
~~~     Merge的消耗通常与输入的数据量成对数级增长,即随着数据量的增大,merge将越耗性能。
### --- 如上所述,我们应该merge RowSet以减少RowSet的数量:

~~~     与如上提到的Delta Compaction不同,请注意,merging Compaction不会保持rowid一样。
~~~     这使得处理并发的mutation错综复杂。这个过程在compaction.txt文件中有比较详细的描述。
十二、Overall picture
十三、Comparison to BigTable approach
### --- 与BigTable不同的设计方式点如下:

~~~     # kudu中
~~~     一个给定的key只会存在于一个tablet的RowSet里。 
~~~     在BigTable里,一个key可以存在多个不同的SSTable里。
~~~     BigTable的一整个Tablet类似于kudu的RowSet:
~~~     读取一条数据需要merge所有SSTable里找到的数据(根据key),类似于Kudu,
~~~     读取一条数据需要merge base data和所有DeltaFile数据。 
~~~     Kudu的优势是,读取一条数据或者执行非排序查询,不需要merge。
~~~     例如,聚合一定范围内的key可以独立的查询每个RowSet(甚至可以并行的),
~~~     然后执行求和,因为key的顺序是不重要的,显然查询的效率更高。 
~~~     Kudu的劣势是,不像BigTable,insert和mutation是不同的操作:
~~~     insert写入数据至MemRowSet,而mutation(delete、update)
~~~     写入存在这条数据的RowSet的DeltaMemStore里。# 性能影响有一下几点: 
~~~     # a)写入时必须确定这是一条新数据。这会产生一个bloom filter查询所有RowSet。
~~~     如果布隆过滤器得到一个可能的match(即计算出可能在一个RowSet里),
~~~     接着为了确定是否是insert还是update,一个寻址就必须被执行。 
~~~     假设,只要RowSet足够小,bloom filter的结果就会足够精确,
~~~     那么大部分插入将不需要物理磁盘寻址。另外,如果插入的key是有序的,
~~~     例如timeseries+“_”+xxx,由于频繁使用,key所在的block可能会被保存在数据块缓存中。 
~~~     # b)Update时,需要确定key在哪个RowSet。与上雷同,需要执行bloom filter。
~~~     这有点类似于关系型数据库RDBMS,当插入一条主键存在的数据时会报错,且不会更新这条数据。
~~~     类似的,更新一条数据时,如果这条数据不存在也会报错。BigTable的语法却不是这样。
~~~     # Mutation操作磁盘数据,是通过rowid的,而不是实际意义上的key。

~~~     BigTable中,同一个主键数据是可以存在多个SSTable里的,
~~~     为了让mutation和磁盘的存的key组合在一起,BigTable需要基于rowkey执行merge。
~~~     Rowkey可以是任意长度的字符串,因此对比rowkey是非常耗性能的。
~~~     另外,在一个查询中,即使key列没有被使用(例如聚合计算),它们也要被读取出来,
~~~     这导致了额外的IO。复合主键在BigTable应用中很常见,
~~~     主键的大小可能比你关注的列大一个数量级,特别是查询的列被压缩的情况下。 
~~~     相比之下,kudu的mutation是与rowid绑定的。
~~~     所以merge会更加高效,通过维护计数器的方式:
~~~     给定下一个需要保存的mutation,我们可以简单的相减,
~~~     就可以得到从base data到当前版本有多少个mutation。
~~~     或者,直接寻址可以用来高效的获取最新版本的数据。 
~~~     另外,如果在查询中没有指定key,那执行计划就不会查阅key,除了需要确定key边界情况。
### --- 举例:

~~~     # 如上表的主键是(host,unitx_time),
~~~     # 在kudu里的执行伪代码如下:
sum = 0 foreach RowSet: start_rowid =rowset.lookup_key(1349658729) 
end_rowid = rowset.lookup_key(1352250720) iter 
=rowset.new_iterator(“cpu_usage”) iter.seek(start_rowid) remaining 
= end_rowid - start_rowid whileremaining > 0: block 
= iter.fetch_upto(remaining) sum += sum(block)。
~~~     # 获取block也非常的高效,因为mutation直接指向了block的索引地址。
~~~     timgstamp不是数据模型里的一部分。 
~~~     BigTable-like的系统中,每个cell的timstamp都是暴露给用户的,
~~~     本质上组成了这个cell的一个符合主键。
~~~     意味着,这种方式可以高效的直接访问指定版本的cell,
~~~     且它存储了一个cell的整个时间序列的所有版本。
~~~     而Kudu却不高效(需要执行多个mutation),
~~~     它的timestamp是从MVCC实现而来的,它不是主键的另外一个描述。
~~~     作为替代,kudu可以使用原生的复合主键来满足时间序列场景,例如主键(host,unix_time)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yanqi_vip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值