分享

hbase教程-Flush与Compaction



一条数据的HBase之旅,简明HBase入门教程-Flush与Compaction

Flush与Compaction其实属于Write流程的继续,所以本文应该称之为”Write后传“。在2.0版本中,最主要的变化就是新增了In-memory Flush/Compaction,而DateTieredCompaction并不算2.0新加入的特性,2.0版本在Compaction核心算法方面并没有什么新的突破。本文将带你探讨Flush/Compaction的一些本质问题。

在阅读本文之前,希望你已经阅读过:

一条数据的HBase之旅,简明HBase入门教程-开篇


一条数据的HBase之旅,简明HBase入门教程-Write全流程




前文回顾:


1. 介绍HBase写数据可选接口以及接口定义
2. 通过一个样例,介绍了RowKey定义以及列定义的一些方法,以及如何组装Put对象
3. 数据路由,数据分发、打包,以及Client通过RPC发送写数据请求至RegionServer
4. RegionServer接收数据以后,将数据写到每一个Region中。写数据流程先写WAL再写MemStore,这里展开了一些技术细节
5. 简单介绍了HBase权限控制模型

至此,数据已经被写入WAL与MemStore,可以说数据已经被成功写到HBase中了。事实上,上篇文章讲到的Flush流程是"简化"后的流程,在2.0版本中,这里已经变的更加复杂。



本文思路


1. 回顾Flush&Compaction旧流程
2. 介绍2.0版本的In-memory Flush & Compaction特性
3. 介绍Compaction要解决的本质问题是什么
4. 在选择合理的Compaction策略之前,用户应该从哪些维度调研自己的业务模型
5. HBase现有的Compaction策略有哪些,各自的适用场景是什么
6. Compaction如何选择待合并的文件
7. 关于Compaction更多的一些思考


Flush&Compaction


这是1.X系列版本以及更早版本中的Flush&Compaction行为:

MemStore中的数据,达到一定的阈值,被Flush成HDFS中的HFile文件。

但随着Flush次数的不断增多,HFile的文件数量也会不断增多,那这会带来什么影响?在HBaseCon 2013大会上,Hontonworks的名为《Compaction Improvements in Apache HBase》的演讲主题中,提到了他们测试过的随着HFile的数量的不断增多对读取时延带来的影响:
1.png

尽管关于Read的流程在后面文章中才会讲到,但下图可以帮助我们简单的理解这其中的原因:
2.png

图中说明了从一个文件中指定RowKey为“66660000431^201803011300”的记录,以及从两个文件中读取该行记录的区别,明显,从两个文件中读取,将导致更多的IOPS。这就是HBase Compaction存在的一大初衷,Compaction可以将一些HFile文件合并成较大的HFile文件,也可以把所有的HFile文件合并成一个大的HFile文件,这个过程可以理解为:将多个HFile的“交错无序状态”,变成单个HFile的“有序状态”,降低读取时延。小范围的HFile文件合并,称之为Minor Compaction,一个列族中将所有的HFile文件合并,称之为Major Compaction。除了文件合并范围的不同之外,Major Compaction还会清理一些TTL过期/版本过旧以及被标记删除的数据。下图直观描述了旧版本中的Flush与Compaction流程:
3.png



Flush


在2.0版本中,Flush的行为发生了变化,默认的Flush,仅仅是将正在写的MemStore中的数据归档成一个不可变的Segment,而这个Segment依然处于内存中,这就是2.0的新特性:In-memory Flush and Compaction ,而且该特性在2.0版本中已被默认启用(系统表除外)。

上文中简单提到了MemStore的核心是一个CellSet,但到了这里,我们可以发现,MemStore的结构其实更加复杂:MemStore由一个可写的Segment,以及一个或多个不可写的Segments构成。


4.png


MemStore中的数据先Flush成一个Immutable的Segment,多个Immutable Segments可以在内存中进行Compaction,当达到一定阈值以后才将内存中的数据持久化成HDFS中的HFile文件。

看到这里,可能会有这样的疑问:这样做的好处是什么?为何不直接调大MemStore的Flush Size?

如果MemStore中的数据被直接Flush成HFile,而多个HFile又被Compaction合并成了一个大HFile,随着一次次Compaction发生以后,一条数据往往被重写了多次,这带来显著的IO放大问题,另外,频繁的Compaction对IO资源的抢占,其实也是导致HBase查询时延大毛刺的罪魁祸首之一。而In-memory Flush and Compaction特性可以有力改善这一问题。

那为何不干脆调大MemStore的大小?这里的本质原因在于,ConcurrentSkipListMap在存储的数据量达到一定大小以后,写入性能将会出现显著的恶化。

在融入了In-Memory Flush and Compaction特性之后,Flush与Compaction的整体流程演变为:


5.png

关于Flush执行的策略
一个Region中是否执行Flush,原来的默认行为是通过计算Region中所有Column Family的整体大小,如果超过了一个阈值,则这个Region中所有的Column Family都会被执行Flush。
2.0版本中合入了0.89-fb版本中的一个特性:HBASE-10201/HBASE-3149:Make flush decisions per column family。
2.0版本中默认启用的Flush策略为FlushAllLargeStoresPolicy,也就是说,这个策略使得每一次只Flush超出阈值大小的Column Family,如果都未超出大小,则所有的Column Family都会被Flush。
改动之前,一个Region中所有的Column Family的Flush都是同步的,虽然容易导致大量的小HFile,但也有好处,尤其是对于WAL文件的快速老化,避免导致过多的WAL文件。而如果这些Column Family的Flush不同步以后,可能会导致过多的WAL文件(过多的WAL文件会触发一些拥有老数据的Column Family执行Flush),这里需要结合业务场景实测一下。如果每一行数据的写入,多个Column Family的数据都是同步写入的,那么,这个默认策略可能并不合适。

更多阅读原文

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条