您的位置:首页 > 理论基础 > 计算机网络

HBASE中的compaction策略,日期分层

2016-12-07 19:48 127 查看
DTCP(日期分层Compaction)

问题描述

ExploringCompactionPolicy是hbase minor compaction的默认策略。图一表现了这个算法默认设置下的表现情况



Figure 1: Illustration of store files with threshold = 3 and compaction ratio = 1.2 (default and our setting
too) from http://www.ngdata.com/visualizing-hbase-flushes-and-compactions/

该策略产生的文件结构与之后讨论的固定窗口大小的分层compaction很相似,区别在于对主干大小和分层没有精确控制, 文件的最大上限取决于major compaction发生的间隔, major compaction 会把多个文件compact成一个。

设想在某种访问模型下, 写入全部是顺序的,读数据主要是基于时间区间对特定列族的scan。绝大多数scan都是基于回看窗口的。默认的文件结构没法支持scan api来跳过超出时间区间的存储文件。

如果采用时间分层的compaction, 我们能够得到如下好处:

1.相比major compaction对跨时间的scan有更好的粒度

2.减少Compaction的IO开销

3.有效的数据保留管理

Compaction策略

https://labs.spotify.com/2014/12/18/date-tiered-compaction/
介绍了
cassadnra的设计。我们通过计算Unix epoch到现在的时间来获取质数分布的时间窗口。这些窗口并随着时间滑动。相反,随着时间流逝, 新的时间窗口生成,旧的时间窗口被合并成了更大的窗口,正如图2所示:



Figure 2.base window = 1 hour, windows per
tier = 4

当前时间节点永远都在最新的时间窗口里。当某层中包含的时间窗口超过4时,该层被合并成一个新的窗口。这可能会导致多米诺效应,比如最后一行中新加的1小时窗口导致一个16小时的窗口生成。

窗口的大小被定义成纯指数的来简化实现和调优。由于没有使用天,月份和年份等单位,没有必要在考虑日历边界问题和滑动边界。不过, 当我们调整配置时,要考虑到数据读取模式通常是读取一小时,一天,一周或者一个月的数据。

为了实现时间分层compaction, 需要配置一下变量:

基础窗口大小,每层最多窗口数量,StoreFile多长时间之后停止compacting,最新窗口内多少文件compact一次

更多层的好处:

更好的粒度, 对于普通的scan来说数据范围更小,要查询的文件更小。

更多层次的坏处:

#Get和Scan的磁盘寻址和存储文件合并开销加大

#层次越多, 每个KV就要被compact越多次

问题1:能否保证每层至少有一个文件来优化scan性能

该算法能够保证每层至少有一个窗口。但是如果在这段时间内没有写发生,将没有文件生成。用户需要根据写模式来选择最佳的窗口大小

问题2 如何处理超出窗口边界的数据

有时可能会产生晚到的数据, 比如复制延时,用户自定义时间戳和bulkload。存储文件之间也可能存在重叠的最大最小时间戳,导致改变了顺序影响层的定义。

在用户永远不写入未来时间戳的标准情况下,我们使用最大时间戳来决定文件的顺序和compaction窗口。文件也不需要紧紧遵时间分布在决定其属于哪一层。他们的层次取决于最大时间戳。通常情况下,每一层中较大的文件会导致scan性能下降, 但这一情况会随着时间好转。如果用户不写入未来的时间戳,最差情况下就是一个高层次的文件出现在较低的层次。这种长尾效应会导致scan时扫描更新和更小文件这种额外的开销。

注意,分层compaction不推荐于使用在会写入未来timestamp的情境下,会退化为exploring compaction

问题3 如何保证数据的一致性

正如Enis Soztutar解释的,如果两个put有相同的timestamp,seqId大的被认为是latest。这意味着用户可以在某些情况下复写之前设置的值。非连续的Compaction会导致我们并不永久性的保存每个cell的seqId,一段时间之后,我们会清除cell的seqId,每个hFile只保留一个seqId。因此如果我们允许两个不同的puts拥有不同的seqId, 但是同样的timestamp,允许不连续的compactions会破坏排序规则。

对于分层compaction,需要从最旧的seqId扫描到最新的seqid. 如果当前文件最大时间戳比目前最大时间戳小,那么当前文件的最大时间戳等于目前最大时间戳, 否则当前最大时间戳等于该文件的时间戳。 如此以来, 基于时间戳的排序将与基于seqId的排序一致。

举个例子,加入有如下文件(seqId, maxTs)

(1,0), (2, 13),
(3,3), (4,10), (5,11), (6,1), (7,2), (8,12), (9,14), (10,15)

根据上述方法处理之后,maxTs被更新

(1,0),
(2, 13), (3,13), (4,13), (5,13), (6,13), (7,13), (8,13), (9,14), (10,15)

如此以来,我们就可以保证乱序(seqId和maxTs不一致)的所有文件被放在同一个层中进行compaction,连续compaction这个规则得以保证。

代价: Scan performance会受影响,尤其是当有某些文件seqId很小但是maxTs很大的时候。两种典型的冲突情况: 1.seqId和ts是逆序

2.BulkLoad 文件seqid是-1,会导致Compaction退化到

exploring compaction.


问题4 如何优雅的处理bulk-load文件

默认情况下,如果

"hbase.mapreduce.bulkload.assign.sequenceNumbers"被关闭,
bulk load 文件会分配一个-1作为seqId, 这将会导致一个类似MajorCompaction的的Compaction发生(所有maxTimestamp小于bulkLoad文件maxTimestamp的文件都会被compact),我们并不推荐这种配置。T

Time-series data that are loaded periodically with minimal time range overlap will perform perfectly
in this case with base window set to


最符合使用场景的情况下,导入的时间序列数据如果有较小的时间段重叠并且都在同一个时间窗口内。某些用户可能偶尔bulkload超出文件时间戳层的数据, 这会导致额外的scan开销。随着时间流逝, 这些数据流向更大的窗口,开销将会逐渐抵消。 如果此类bulkload文件太大,最好进行一次major compaction。

触发机制

当前compaction是由文件数量和文件大小比例来触发的,参考 CompactionPolicy.needCompaction(). CompactionChecker 也会隔一段时间触发一次检查观察是否需要compaction

我们需要有下至上计算每层的窗口。在当前窗口, compaction只会在file count超出的时候触发,来避免多次compact同样的数据。对于其它层,我们使用文件数很少的exploring
compaction算法

问题和解决

当前的scan API需要打开所有的文件来检查min-max 范围, 我们应该通过只选择相关文件来优化么?

不需要的,因为这些信息实际上都已经在Hstore打开的时候load进内存了

如何避免region compact大层的时候导致的性能影响?

使用 PressureAwareCompactionThroughputController.http://www.cloudera.com/content/www/en-us/documentation/enterprise/latest/topics/admin_hbase_compaction_throughput_configure.html

Notes:a:compaction时间增长会导致region被lock无法分裂

b:compaction压力计算(storefileCount
- minFilesToCompact) / (blockingFileCount - minFilesToCompact).blockingFIleCount的设计非常重要

TTL

TTL可以利用分层compaction的优势来直接删除某些最大时间已经过期的数据,这部分逻辑已经实现了

旧文件处理机制

旧的文件并不会使用分层策略来进行split。他们将会逐渐的被访问的越来越少并最终过期。ExploringCompaction
策略会防止大的文件被一直compaction



日期分层Compaction的多输出

当我们compact的时候,我们可以对不同的窗口输出多个文件,这种情况有两周使用情况:

1.Major Compaction的时候, 需要输出多个文件到不同的窗口去

2.升级到DTCP之前,BulkLoad文件和旧文件需要被majorcompaction 处理

好处:

1.恢复局部性,处理版本, 在处理分层的过程中可以更新和删除

2.最好的固定时间偏移的方法。

几个重要的设计理念

1. 我们只在major compaction的时候把文件输出到多个窗口。 与此同时, 我们还需要维护最老文件所在的最高层次的窗口大小。一旦一个文件够老,超过了MinorCompaction的界限,我们就不再对他进行compaction。这些文件将会一直在我们最后一次compact时的最高层窗口大小保持一直的时间间隔。 Major Compaction会更改这些文件,但我们不会改变文件的布局。

2.对于minor compaction而言, 我们不会输出多文件,原因在于目前compaction有关于seqId的连续性要求。Minor compaction的输出只有两个文件,一个是在当前时间窗的文件,一个是不在当前时间窗的尾部。如果有某些时间窗中的文件被排除在compaction之外, compaction的输出将会只有一个文件。当时间窗范围扩大, 这种乱序数据的问题将会被逐渐解决。

3.我们需要一种新的compaction, 因为时间窗布局取决于计算被调用时间,我们需要跨越文件列表边界的镜像而不是分别两次调用(这句话没有理解)

4. 我们不能安全的分配seqId除非0到当前的HRegion.sequenceId之间有足够的空间。这不仅仅是对于时间分层的Compaction来讲,
也是对于按key分层的Compaction来讲。如果使用负seqId,我们就打破了buldload文件才可以使用负seqId的假设。一种方法是在每次compaction的时候都增加HRegion.sequenceId,这样后面flush的文件在我们决定是否需要compact的时候就会包括更得seqId。另一种方法是强制每次compact过的文件都设置HRegion.sequenceId最大。我个人倾向于第二种方法,但是无论哪种方式都会包含许多重要的更改但是收益很有限。因为不同的文件之间没有重复的键值或重复的时间,我们可以保证输出文件的正确性。

5.由于我们队所有的输出文件设置了同样的seqId,我们需要根据最大的时间戳来排序。目前所有的compaction策略都是通过seqId和其他方面排序,我们只在DTCP中使用这个策略,来避免影响compaction策略。

6.对目前的存储引擎和Compaction策略我们需要一定的调整。

Region分裂和合并

Region分裂的时候,Regionserver会把所有的存储文件的进行分裂, 做法是在父region新建两个引用文件。这两个引用文件将会指向父region的文件。在分裂发生之后,元数据和HDFS仍然会包含父节点的引用。这些引用将会在子region进行Compaction的时候清除。垃圾清理线程将会定期查看子region是否仍然引用父region的文件,如果不再被引用文件将会被清空。

region合并是与分裂相反。唯一的担忧在于这些从两个region来的文件是否会进入同一个compaction窗口。最差情况下, 所有包含max_age的文件将会被compact,类似于major compaction。 需要通过限制流量来防止IO波动和竞争。

从exploring compaction策略改变为分层compaction策略不会需要更改内部compaction流程,也不会影响当前逻辑。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Hbase DTCP compaction