|NO.Z.00009|——————————|BigDataEnd|——|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)。
Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
——W.S.Landor
分类:
bdv022-kudu
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」