HBase高性能随机查询之道 – HFile原理解析

hbasegroup 发表了文章 • 0 个评论 • 563 次浏览 • 2018-07-02 11:20 • 来自相关话题

在各色数据库系统百花齐放的今天,能让大家铭记的,往往是一个数据库所能带给大家的差异化能力。正如梁宁老师的产品思维课程中所讲到的,这是一个数据库系统所能带给产品使用者的”确定性”。
差异化能力通常需要从数据库底层开始构筑,而数据存储方式显得至关重要,因为它直接关乎数据写入与读取的效率。在一个系统中,这两方面的能力需要进行很好的权衡:如果设计有利于数据的快速写入,可能意味着查询时需要需要花费较大的精力去组织数据,反之,如果写入时花费精力去更好的组织数据,查询就会变的非常轻松。
探讨数据库的数据存储方式,其实就是探讨数据如何在磁盘上进行有效的组织。因为我们通常以如何高效读取和消费数据为目的,而不是数据存储本身。在RDBMS领域,因为键与数据的组织方式的区别,有两种表组织结构最为常见,一种是键与数据联合存储的索引组织表结构,在这种表结构下,查到键值意味着查找到数据;另外一种是键与数据分离存储的堆表结构。在这种表结构下,查找到键以后,只是拿到了数据记录的物理地址,还需要基于该物理地址去查找具体的数据记录。
在大数据分析领域,有几种通用的文件格式,如Parquet, RCFile, ORCFile,CarbonData等等,这些文件大多基于列式的设计结构,来加速通用的分析型查询。但在实时数据库领域,却以各种私有的文件格式最为常见,如Bigtable的SSTable,HBase的HFile,Kudu的DiskRowSets,Cassandra的变种SSTable,MongoDB支持的每一种Storage Engine都是私有的文件格式设计,等等。
本文将详细探讨HBase的HFile设计,第一部分为HFile原理概述,第二部分介绍了一个HFile从无到有的生成过程,最后部分列出了几点与HFile有关的附加信息。
HFile原理概述
最初的HFile格式(HFile V1),参考了Bigtable的SSTable以及Hadoop的TFile(HADOOP-3315)。如下图所示:




HFile在生成之前,数据在内存中已经是按序组织的。存放用户数据的KeyValue,被存储在一个个默认为64kb大小的Data Block中,在Data Index部分存储了每一个Data Block的索引信息{Offset,Size,FirstKey},而Data Index的索引信息{Data Index Offset, Data Block Count}被存储在HFile的Trailer部分。除此以外,在Meta Block部分还存储了Bloom Filter的数据。下图更直观的表达出了HFile V1中的数据组织结构:




这种设计简单、直观。但用过0.90或更老版本的同学,对于这个HFile版本所存在的问题应该深有痛楚:Region Open的时候,需要加载所有的Data Block Index数据,另外,第一次读取时需要加载所有的Bloom Filter数据到内存中。一个HFile中的Bloom Filter的数据大小可达百MB级别,一个RegionServer启动时可能需要加载数GB的Data Block Index数据。这在一个大数据量的集群中,几乎无法忍受。
Data Block Index究竟有多大?
一个Data Block在Data Block Index中的索引信息包含{Offset, Size, FirstKey},BlockOffset使用Long型数字表示,Size使用Int表示即可。假设用户数据RowKey的长度为50bytes,那么,一个64KB的Data Block在Data Block Index中的一条索引数据大小约为62字节。
假设一个RegionServer中有500个Region,每一个Region的数量为10GB(假设这是Data Blocks的总大小),在这个RegionServer上,约有81920000个Data Blocks,此时,Data Block Index所占用的大小为81920000*62bytes,约为4.7GB。
这是HFile V2设计的初衷,HFile V2期望显著降低RegionServer启动时加载HFile的时延,更希望解决一次全量加载数百MB级别的BloomFilter数据带来的时延过大的问题。下图是HFile V2的数据组织结构:




较之HFile V1,我们来看看HFile V2的几点显著变化:
1.分层索引​
无论是Data Block Index还是Bloom Filter,都采用了分层索引的设计。
Data Block的索引,在HFile V2中做多可支持三层索引:最底层的Data Block Index称之为Leaf Index Block,可直接索引到Data Block;中间层称之为Intermediate Index Block,最上层称之为Root Data Index,Root Data index存放在一个称之为”Load-on-open Section“区域,Region Open时会被加载到内存中。基本的索引逻辑为:由Root Data Index索引到Intermediate Block Index,再由Intermediate Block Index索引到Leaf Index Block,最后由Leaf Index Block查找到对应的Data Block。在实际场景中,Intermediate Block Index基本上不会存在,文末部分会通过详细的计算阐述它基本不存在的原因,因此,索引逻辑被简化为:由Root Data Index直接索引到Leaf Index Block,再由Leaf Index Block查找到的对应的Data Block。
2.交叉存放
在”Scanned Block Section“区域,Data Block(存放用户数据KeyValue)、存放Data Block索引的Leaf Index Block(存放Data Block的索引)与Bloom Block(Bloom Filter数据)交叉存在。
3.按需读取
无论是Data Block的索引数据,还是Bloom Filter数据,都被拆成了多个Block,基于这样的设计,无论是索引数据,还是Bloom Filter,都可以按需读取,避免在Region Open阶段或读取阶段一次读入大量的数据,有效降低时延。
从0.98版本开始,社区引入了HFile V3版本,主要是为了支持Tag特性,在HFile V2基础上只做了微量改动。在下文内容中,主要围绕HFile V2的设计展开。
HFile生成流程
在本章节,我们以Flush流程为例,介绍如何一步步生成HFile的流程,来加深大家对于HFile原理的理解。起初,HFile中并没有任何Block,数据还存在于MemStore中。
Flush发生时,创建HFile Writer,第一个空的Data Block出现,初始化后的Data Block中为Header部分预留了空间,Header部分用来存放一个Data Block的元数据信息。
而后,位于MemStore中的KeyValues被一个个append到位于内存中的第一个Data Block中:




注:如果配置了Data Block Encoding,则会在Append KeyValue的时候进行同步编码,编码后的数据不再是单纯的KeyValue模式。Data Block Encoding是HBase为了降低KeyValue结构性膨胀而提供的内部编码机制。上图中所体现出来的KeyValue,只是为了方便大家理解。
当Data Block增长到预设大小(默认64KB)后,一个Data Block被停止写入,该Data Block将经历如下一系列处理流程:
1.如果有配置启用压缩或加密特性,对Data Block的数据按相应的算法进行压缩和加密。




2.在预留的Header区,写入该Data Block的元数据信息,包含{压缩前的大小,压缩后的大小,上一个Block的偏移信息,Checksum元数据信息}等信息,下图是一个Header的完整结构:




3.生成Checksum信息。




4.Data Block以及Checksum信息通过HFile Writer中的输出流写入到HDFS中。
5.为输出的Data Block生成一条索引记录,包含这个Data Block的{起始Key,偏移,大小}信息,这条索引记录被暂时记录到内存的Block Index Chunk中:




注:上图中的firstKey并不一定是这个Data Block的第一个Key,有可能是上一个Data Block的最后一个Key与这一个Data Block的第一个Key之间的一个中间值。具体可参考附录部分的信息。
至此,已经写入了第一个Data Block,并且在Block Index Chunk中记录了关于这个Data Block的一条索引记录。
随着Data Blocks数量的不断增多,Block Index Chunk中的记录数量也在不断变多。当Block Index Chunk达到一定大小以后(默认为128KB),Block Index Chunk也经与Data Block的类似处理流程后输出到HDFS中,形成第一个Leaf Index Block:




此时,已输出的Scanned Block Section部分的构成如下:




正是因为Leaf Index Block与Data Block在Scanned Block Section交叉存在,Leaf Index Block被称之为Inline Block(Bloom Block也属于Inline Block)。在内存中还有一个Root Block Index Chunk用来记录每一个Leaf Index Block的索引信息:




从Root Index到Leaf Data Block再到Data Block的索引关系如下:




我们先假设没有Bloom Filter数据。当MemStore中所有的KeyValues全部写完以后,HFile Writer开始在close方法中处理最后的”收尾”工作:
1.写入最后一个Data Block。
2.写入最后一个Leaf Index Block。
如上属于Scanned Block Section部分的”收尾”工作。
3.如果有MetaData则写入位于Non-Scanned Block Section区域的Meta Blocks,事实上这部分为空。
4.写Root Block Index Chunk部分数据:
如果Root Block Index Chunk超出了预设大小,则输出位于Non-Scanned Block Section区域的Intermediate Index Block数据,以及生成并输出Root Index Block(记录Intermediate Index Block索引)到Load-On-Open Section部分。
如果未超出大小,则直接输出为Load-On-Open Section部分的Root Index Block。
5.写入用来索引Meta Blocks的Meta Index数据(事实上这部分只是写入一个空的Block)。
6.写入FileInfo信息,FileInfo中包含:
Max SequenceID, MajorCompaction标记,TimeRanage信息,最早的Timestamp, Data BlockEncoding类型,BloomFilter配置,最大的Timestamp,KeyValue版本,最后一个RowKey,平均的Key长度,平均Value长度,Key比较器等。
7.写入Bloom Filter元数据与索引数据。
注:前面每一部分信息的写入,都以Block形式写入,都包含Header与Data两部分,Header中的结构也是相同的,只是都有不同的Block Type,在Data部分,每一种类型的Block可以有自己的定义。
8.写入Trailer部分信息, Trailer中包含:
Root Index Block的Offset,FileInfo部分Offset,Data Block Index的层级,Data Block Index数据总大小,第一个Data Block的Offset,最后一个Data Block的Offset,Comparator信息,Root Index Block的Entries数量,加密算法类型,Meta Index Block的Entries数量,整个HFile文件未压缩大小,整个HFile中所包含的KeyValue总个数,压缩算法类型等。
至此,一个完整的HFile已生成。我们可以通过下图再简单回顾一下Root Index Block、Leaf Index Block、Data Block所处的位置以及索引关系:




简单起见,上文中刻意忽略了Bloom Filter部分。Bloom Filter被用来快速判断一条记录是否在一个大的集合中存在,采用了多个Hash函数+位图的设计。写入数据时,一个记录经X个Hash函数运算后,被映射到位图中的X个位置,将位图中的这X个位置写为1。判断一条记录是否存在时,也是通过这个X个Hash函数计算后,获得X个位置,如果位图中的这X个位置都为1,则表明该记录”可能存在”,但如果至少有一个为0,则该记录”一定不存在”。详细信息,大家可以直接参考Wiki,这里不做过多展开。
Bloom Filter包含Bloom元数据(Hash函数类型,Hash函数个数等)与位图数据(BloomData),为了避免每一次读取时加载所有的Bloom Data,HFile V2中将BloomData部分分成了多个小的Bloom Block。BloomData数据也被当成一类Inline Block,与Data Block、Leaf Index Block交叉存在,而关于Bloom Filter的元数据与多个Bloom Block的索引信息,被存放在Load-On-Open Section部分。但需要注意的是,在FileInfo部分,保存了关于BloomFilter配置类型信息,共包含三种类型:不启用,基于Row构建BloomFilter,基于Row+Column构建Bloom Filter。混合了BloomFilter Block以后的HFile构成如下图所示:




附录1 多大的HFile文件才存在Intermiate Index Block
每一个Leaf Index Block大小的计算方法如下(HFileBlockIndex$BlockIndexChunk#getNonRootSize):/**
* @return the size of this chunk if stored in the non-root
* index block format
*/
int getNonRootSize() {
// Number of entries
// Secondary index
// All entries
return Bytes.SIZEOF_INT
+ Bytes.SIZEOF_INT * (blockKeys.size() + 1)
+ curTotalNonRootEntrySize;
}curTotalNonRootEntrySize是在每次写入一个新的Entry的时候累加的:static final int SECONDARY_INDEX_ENTRY_OVERHEAD =
Bytes.SIZEOF_INT + Bytes.SIZEOF_LONG;

void add(byte firstKey, long blockOffset, int onDiskDataSize,
long curTotalNumSubEntries) {
// Record the offset for the secondary index
secondaryIndexOffsetMarks.add(curTotalNonRootEntrySize);
curTotalNonRootEntrySize
+= SECONDARY_INDEX_ENTRY_OVERHEAD
+ firstKey.length;
// ....(略去非相关代码)...
}这样子,可以看出来,每一次新增一个Entry,则累计的值为:
​ 12 + firstKey.length
假设一个Leaf Index Block可以容纳的Data Block的数量为x:
​ 4 + 4 * (x + 1) + x * (12 + firstKey.length)
进一步假设,firstKey.length为50bytes。而一个Leaf Index Block的默认最大大小为128KB:
​ 4 + 4 * (x + 1) + x * (12 + 50) = 128 * 1024
​ x ≈1986
也就是说,在假设firstKey.length为50Bytes时,一个128KB的Leaf Index Block所能容纳的Data Block数量约为1986个。
我们再来看看Root Index Chunk大小的计算方法:/**
* @return the size of this chunk if stored in the root index block format
*/
int getRootSize() {
return curTotalRootSize;
}

void add(byte firstKey, long blockOffset, int onDiskDataSize,
long curTotalNumSubEntries) {
// ......
curTotalRootSize += Bytes.SIZEOF_LONG + Bytes.SIZEOF_INT
+ WritableUtils.getVIntSize(firstKey.length) + firstKey.length;
// ......
}基于firstKey为50 Bytes的假设,每往Root Index Chunk中新增一个Entry(关联一个Leaf Index Block),那么,curTotalRootSize的累加值为:
​ 12 + 1 + 50 = 63
因此,一个128KB的Root Index Chunk可以至少存储2080个Entries,即可存储2080个Leaf Index Block。
这样, 一个Root Index Chunk所关联的Data Blocks的总量应该为:
​ 1986 * 2080 = 4,130,880
而每一个Data Block默认大小为64KB,那么,这个HFile的总大小至少为:
​ 4,130,880 * 64 * 1024 ≈ 252 GB
即,基于每一个Block中的FirstKey为50bytes的假设,一个128KB的Root Index Block可容纳的HFile文件总大小约为252GB。
如果实际的RowKey小于50 Bytes,或者将Data Block的Size调大,一个128KB的Root Index Chunk所关联的HFile文件将会更大。因此,在大多数场景中,Intermediate Index Block并不会存在。
附录2 关于HFile数据查看工具
HBase中提供了一个名为HFilePrettyPrinter的工具,可以以一种直观的方式查看HFile中的数据,关于该工具的帮助信息,可通过如下命令查看:
hbase org.apache.hadoop.hbase.io.hfile.HFile
References
HBase Architecture 101 – Storage
HBASE-3857: Change the HFile Format
HBase Document: Appendix H: HFile format
HADOOP-3315: New Binary file format
SSTable and Log Structured Storage: LevelDB
 
转载自毕杰山“HBase高性能随机查询之道 – HFile原理解析” 查看全部
在各色数据库系统百花齐放的今天,能让大家铭记的,往往是一个数据库所能带给大家的差异化能力。正如梁宁老师的产品思维课程中所讲到的,这是一个数据库系统所能带给产品使用者的”确定性”。
差异化能力通常需要从数据库底层开始构筑,而数据存储方式显得至关重要,因为它直接关乎数据写入与读取的效率。在一个系统中,这两方面的能力需要进行很好的权衡:如果设计有利于数据的快速写入,可能意味着查询时需要需要花费较大的精力去组织数据,反之,如果写入时花费精力去更好的组织数据,查询就会变的非常轻松。
探讨数据库的数据存储方式,其实就是探讨数据如何在磁盘上进行有效的组织。因为我们通常以如何高效读取和消费数据为目的,而不是数据存储本身。在RDBMS领域,因为键与数据的组织方式的区别,有两种表组织结构最为常见,一种是键与数据联合存储的索引组织表结构,在这种表结构下,查到键值意味着查找到数据;另外一种是键与数据分离存储的堆表结构。在这种表结构下,查找到键以后,只是拿到了数据记录的物理地址,还需要基于该物理地址去查找具体的数据记录。
在大数据分析领域,有几种通用的文件格式,如Parquet, RCFile, ORCFile,CarbonData等等,这些文件大多基于列式的设计结构,来加速通用的分析型查询。但在实时数据库领域,却以各种私有的文件格式最为常见,如Bigtable的SSTable,HBase的HFile,Kudu的DiskRowSets,Cassandra的变种SSTable,MongoDB支持的每一种Storage Engine都是私有的文件格式设计,等等。
本文将详细探讨HBase的HFile设计,第一部分为HFile原理概述,第二部分介绍了一个HFile从无到有的生成过程,最后部分列出了几点与HFile有关的附加信息。
HFile原理概述
最初的HFile格式(HFile V1),参考了Bigtable的SSTable以及Hadoop的TFile(HADOOP-3315)。如下图所示:
HFile-V1.jpg

HFile在生成之前,数据在内存中已经是按序组织的。存放用户数据的KeyValue,被存储在一个个默认为64kb大小的Data Block中,在Data Index部分存储了每一个Data Block的索引信息{Offset,Size,FirstKey},而Data Index的索引信息{Data Index Offset, Data Block Count}被存储在HFile的Trailer部分。除此以外,在Meta Block部分还存储了Bloom Filter的数据。下图更直观的表达出了HFile V1中的数据组织结构:
HFileV1-Index.png

这种设计简单、直观。但用过0.90或更老版本的同学,对于这个HFile版本所存在的问题应该深有痛楚:Region Open的时候,需要加载所有的Data Block Index数据,另外,第一次读取时需要加载所有的Bloom Filter数据到内存中。一个HFile中的Bloom Filter的数据大小可达百MB级别,一个RegionServer启动时可能需要加载数GB的Data Block Index数据。这在一个大数据量的集群中,几乎无法忍受。
Data Block Index究竟有多大?
一个Data Block在Data Block Index中的索引信息包含{Offset, Size, FirstKey},BlockOffset使用Long型数字表示,Size使用Int表示即可。假设用户数据RowKey的长度为50bytes,那么,一个64KB的Data Block在Data Block Index中的一条索引数据大小约为62字节。
假设一个RegionServer中有500个Region,每一个Region的数量为10GB(假设这是Data Blocks的总大小),在这个RegionServer上,约有81920000个Data Blocks,此时,Data Block Index所占用的大小为81920000*62bytes,约为4.7GB。

这是HFile V2设计的初衷,HFile V2期望显著降低RegionServer启动时加载HFile的时延,更希望解决一次全量加载数百MB级别的BloomFilter数据带来的时延过大的问题。下图是HFile V2的数据组织结构:
HFileV2.png

较之HFile V1,我们来看看HFile V2的几点显著变化:
1.分层索引​
无论是Data Block Index还是Bloom Filter,都采用了分层索引的设计。
Data Block的索引,在HFile V2中做多可支持三层索引:最底层的Data Block Index称之为Leaf Index Block,可直接索引到Data Block;中间层称之为Intermediate Index Block,最上层称之为Root Data Index,Root Data index存放在一个称之为”Load-on-open Section“区域,Region Open时会被加载到内存中。基本的索引逻辑为:由Root Data Index索引到Intermediate Block Index,再由Intermediate Block Index索引到Leaf Index Block,最后由Leaf Index Block查找到对应的Data Block。在实际场景中,Intermediate Block Index基本上不会存在,文末部分会通过详细的计算阐述它基本不存在的原因,因此,索引逻辑被简化为:由Root Data Index直接索引到Leaf Index Block,再由Leaf Index Block查找到的对应的Data Block。
2.交叉存放
在”Scanned Block Section“区域,Data Block(存放用户数据KeyValue)、存放Data Block索引的Leaf Index Block(存放Data Block的索引)与Bloom Block(Bloom Filter数据)交叉存在。
3.按需读取
无论是Data Block的索引数据,还是Bloom Filter数据,都被拆成了多个Block,基于这样的设计,无论是索引数据,还是Bloom Filter,都可以按需读取,避免在Region Open阶段或读取阶段一次读入大量的数据,有效降低时延。
从0.98版本开始,社区引入了HFile V3版本,主要是为了支持Tag特性,在HFile V2基础上只做了微量改动。在下文内容中,主要围绕HFile V2的设计展开。
HFile生成流程
在本章节,我们以Flush流程为例,介绍如何一步步生成HFile的流程,来加深大家对于HFile原理的理解。起初,HFile中并没有任何Block,数据还存在于MemStore中。
Flush发生时,创建HFile Writer,第一个空的Data Block出现,初始化后的Data Block中为Header部分预留了空间,Header部分用来存放一个Data Block的元数据信息。
而后,位于MemStore中的KeyValues被一个个append到位于内存中的第一个Data Block中:
1.HFileBlock-A_.png

:如果配置了Data Block Encoding,则会在Append KeyValue的时候进行同步编码,编码后的数据不再是单纯的KeyValue模式。Data Block Encoding是HBase为了降低KeyValue结构性膨胀而提供的内部编码机制。上图中所体现出来的KeyValue,只是为了方便大家理解。
当Data Block增长到预设大小(默认64KB)后,一个Data Block被停止写入,该Data Block将经历如下一系列处理流程:
1.如果有配置启用压缩或加密特性,对Data Block的数据按相应的算法进行压缩和加密。
1.HFileBlock-B_.png

2.在预留的Header区,写入该Data Block的元数据信息,包含{压缩前的大小,压缩后的大小,上一个Block的偏移信息,Checksum元数据信息}等信息,下图是一个Header的完整结构:
HFileBlockHeader.png

3.生成Checksum信息。
1.HFileBlock-C_.png

4.Data Block以及Checksum信息通过HFile Writer中的输出流写入到HDFS中。
5.为输出的Data Block生成一条索引记录,包含这个Data Block的{起始Key,偏移,大小}信息,这条索引记录被暂时记录到内存的Block Index Chunk中:
1.HFileBlock-D-AddIndexEntry_.png

:上图中的firstKey并不一定是这个Data Block的第一个Key,有可能是上一个Data Block的最后一个Key与这一个Data Block的第一个Key之间的一个中间值。具体可参考附录部分的信息。
至此,已经写入了第一个Data Block,并且在Block Index Chunk中记录了关于这个Data Block的一条索引记录。
随着Data Blocks数量的不断增多,Block Index Chunk中的记录数量也在不断变多。当Block Index Chunk达到一定大小以后(默认为128KB),Block Index Chunk也经与Data Block的类似处理流程后输出到HDFS中,形成第一个Leaf Index Block
2.BlockIndexChunk-A_.png

此时,已输出的Scanned Block Section部分的构成如下:
2.BlockIndexChunk-B_.png

正是因为Leaf Index Block与Data Block在Scanned Block Section交叉存在,Leaf Index Block被称之为Inline Block(Bloom Block也属于Inline Block)。在内存中还有一个Root Block Index Chunk用来记录每一个Leaf Index Block的索引信息
2.BlockIndexChunk-C_.png

从Root Index到Leaf Data Block再到Data Block的索引关系如下:
3.RootBlockIndex-A_.png

我们先假设没有Bloom Filter数据。当MemStore中所有的KeyValues全部写完以后,HFile Writer开始在close方法中处理最后的”收尾”工作:
1.写入最后一个Data Block。
2.写入最后一个Leaf Index Block。
如上属于Scanned Block Section部分的”收尾”工作。
3.如果有MetaData则写入位于Non-Scanned Block Section区域的Meta Blocks,事实上这部分为空。
4.写Root Block Index Chunk部分数据:
如果Root Block Index Chunk超出了预设大小,则输出位于Non-Scanned Block Section区域的Intermediate Index Block数据,以及生成并输出Root Index Block(记录Intermediate Index Block索引)到Load-On-Open Section部分。
如果未超出大小,则直接输出为Load-On-Open Section部分的Root Index Block。
5.写入用来索引Meta Blocks的Meta Index数据(事实上这部分只是写入一个空的Block)。
6.写入FileInfo信息,FileInfo中包含:
Max SequenceID, MajorCompaction标记,TimeRanage信息,最早的Timestamp, Data BlockEncoding类型,BloomFilter配置,最大的Timestamp,KeyValue版本,最后一个RowKey,平均的Key长度,平均Value长度,Key比较器等。
7.写入Bloom Filter元数据与索引数据。
:前面每一部分信息的写入,都以Block形式写入,都包含Header与Data两部分,Header中的结构也是相同的,只是都有不同的Block Type,在Data部分,每一种类型的Block可以有自己的定义。
8.写入Trailer部分信息, Trailer中包含:
Root Index Block的Offset,FileInfo部分Offset,Data Block Index的层级,Data Block Index数据总大小,第一个Data Block的Offset,最后一个Data Block的Offset,Comparator信息,Root Index Block的Entries数量,加密算法类型,Meta Index Block的Entries数量,整个HFile文件未压缩大小,整个HFile中所包含的KeyValue总个数,压缩算法类型等。
至此,一个完整的HFile已生成。我们可以通过下图再简单回顾一下Root Index Block、Leaf Index Block、Data Block所处的位置以及索引关系:
3.RootBlockIndex-B_.png

简单起见,上文中刻意忽略了Bloom Filter部分。Bloom Filter被用来快速判断一条记录是否在一个大的集合中存在,采用了多个Hash函数+位图的设计。写入数据时,一个记录经X个Hash函数运算后,被映射到位图中的X个位置,将位图中的这X个位置写为1。判断一条记录是否存在时,也是通过这个X个Hash函数计算后,获得X个位置,如果位图中的这X个位置都为1,则表明该记录”可能存在”,但如果至少有一个为0,则该记录”一定不存在”。详细信息,大家可以直接参考Wiki,这里不做过多展开。
Bloom Filter包含Bloom元数据(Hash函数类型,Hash函数个数等)位图数据(BloomData),为了避免每一次读取时加载所有的Bloom Data,HFile V2中将BloomData部分分成了多个小的Bloom Block。BloomData数据也被当成一类Inline Block,与Data Block、Leaf Index Block交叉存在,而关于Bloom Filter的元数据与多个Bloom Block的索引信息,被存放在Load-On-Open Section部分。但需要注意的是,在FileInfo部分,保存了关于BloomFilter配置类型信息,共包含三种类型:不启用,基于Row构建BloomFilter,基于Row+Column构建Bloom Filter。混合了BloomFilter Block以后的HFile构成如下图所示:
4.BloomFilter_.png

附录1 多大的HFile文件才存在Intermiate Index Block
每一个Leaf Index Block大小的计算方法如下(HFileBlockIndex$BlockIndexChunk#getNonRootSize):
/**
* @return the size of this chunk if stored in the non-root
* index block format
*/
int getNonRootSize() {
// Number of entries
// Secondary index
// All entries
return Bytes.SIZEOF_INT
+ Bytes.SIZEOF_INT * (blockKeys.size() + 1)
+ curTotalNonRootEntrySize;
}
curTotalNonRootEntrySize是在每次写入一个新的Entry的时候累加的:
static final int SECONDARY_INDEX_ENTRY_OVERHEAD = 
Bytes.SIZEOF_INT + Bytes.SIZEOF_LONG;

void add(byte firstKey, long blockOffset, int onDiskDataSize,
long curTotalNumSubEntries) {
// Record the offset for the secondary index
secondaryIndexOffsetMarks.add(curTotalNonRootEntrySize);
curTotalNonRootEntrySize
+= SECONDARY_INDEX_ENTRY_OVERHEAD
+ firstKey.length;
// ....(略去非相关代码)...
}
这样子,可以看出来,每一次新增一个Entry,则累计的值为:
​ 12 + firstKey.length
假设一个Leaf Index Block可以容纳的Data Block的数量为x:
​ 4 + 4 * (x + 1) + x * (12 + firstKey.length)
进一步假设,firstKey.length为50bytes。而一个Leaf Index Block的默认最大大小为128KB:
​ 4 + 4 * (x + 1) + x * (12 + 50) = 128 * 1024
​ x ≈1986
也就是说,在假设firstKey.length为50Bytes时,一个128KB的Leaf Index Block所能容纳的Data Block数量约为1986个。
我们再来看看Root Index Chunk大小的计算方法:
/**
* @return the size of this chunk if stored in the root index block format
*/
int getRootSize() {
return curTotalRootSize;
}

void add(byte firstKey, long blockOffset, int onDiskDataSize,
long curTotalNumSubEntries) {
// ......
curTotalRootSize += Bytes.SIZEOF_LONG + Bytes.SIZEOF_INT
+ WritableUtils.getVIntSize(firstKey.length) + firstKey.length;
// ......
}
基于firstKey为50 Bytes的假设,每往Root Index Chunk中新增一个Entry(关联一个Leaf Index Block),那么,curTotalRootSize的累加值为:
​ 12 + 1 + 50 = 63
因此,一个128KB的Root Index Chunk可以至少存储2080个Entries,即可存储2080个Leaf Index Block。
这样, 一个Root Index Chunk所关联的Data Blocks的总量应该为:
​ 1986 * 2080 = 4,130,880
而每一个Data Block默认大小为64KB,那么,这个HFile的总大小至少为:
​ 4,130,880 * 64 * 1024 ≈ 252 GB
即,基于每一个Block中的FirstKey为50bytes的假设,一个128KB的Root Index Block可容纳的HFile文件总大小约为252GB。
如果实际的RowKey小于50 Bytes,或者将Data Block的Size调大,一个128KB的Root Index Chunk所关联的HFile文件将会更大。因此,在大多数场景中,Intermediate Index Block并不会存在。
附录2 关于HFile数据查看工具
HBase中提供了一个名为HFilePrettyPrinter的工具,可以以一种直观的方式查看HFile中的数据,关于该工具的帮助信息,可通过如下命令查看:
hbase org.apache.hadoop.hbase.io.hfile.HFile
References
HBase Architecture 101 – Storage
HBASE-3857: Change the HFile Format
HBase Document: Appendix H: HFile format
HADOOP-3315: New Binary file format
SSTable and Log Structured Storage: LevelDB
 
转载自毕杰山“HBase高性能随机查询之道 – HFile原理解析”

Hbase日志存储——以便利店和无人超市业务为例

hbasegroup 发表了文章 • 0 个评论 • 591 次浏览 • 2018-07-01 21:55 • 来自相关话题

随着去年,马云提出新零售、刘强东提出无界零售等,线上电子商务公司认为线上流量红利已经殆尽,开始纷纷正式转型进入线下。阿里采取入股高鑫零售,腾讯京东联手入股永辉超市以及步步高等,正式开启线下零售大战。

在此背景下,公司正式开启便利店以及无人超市业务,与此同时参与到该项目当中。主要负责人脸进出门业务,对人脸数据进行存储与管理。由于hbase在大量数据写入的时候有很大的优势,因此考虑使用hbase;除此之外,hbase存储的数据可以接入phoenix,来实现数据的分析,因此本案例主要介绍公司便利店以及无人超市等人脸日志存储。






根据上述门店业务,首先需要考虑的是每次一个人刷脸,算法进行人脸识别的时候是多线程多任务进行识别以达到尽快地识别出来,因此会有很多次识别结果,只要其中一次识别结果成功则定义为成功,即可开门。

在此业务场景下,可以想到每个人的一次进门,会有数十条识别数据;当用户量达到一定程度的时候,因此数据量是非常庞大的。而且非常符合hbase的高写入场景,所以非常适合选择hbase作为存储,同时hbase最终存储的结果也可以导出,做分析。

下面主要列举了三点在无人超市和便利店场景下的hbase使用中的关键点。

1.关键点一:hbase的rowkey设计

idx_$num_$Uuid,其中$num=99999999999L-当前时间,$Uuid是随机生成uuid:这样设计的目地是为了能够保证最新的数据是呈现在最上面的。

2.关键点二:hbase的相关表设计

(1)设计基本的人脸采集日志表、识别日志表,用来存储所有的人脸采集日志信息、识别日志信息

(2)设计若干索引表(时间维度、业务维度、用户维度等等),索引表只存储主表的rowkey:这样做的目地是为了在查询的时候先去查询相关索引表,然后再根据索引表获取到的rowkey来获取主表信息,解决hbase不像关系型数据库一样,能够提供表之间的关联上的痛点。

3.关键点三:hbase数据分析

(1)可以将hbase中的数据同步接入phoenix来做分析以及报表处理,供运营决策。

(2)在报表方面可以考虑接入phoenix之后导入到关系型数据库中再接入tableu做报表输出。

(3)除此之外hbase数据在做分析的时候还需要结合hive来对数据进行清洗:因为每一个用户每次进门都有多次识别结果,应该选择当前最近时间段内的最后一条成功的识别结果作为该用户的进门数据,需要使用上hive开窗函数进行聚合处理。

大家工作学习遇到HBase技术问题,把问题发布到HBase技术社区论坛http://hbase.group,欢迎大家论坛上面提问留言讨论。想了解更多HBase技术关注HBase技术社区公众号(微信号:hbasegroup),非常欢迎大家积极投稿。
 
长按下面的二维码关注HBase技术社区公众号,同时也欢迎长按下面的二维码关注我的公众号










  查看全部
随着去年,马云提出新零售、刘强东提出无界零售等,线上电子商务公司认为线上流量红利已经殆尽,开始纷纷正式转型进入线下。阿里采取入股高鑫零售,腾讯京东联手入股永辉超市以及步步高等,正式开启线下零售大战。

在此背景下,公司正式开启便利店以及无人超市业务,与此同时参与到该项目当中。主要负责人脸进出门业务,对人脸数据进行存储与管理。由于hbase在大量数据写入的时候有很大的优势,因此考虑使用hbase;除此之外,hbase存储的数据可以接入phoenix,来实现数据的分析,因此本案例主要介绍公司便利店以及无人超市等人脸日志存储。

微信图片_20180701213858.png


根据上述门店业务,首先需要考虑的是每次一个人刷脸,算法进行人脸识别的时候是多线程多任务进行识别以达到尽快地识别出来,因此会有很多次识别结果,只要其中一次识别结果成功则定义为成功,即可开门。

在此业务场景下,可以想到每个人的一次进门,会有数十条识别数据;当用户量达到一定程度的时候,因此数据量是非常庞大的。而且非常符合hbase的高写入场景,所以非常适合选择hbase作为存储,同时hbase最终存储的结果也可以导出,做分析。

下面主要列举了三点在无人超市和便利店场景下的hbase使用中的关键点。

1.关键点一:hbase的rowkey设计

idx_$num_$Uuid,其中$num=99999999999L-当前时间,$Uuid是随机生成uuid:这样设计的目地是为了能够保证最新的数据是呈现在最上面的。

2.关键点二:hbase的相关表设计

(1)设计基本的人脸采集日志表、识别日志表,用来存储所有的人脸采集日志信息、识别日志信息

(2)设计若干索引表(时间维度、业务维度、用户维度等等),索引表只存储主表的rowkey:这样做的目地是为了在查询的时候先去查询相关索引表,然后再根据索引表获取到的rowkey来获取主表信息,解决hbase不像关系型数据库一样,能够提供表之间的关联上的痛点。

3.关键点三:hbase数据分析

(1)可以将hbase中的数据同步接入phoenix来做分析以及报表处理,供运营决策。

(2)在报表方面可以考虑接入phoenix之后导入到关系型数据库中再接入tableu做报表输出。

(3)除此之外hbase数据在做分析的时候还需要结合hive来对数据进行清洗:因为每一个用户每次进门都有多次识别结果,应该选择当前最近时间段内的最后一条成功的识别结果作为该用户的进门数据,需要使用上hive开窗函数进行聚合处理。

大家工作学习遇到HBase技术问题,把问题发布到HBase技术社区论坛http://hbase.group,欢迎大家论坛上面提问留言讨论。想了解更多HBase技术关注HBase技术社区公众号(微信号:hbasegroup),非常欢迎大家积极投稿。
 
长按下面的二维码关注HBase技术社区公众号,同时也欢迎长按下面的二维码关注我的公众号

微信图片_20180623105555.jpg


qrcode_for_gh_e12b18786730_258_(3).jpg

 

hbase可以存图片吗?

beyond 回复了问题 • 2 人关注 • 2 个回复 • 2947 次浏览 • 2018-06-27 19:18 • 来自相关话题

HBase表热点

beyond 回复了问题 • 5 人关注 • 4 个回复 • 650 次浏览 • 2018-06-27 17:55 • 来自相关话题

Hbase 分区能删除吗?如何删呢?

beyond 回复了问题 • 3 人关注 • 2 个回复 • 370 次浏览 • 2018-06-27 17:31 • 来自相关话题

中国HBase技术社区简介

hbasegroup 发表了文章 • 1 个评论 • 269 次浏览 • 2018-06-25 15:01 • 来自相关话题

  为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,由阿里巴巴、小米、华为、网易、京东、滴滴、知乎等公司的HBase技术研究人员共同发起了组建:中国HBase技术社区(Chinese HBase Technical Community 简称CHTC)。
  且在2018年6月6号,由阿里云主办的中国第一次HBase Meetup在北京望京阿里中心举行,来自阿里、小米、滴滴、360等公司的各位HBase的PMC、committer共聚一堂,共同探讨HBase2.0的技术革新以及HBase在国内各个大型企业内的应用价值,并一起见证HBase技术社区成立仪式的历史时刻。
  中国HBase技术社区,我们非常欢迎对HBase有技术激情的同学一起加入探讨HBase技术,同时诚邀广大HBase技术爱好者加入。大家在工作学习遇到HBase技术问题,可以把问题发布到中国HBase技术社区论坛http://hbase.group,欢迎大家论坛上面提问留言讨论。想了解更多HBase技术,关注HBase技术社区公众号(微信号:hbasegroup),邀请进社区的讨论群。 查看全部
  为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,由阿里巴巴、小米、华为、网易、京东、滴滴、知乎等公司的HBase技术研究人员共同发起了组建:中国HBase技术社区(Chinese HBase Technical Community 简称CHTC)。
  且在2018年6月6号,由阿里云主办的中国第一次HBase Meetup在北京望京阿里中心举行,来自阿里、小米、滴滴、360等公司的各位HBase的PMC、committer共聚一堂,共同探讨HBase2.0的技术革新以及HBase在国内各个大型企业内的应用价值,并一起见证HBase技术社区成立仪式的历史时刻。
  中国HBase技术社区,我们非常欢迎对HBase有技术激情的同学一起加入探讨HBase技术,同时诚邀广大HBase技术爱好者加入。大家在工作学习遇到HBase技术问题,可以把问题发布到中国HBase技术社区论坛http://hbase.group,欢迎大家论坛上面提问留言讨论。想了解更多HBase技术,关注HBase技术社区公众号(微信号:hbasegroup),邀请进社区的讨论群。

我们为什么需要HBase?

hbasegroup 发表了文章 • 0 个评论 • 542 次浏览 • 2018-06-23 10:58 • 来自相关话题

我们肯定听说过HBase,但是对于HBase的了解可能仅仅是它是Hadoop生态圈重要的一员,它是大数据技术圈一个很强的开源项目。然后内心os:它很屌,但是我用mysql/oracle。

一门技术的兴起,一个优秀的开源项目的存在肯定是有它所存在的意义,正如大数据一样,正是因为随着时间的发展,随着技术的发展导致我们每天的数据增量达到一个非常庞大的状态,同时在数据之中又能挖掘到很多有用的信息。所以才有了大数据技术的飞速发展。那么,我们为什么需要HBase,什么时候需要HBase呢?

HBase是什么?

HBase(Hadoop
Database) 是一个高可靠性,高性能,可伸缩,面向列的分布式数据库(也许叫做存储系统会更加贴切)。

就跟Hadoop本身也是起源与Google发布的GFS和MapReduce相关的论文一样,HBase是Google BigTable的开源实现。它整体的架构与BigTable很类似。例如:Google BigTableHBase利用GFS作为文件存储系统利用HDFS作为文件存储系统运行MapReduce处理存储的海量数据同样利用Hadoop MapReduce处理海量数据利用Chubby作为协同服务利用Zookeeper作为协同服务

HBase与Hadoop的关系非常紧密,Hadoop的HDFS提供了高可靠性的底层存储支持,Hadoop MapReduce为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定性及failover机制的保障。同时其他周边产品诸如Hive可以与HBase相结合使在HBase进行数据统计处理变得简单,Sqoop为HBase提供了方便的RDBMS数据导入功能,使传统数据库的数据向HBase中迁移变得容易,Spark等高性能的内存分布式计算引擎也可能帮助我们更加快速的对HBase中的数据进行处理分析。

大数据的水很深,但是范围适中。初学者都是扎根于Hadoop的生态圈,HBase是必学技能之一

为什么选择HBase?而不是Mysql或者Oracle

当我们开始学习一门技术的时候总是习惯于将它们与已有的技术进行对比。当我们刚接触python的时候会发现它的简洁与效率,当我们刚接触php的时候也会探寻为啥它是最好的语言没有之一。。。

那么HBase经常会和常见的关系型数据库进行对比:

HBase  Mysql or Oracle列式,Nosql数据库行式,关系型数据库只支持byte类型支持多种数据类型支持海量数据存储支持大量数据存储只支持基于rowkey的索引支持每秒百万查询吞吐量每秒数千查询吞吐量事务只支持到row级别完整的事务适合时间序列或者随机查询适合复杂查询,多表关联等数据维护形式单一,更新支持多个版本存在数据增删改查非常方便,直接修改原有数据

其实两者的对比毫无意义,因为两者适用于不同的场景

HBase作为一个NoSQL,不支持完整的事务性,而且仅仅支持基于RowKey的索引,在性能上不如memcached和redis。但是在海量数据,持久化存储方便比内存类型的NoSQL强的多,作为文档型NoSQL在分布式存储上比mongoDB做切分和MapReduce分析也简单方便的多。这一切都源于HBase本身基于Hadoop,可以简单的通过增加廉价节点的方式进行扩展,对于数据本身就可以很好的进行水平切分,同时和HDFS,MapReduce,Spark等结合的很好。不仅可以方便的进行存储同时可以更加方便的对数据进行处理和运算,这才是HBase最核心的特性。这些都是常见的关系型数据库无法比拟的。比其他常见的NoSQL也要强出不少。

当然,HBase并不能解决所有的问题,所以才会有那么多的NoSQL和SQL

HBase典型的应用场景就是不断的插入新的信息。对于持续的大量的插入可以达到每秒百万的吞吐量。对于已有的数据修改的频率是很小的。 Google用自己的BigTable存储互联网上新生成的网页,Facebook的messenger是基于HBase实现的。

举个栗子

在大数据相关的应用之中,假设你要存储用户的地址和喜好。这些当然可以存储到关系型数据库之中,但是假设用户从上海搬到了北京。那么之前上海的地址就要update覆盖掉吗?这种应用场景下,我们需要计算分析用户的整个人生周期的活动记录和喜好,进而推测他的行为,收入,知识层次,信用等等。这些历史行为是不能被丢弃的,所以HBase可以很好的适应这样的场景。

摘自知乎:《HBase为什么火?它适用于哪些业务场景》中向磊的回答。

对于海量小文件存储HBase也是非常适合的。对比于支持文档型数据存储的MongoDB,HBase写优先于随机读,MongoDB的写性能不如读性能。两者虽然都支持MapReduce但是HBase对MapReduce的支持更好,同时HBase本身就支持水平切分,在数据分片上也有很大的优势。同时HBase本身就支持多个版本,对于多版本的数据存储也很方便。Mongo对于复杂查询支持较好,但是我们HBase也有Phoenix。
 
 
大家工作学习遇到HBase技术问题,把问题发布到HBase技术社区论坛http://hbase.group,欢迎大家论坛上面提问留言讨论。想了解更多HBase技术关注HBase技术社区公众号(微信号:hbasegroup),非常欢迎大家积极投稿。
 
长按下面的二维码关注HBase技术社区公众号,同时也欢迎长按下面的二维码关注我的公众号








 
 
 
  查看全部
我们肯定听说过HBase,但是对于HBase的了解可能仅仅是它是Hadoop生态圈重要的一员,它是大数据技术圈一个很强的开源项目。然后内心os:它很屌,但是我用mysql/oracle。

一门技术的兴起,一个优秀的开源项目的存在肯定是有它所存在的意义,正如大数据一样,正是因为随着时间的发展,随着技术的发展导致我们每天的数据增量达到一个非常庞大的状态,同时在数据之中又能挖掘到很多有用的信息。所以才有了大数据技术的飞速发展。那么,我们为什么需要HBase,什么时候需要HBase呢?

HBase是什么?

HBase(Hadoop
Database) 是一个高可靠性,高性能,可伸缩,面向列的分布式数据库(也许叫做存储系统会更加贴切)。

就跟Hadoop本身也是起源与Google发布的GFS和MapReduce相关的论文一样,HBase是Google BigTable的开源实现。它整体的架构与BigTable很类似。例如:Google BigTableHBase利用GFS作为文件存储系统利用HDFS作为文件存储系统运行MapReduce处理存储的海量数据同样利用Hadoop MapReduce处理海量数据利用Chubby作为协同服务利用Zookeeper作为协同服务

HBase与Hadoop的关系非常紧密,Hadoop的HDFS提供了高可靠性的底层存储支持,Hadoop MapReduce为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定性及failover机制的保障。同时其他周边产品诸如Hive可以与HBase相结合使在HBase进行数据统计处理变得简单,Sqoop为HBase提供了方便的RDBMS数据导入功能,使传统数据库的数据向HBase中迁移变得容易,Spark等高性能的内存分布式计算引擎也可能帮助我们更加快速的对HBase中的数据进行处理分析。

大数据的水很深,但是范围适中。初学者都是扎根于Hadoop的生态圈,HBase是必学技能之一

为什么选择HBase?而不是Mysql或者Oracle

当我们开始学习一门技术的时候总是习惯于将它们与已有的技术进行对比。当我们刚接触python的时候会发现它的简洁与效率,当我们刚接触php的时候也会探寻为啥它是最好的语言没有之一。。。

那么HBase经常会和常见的关系型数据库进行对比:

HBase  Mysql or Oracle列式,Nosql数据库行式,关系型数据库只支持byte类型支持多种数据类型支持海量数据存储支持大量数据存储只支持基于rowkey的索引支持每秒百万查询吞吐量每秒数千查询吞吐量事务只支持到row级别完整的事务适合时间序列或者随机查询适合复杂查询,多表关联等数据维护形式单一,更新支持多个版本存在数据增删改查非常方便,直接修改原有数据

其实两者的对比毫无意义,因为两者适用于不同的场景

HBase作为一个NoSQL,不支持完整的事务性,而且仅仅支持基于RowKey的索引,在性能上不如memcached和redis。但是在海量数据,持久化存储方便比内存类型的NoSQL强的多,作为文档型NoSQL在分布式存储上比mongoDB做切分和MapReduce分析也简单方便的多。这一切都源于HBase本身基于Hadoop,可以简单的通过增加廉价节点的方式进行扩展,对于数据本身就可以很好的进行水平切分,同时和HDFS,MapReduce,Spark等结合的很好。不仅可以方便的进行存储同时可以更加方便的对数据进行处理和运算,这才是HBase最核心的特性。这些都是常见的关系型数据库无法比拟的。比其他常见的NoSQL也要强出不少。

当然,HBase并不能解决所有的问题,所以才会有那么多的NoSQL和SQL

HBase典型的应用场景就是不断的插入新的信息。对于持续的大量的插入可以达到每秒百万的吞吐量。对于已有的数据修改的频率是很小的。 Google用自己的BigTable存储互联网上新生成的网页,Facebook的messenger是基于HBase实现的。

举个栗子

在大数据相关的应用之中,假设你要存储用户的地址和喜好。这些当然可以存储到关系型数据库之中,但是假设用户从上海搬到了北京。那么之前上海的地址就要update覆盖掉吗?这种应用场景下,我们需要计算分析用户的整个人生周期的活动记录和喜好,进而推测他的行为,收入,知识层次,信用等等。这些历史行为是不能被丢弃的,所以HBase可以很好的适应这样的场景。

摘自知乎:《HBase为什么火?它适用于哪些业务场景》中向磊的回答。

对于海量小文件存储HBase也是非常适合的。对比于支持文档型数据存储的MongoDB,HBase写优先于随机读,MongoDB的写性能不如读性能。两者虽然都支持MapReduce但是HBase对MapReduce的支持更好,同时HBase本身就支持水平切分,在数据分片上也有很大的优势。同时HBase本身就支持多个版本,对于多版本的数据存储也很方便。Mongo对于复杂查询支持较好,但是我们HBase也有Phoenix。
 
 
大家工作学习遇到HBase技术问题,把问题发布到HBase技术社区论坛http://hbase.group,欢迎大家论坛上面提问留言讨论。想了解更多HBase技术关注HBase技术社区公众号(微信号:hbasegroup),非常欢迎大家积极投稿。
 
长按下面的二维码关注HBase技术社区公众号,同时也欢迎长按下面的二维码关注我的公众号
微信图片_20180623105555.jpg

qrcode_for_gh_e12b18786730_258_(3).jpg

 
 
 
 

HBase 有没有对业务影响最小的滚动重启方案?

martin 回复了问题 • 3 人关注 • 2 个回复 • 600 次浏览 • 2018-06-17 20:09 • 来自相关话题

中国HBase技术社区第一届MeetUp

hbasegroup 发表了文章 • 2 个评论 • 675 次浏览 • 2018-05-31 13:52 • 来自相关话题

6月6日,由中国HBase技术社区组织,阿里云主办的中国第一届HBase Meetup将在北京举行,来自阿里、小米、滴滴、360等公司的各位大神会共同探讨HBase2.0的技术革新,HBase在国内各个大型企业内的应用价值,并一起见证中国HBase技术社区成立仪式的历史时刻。主办方阿里云将在线直播此次meetup,对于不能去现场的小伙伴可以收藏此网址,在6月6号下午14:00观看直播。中国HBase技术社区第一届MeetUp:https://promotion.aliyun.com/n ... .html
 
HBase Meetup亮点
共同见证中国HBase技术社区成立HBase大佬,神秘嘉宾亮相寄语多位HBase committer为您深度解读HBase2.0
名企HBase负责人讲述典型业务应用
 
直播议程安排
2018.06.06
14:00-14:30 | 议程:云数据库HBase2.0产品发布
所在 阿里云HBase高级产品专家
宣布阿里云云数据库HBase2.0版本发布,介绍云数据库HBase2.0版本基于社区版本做的改进以及重点企业级功能介绍。

14:30-15:00 | 议程:HBase2.0研讨圆桌会
HBase Committers&各公司HBase负责人
出席嘉宾(排名不分次序): 陈恒(HBase Committer,蚂蚁金服); 曹龙(阿里云HBase负责人); 胡争(HBase Committer,小米); 罗李(研究员, 滴滴); 李钰(HBase PMC, 阿里); 杨文龙(HBase Committer, 阿里) ; 杨哲(HBase Committer, 小马智行); 沈春辉(HBase PMC, 阿里); 王锋(奇虎360大数据负责人); 姚靖怡(滴滴HBase负责人); 张铎(HBase PMC, 小米); 张洸豪(HBase PMC, 小米)。

15:00-15:10 | 议程:中国HBase技术社区成立及招募仪式
阿里云、滴滴、小米等社区发起者
宣布中国HBase技术社区正式成立,并进行成员招募
15:10-15:40 | 议程:HBase 3.0的发展规划
张铎 HBase PMC 小米HBase负责人
展望HBase3.0的规划及技术革新给业务场景带来的价值

15:40-16:10 | 议程:滴滴HBase应用与实践
姚靖怡 滴滴HBase负责人
讲述HBase在滴滴实际业务中的应用

16:10-17:00 | 议程:当HBase遇上云的思考
封神 阿里云HBase负责人详解阿里云HBase基于社区版本的改进及企业级功能解决的用户痛点
 
中国HBase技术社区招募
为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,由HBase项目负责人Stack授权,阿里云发起,滴滴、小米等公司的HBase技术研究人员共同组建了中国HBase技术社区(CHTC:Chinese HBase Technical Community),旨在成为中国最有影响力的HBase技术社区,社区已经试运行2个月,现正式对广大HBase爱好者开放招募,加入中国HBase用户会,您将获得:
获取HBase最新技术迭代信息以及权威解读参加社区不定期组织的 线下meetup,拓展合作机会与各路技术大牛共同探讨 学习HBase为HBase的发展提出您的 意见,推动技术进步
 
加入中国HBase技术社区
HBase是一个分布式的面向列的开源数据库,是大数据生态圈中非常重要的一环,主要应用在大数据量(PB级)存储及超大规模(千万级QPS)随机读写访问。为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,阿里巴巴、小米、华为、网易、京东、滴滴、知乎等公司的HBase技术研究人员共同发起了组建HBase技术社区。我们非常欢迎对HBase有技术激情的同学一起加入探讨HBase技术,如果你热爱写技术博客,欢迎加入我们,一起坚持创作写出高质量的内容。加入中国HBase技术社区请点击链接:https://mp.weixin.qq.com/s/3XNu-cbDuhy7y6gARjFSzw
 
 
  查看全部
6月6日,由中国HBase技术社区组织,阿里云主办的中国第一届HBase Meetup将在北京举行,来自阿里、小米、滴滴、360等公司的各位大神会共同探讨HBase2.0的技术革新,HBase在国内各个大型企业内的应用价值,并一起见证中国HBase技术社区成立仪式的历史时刻。主办方阿里云将在线直播此次meetup,对于不能去现场的小伙伴可以收藏此网址,在6月6号下午14:00观看直播。中国HBase技术社区第一届MeetUp:https://promotion.aliyun.com/n ... .html
 
HBase Meetup亮点
  • 共同见证中国HBase技术社区成立
  • HBase大佬,神秘嘉宾亮相寄语
  • 多位HBase committer为您深度解读HBase2.0

  • 名企HBase负责人讲述典型业务应用

 
直播议程安排
2018.06.06
14:00-14:30 | 议程:云数据库HBase2.0产品发布

所在 阿里云HBase高级产品专家
宣布阿里云云数据库HBase2.0版本发布,介绍云数据库HBase2.0版本基于社区版本做的改进以及重点企业级功能介绍。

14:30-15:00 | 议程:HBase2.0研讨圆桌会
HBase Committers&各公司HBase负责人
出席嘉宾(排名不分次序): 陈恒(HBase Committer,蚂蚁金服); 曹龙(阿里云HBase负责人); 胡争(HBase Committer,小米); 罗李(研究员, 滴滴); 李钰(HBase PMC, 阿里); 杨文龙(HBase Committer, 阿里) ; 杨哲(HBase Committer, 小马智行); 沈春辉(HBase PMC, 阿里); 王锋(奇虎360大数据负责人); 姚靖怡(滴滴HBase负责人); 张铎(HBase PMC, 小米); 张洸豪(HBase PMC, 小米)。

15:00-15:10 | 议程:中国HBase技术社区成立及招募仪式
阿里云、滴滴、小米等社区发起者

宣布中国HBase技术社区正式成立,并进行成员招募
15:10-15:40 | 议程:HBase 3.0的发展规划
张铎 HBase PMC 小米HBase负责人

展望HBase3.0的规划及技术革新给业务场景带来的价值

15:40-16:10 | 议程:滴滴HBase应用与实践
姚靖怡 滴滴HBase负责人

讲述HBase在滴滴实际业务中的应用

16:10-17:00 | 议程:当HBase遇上云的思考
封神 阿里云HBase负责人详解阿里云HBase基于社区版本的改进及企业级功能解决的用户痛点
 
中国HBase技术社区招募
为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,由HBase项目负责人Stack授权,阿里云发起,滴滴、小米等公司的HBase技术研究人员共同组建了中国HBase技术社区(CHTC:Chinese HBase Technical Community),旨在成为中国最有影响力的HBase技术社区,社区已经试运行2个月,现正式对广大HBase爱好者开放招募,加入中国HBase用户会,您将获得:
  • 获取HBase最新技术迭代信息以及权威解读
  • 参加社区不定期组织的 线下meetup,拓展合作机会
  • 与各路技术大牛共同探讨 学习HBase
  • 为HBase的发展提出您的 意见,推动技术进步

 
加入中国HBase技术社区
HBase是一个分布式的面向列的开源数据库,是大数据生态圈中非常重要的一环,主要应用在大数据量(PB级)存储及超大规模(千万级QPS)随机读写访问。为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,阿里巴巴、小米、华为、网易、京东、滴滴、知乎等公司的HBase技术研究人员共同发起了组建HBase技术社区。我们非常欢迎对HBase有技术激情的同学一起加入探讨HBase技术,如果你热爱写技术博客,欢迎加入我们,一起坚持创作写出高质量的内容。加入中国HBase技术社区请点击链接:https://mp.weixin.qq.com/s/3XNu-cbDuhy7y6gARjFSzw
 
 
 

Hbase中的数据大家是怎么进行权限控制的?

guokaiwhu 回复了问题 • 5 人关注 • 4 个回复 • 2996 次浏览 • 2018-05-29 11:41 • 来自相关话题

hbase ACL用户认证

CGod 回复了问题 • 2 人关注 • 1 个回复 • 2703 次浏览 • 2018-05-28 17:15 • 来自相关话题

HBase2.0新特性之In-Memory Compaction

hbasegroup 发表了文章 • 0 个评论 • 476 次浏览 • 2018-05-07 13:06 • 来自相关话题

In-Memory Compaction是HBase2.0中的重要特性之一,通过在内存中引入LSM结构,减少多余数据,实现降低flush频率和减小写放大的效果。本文根据HBase2.0中相关代码以及社区的讨论、博客,介绍In-Memory Compaction的使用和实现原理。
原理
概念和数据结构
In-Memory Compaction中引入了MemStore的一个新的实现类 CompactingMemStore。顾名思义,这个类和默认memstore的区别在于实现了在内存中compaction。
CompactingMemStore中,数据以 segment作为单位进行组织,一个memStore中包含多个segment。数据写入时首先进入一个被称为 active 的segment,这个segment是可修改的。当active满之后,会被移动到 pipeline中,这个过程称为 in-memory flush 。pipeline中包含多个segment,其中的数据不可修改。CompactingMemStore会在后台将pipeline中的多个segment合并为一个更大、更紧凑的segment,这就是compaction的过程。
如果RegionServer需要把memstore的数据flush到磁盘,会首先选择其他类型的memstore,然后再选择CompactingMemStore。这是因为CompactingMemStore对内存的管理更有效率,所以延长CompactingMemStore的生命周期可以减少总的I/O。当CompactingMemStore被flush到磁盘时,pipeline中的所有segment会被移到一个snapshot中进行合并然后写入HFile。




在默认的MemStore中,对cell的索引使用ConcurrentSkipListMap,这种结构支持动态修改,但是其中存在大量小对象,内存浪费比较严重。而在CompactingMemStore中,由于pipeline里面的数据是只读的,就可以使用更紧凑的数据结构来存储索引,减少内存使用。代码中使用CellArrayMap结构来存储cell索引,其内部实现是一个数组。




Compaction策略
当一个active segment被flush到pipeline中之后,后台会触发一个任务对pipeline中的数据进行合并。合并任务会对pipeline中所有segment进行scan,将他们的索引合并为一个。有三种合并策略可供选择:Basic,Eager,Adaptive。
Basic compaction策略和Eager compaction策略的区别在于如何处理cell数据。Basic compaction不会清理多余的数据版本,这样就不需要对cell的内存进行拷贝。而Eager compaction会过滤重复的数据,并清理多余的版本,这意味着会有额外的开销:例如如果使用了MSLAB存储cell数据,就需要把经过清理之后的cell从旧的MSLAB拷贝到新的MSLAB。basic适用于所有写入模式,eager则主要针对数据大量淘汰的场景:例如消息队列、购物车等。
Adaptive策略则是根据数据的重复情况来决定是否使用Eager策略。在Adaptive策略中,首先会对待合并的segment进行评估,方法是在已经统计过不重复key个数的segment中,找出cell个数最多的一个,然后用这个segment的numUniqueKeys / getCellsCount得到一个比例,如果比例小于设定的阈值,则使用Eager策略,否则使用Basic策略。
使用
配置
2.0中,默认的In-Memory Compaction策略为basic。可以通过修改hbase-site.xml修改:<property>
<name>hbase.hregion.compacting.memstore.type</name>
<value><none|basic|eager|adaptive></value>
</property>也可以单独设置某个列族的级别:create ‘<tablename>’, {NAME => ‘<cfname>’, IN_MEMORY_COMPACTION => ‘<NONE|BASIC|EAGER|ADAPTIVE>’}性能提升
社区的博客中给出了两个不同场景的测试结果。使用YCSB测试工具,100-200 GB数据集。分别在key热度符合Zipf分布和平均分布两种情况下,测试了只有写操作情况下写放大、吞吐、GC相比默认memstore的变化,以及读写各占50%情况下尾部读延时的变化。
测试结果如下表:




结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。 查看全部
In-Memory Compaction是HBase2.0中的重要特性之一,通过在内存中引入LSM结构,减少多余数据,实现降低flush频率和减小写放大的效果。本文根据HBase2.0中相关代码以及社区的讨论、博客,介绍In-Memory Compaction的使用和实现原理。
原理
概念和数据结构
In-Memory Compaction中引入了MemStore的一个新的实现类 CompactingMemStore。顾名思义,这个类和默认memstore的区别在于实现了在内存中compaction。
CompactingMemStore中,数据以 segment作为单位进行组织,一个memStore中包含多个segment。数据写入时首先进入一个被称为 active 的segment,这个segment是可修改的。当active满之后,会被移动到 pipeline中,这个过程称为 in-memory flush 。pipeline中包含多个segment,其中的数据不可修改。CompactingMemStore会在后台将pipeline中的多个segment合并为一个更大、更紧凑的segment,这就是compaction的过程。
如果RegionServer需要把memstore的数据flush到磁盘,会首先选择其他类型的memstore,然后再选择CompactingMemStore。这是因为CompactingMemStore对内存的管理更有效率,所以延长CompactingMemStore的生命周期可以减少总的I/O。当CompactingMemStore被flush到磁盘时,pipeline中的所有segment会被移到一个snapshot中进行合并然后写入HFile。
2.png

在默认的MemStore中,对cell的索引使用ConcurrentSkipListMap,这种结构支持动态修改,但是其中存在大量小对象,内存浪费比较严重。而在CompactingMemStore中,由于pipeline里面的数据是只读的,就可以使用更紧凑的数据结构来存储索引,减少内存使用。代码中使用CellArrayMap结构来存储cell索引,其内部实现是一个数组。
3.png

Compaction策略
当一个active segment被flush到pipeline中之后,后台会触发一个任务对pipeline中的数据进行合并。合并任务会对pipeline中所有segment进行scan,将他们的索引合并为一个。有三种合并策略可供选择:Basic,Eager,Adaptive。
Basic compaction策略和Eager compaction策略的区别在于如何处理cell数据。Basic compaction不会清理多余的数据版本,这样就不需要对cell的内存进行拷贝。而Eager compaction会过滤重复的数据,并清理多余的版本,这意味着会有额外的开销:例如如果使用了MSLAB存储cell数据,就需要把经过清理之后的cell从旧的MSLAB拷贝到新的MSLAB。basic适用于所有写入模式,eager则主要针对数据大量淘汰的场景:例如消息队列、购物车等。
Adaptive策略则是根据数据的重复情况来决定是否使用Eager策略。在Adaptive策略中,首先会对待合并的segment进行评估,方法是在已经统计过不重复key个数的segment中,找出cell个数最多的一个,然后用这个segment的numUniqueKeys / getCellsCount得到一个比例,如果比例小于设定的阈值,则使用Eager策略,否则使用Basic策略。
使用
配置

2.0中,默认的In-Memory Compaction策略为basic。可以通过修改hbase-site.xml修改:
<property>
<name>hbase.hregion.compacting.memstore.type</name>
<value><none|basic|eager|adaptive></value>
</property>
也可以单独设置某个列族的级别:
create ‘<tablename>’, {NAME => ‘<cfname>’, IN_MEMORY_COMPACTION => ‘<NONE|BASIC|EAGER|ADAPTIVE>’}
性能提升
社区的博客中给出了两个不同场景的测试结果。使用YCSB测试工具,100-200 GB数据集。分别在key热度符合Zipf分布和平均分布两种情况下,测试了只有写操作情况下写放大、吞吐、GC相比默认memstore的变化,以及读写各占50%情况下尾部读延时的变化。
测试结果如下表:
4.png

结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
1.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。

HBase MOB压缩分区策略介绍

hbasegroup 发表了文章 • 1 个评论 • 611 次浏览 • 2018-05-07 12:53 • 来自相关话题

介绍
HBase MOB特性是在HBASE-11339中引入,这一特性改善了对中等大小值的低延迟读写(基于我们的测试结果理想状态是100K到10M),这使得可以更好的存储文本,图片和一些其他的中等对象[1],HBase MOB特性通过将引用文件和MOB对象的IO路径分离来实现这一改进,对MOB使用不同的压缩策略并因此减少了因为HBase压缩所导致的写放大问题。若一个表的MOB文件存储在MOB region中,则意味着该region中将存在大量的MOB文件。请参阅下图中的MOB体系结构。




MOB体系结构
最初,MOB文件相对较小(少于1或2个HDFS块)。为了提高HDFS的效率,MOB文件通过称为MOB压缩方式,周期性地合并成较大的文件,该操作独立于正常的压缩过程。 MOB压缩的初始版本将当天的多个MOB文件重写为较大的MOB文件。通过下面示例我们可以更清楚了解这一过程。表t1有两个分区(r1,r2),一个列族f1,并且该表启用了MOB属性。你可以看到如下两个前缀:
D279186428a75016b17e4df5ea43d080  对应分区r1中startkey的散列值
D41d8cd98f00b204e9800998ecf8427e  对应分区r2中startkey的散列值 
r1分区在2016.1.1和2016.1.2各有两个MOB文件,r2分区在2016.1.1有三个MOB文件,具体我们可以通过下面命令查看>ls /hbase/data/mobdir/data/default/t1/78e317a6e78a0fceb27b9fa0cb9dcf5b/f1D279186428a75016b17e4df5ea43d08020160101f9d9713ab2fb4a8b825485f6a8acfcd5
D279186428a75016b17e4df5ea43d08020160101af7713ab2fbf4a8abc5135f6a8467ca8
D279186428a75016b17e4df5ea43d080201601029013ab2fceda8b825485f6a8acfcd515
D279186428a75016b17e4df5ea43d080201601029a7978013ab2fceda8b825485f6a8acf
D41d8cd98f00b204e9800998ecf8427e20160101fc94af623c2345f1b241887721e32a48
D41d8cd98f00b204e9800998ecf8427e20160101d0954af623c2345f1b241887721e3259
D41d8cd98f00b204e9800998ecf8427e20160101439adf4af623c2345f1b241887721e32
通过MOB压缩之后,r1中20161.1和20161.2两天的MOB文件每天被压缩成一个文件,r2中2016.1.1的三个MOB文件被压缩成一个文件,结果如下:
D279186428a75016b17e4df5ea43d08020160101f49a9d9713ab2fb4a8b825485f6a8acf
D279186428a75016b17e4df5ea43d08020160102bc9176d09424e49a9d9065caf9713ab2
D41d8cd98f00b204e9800998ecf8427e20160101d9cb0954af623c2345f1b241887721e3
由于只有在同一区并且为同一天的MOB文件才可被压缩在一起,因此在一个MOB region中的目录下,一年产生的MOB文件数为365乘以region数目。若有1000个region通过MOB压缩,10年后将会有365 x 1000 x 10,3.65(百万)个文件产生并且文件数量会持续增长。但是,由于HDFS中一个目录的文件数目受内存限制[2],当MOB文件数超过HDFS限制后,MOB表将不再可写入文件。HDFS在一个目录下默认的最大文件数为100万,那么对于1000个分区来说,文件数量将在3年左右达到这个极限值。所以分区越多,文件数量将会越快达到这个极限值。
从HBASE-16981开始引入按周和月的MOB压缩分区聚合策略后,最终结果使得MOB文件存放比例相应提高了7%和30%。
HBASE-16981的基本思路是将一周或者一个月的MOB文件压缩合并为更大的文件。根据ISO8601定义的周(起始为周一结束为周日),若采用周策略进行MOB压缩后,则每个分区每周会产生一个文件,同理,用月MOB压缩后,每月会生成一个文件,最终在一个MOB区域目录下的文件数分别为52 乘以分区数和12乘以分区数。这样就大大减少了压缩后MOB文件的数量。
最初的方法
当MOB压缩发生时,HMaster会在一个日历月或一个日历周内将MOB文件合并到更大的文件中。根据MOB压缩发生的频率,文件可能多次被压缩。例如,若MOB采用每天压缩及每月聚合的策略,那么,第1天所有的MOB文件会被压缩为一个文件,第2天将第1天和第2天产生的MOB文件被压缩为一个新的文件,第3天将前两天产生的文件压缩为一个新文件,以此类推,一个月后,第1天的文件压缩会超过30次,因此也就将写的IO数量放大了30倍以上。
HBase MOB的设计目标是为了减少由MOB压缩而导致的写入放大。上述的这种方法没能达到设计目标。
最终的方法
为了克服最初方案的不足,在HBASE-16981中采用了新的按周和月分阶段压缩策略。图2展示了如何按月压缩策略,同时按周压缩策略与此类似。




图2 按月MOB压缩策略
图2所示的MOB压缩发生在2016.11.15。根据配置的MOB阈值,日分区压缩当前日历周中的文件,上图中11.14和11.15的两天的文件各自压缩。当前月份(11月)中的文件基于周阈值(MOB阈值 x 7)分区压缩过去几个日历周中的文件,如11.1-11.6和11.7-11.13的文件分别压缩。11月之前的文件按月进行压缩,例如10.1-10.31文件压缩在一起。需要注意的是11月的第1个日历周是从10.31-11.6结束。由于10.31是10月的最后一天,因此当天的文件压缩是按照月分区进行压缩,这样11月的第一周压缩的天数只剩下6天(11.1-11.6),如果MOB压缩阈值和压缩大小设置合理,那么第一周会有5个压缩文件。
通过这种设计模式,MOB文件可以通过2个阶段或3个阶段完成压缩。在每个阶段,日、周、月分区都会随着MOB压缩阈值的增加而变化。通常情况下,MOB文件每月最多3次压缩,每周最多压缩2次。具体的设计细节可以参考[3]。
用法
在默认情况下,MOB压缩分区策略是每日一次。若要用周或月策略,可以在MOB列族中添加了一个新属性字段:MOB_COMPACT_PARTITION_POLICY。用户可通过HBase shell在创建表时设置该属性。例如:>create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 1000000, MOB_COMPACT_PARTITION_POLICY => 'weekly’}同时也可以改变该属性字段值,命令如下:>alter 't1', {NAME => 'f1', MOB_COMPACT_PARTITION_POLICY => 'monthly'}如果压缩策略从每日改为每周或每月,或从每周改为每月,则下一个MOB压缩将重新压缩之前压缩的MOB文件。如果压缩策略从每月或每周改为每日,或者将每月改为每周,则对已使用先前策略压缩的MOB文件将不会与新策略再次执行压缩。
结束语
HBASE-16981解决了文件数大量增加的问题,并在Apache HBase 2.0.0版本中使用。CDH的CDH5.4.0+及以后的版本开始使用HBase MOB特性,其中从5.11.0开始使用HBASE-16981修复的版本。
本文虽多次斟酌,但由于译者水平有限,有翻译不当之处还请大家多多指出,互相学习,若阅读原版可以点击阅读原文跳转。
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。
参考
[1]https://blog.cloudera.com/blog ... MOBs/
[2]https://blog.cloudera.com/blog ... blem/
[3]https://issues.apache.org/jira/browse/HBASE-16981 查看全部
介绍
HBase MOB特性是在HBASE-11339中引入,这一特性改善了对中等大小值的低延迟读写(基于我们的测试结果理想状态是100K到10M),这使得可以更好的存储文本,图片和一些其他的中等对象[1],HBase MOB特性通过将引用文件和MOB对象的IO路径分离来实现这一改进,对MOB使用不同的压缩策略并因此减少了因为HBase压缩所导致的写放大问题。若一个表的MOB文件存储在MOB region中,则意味着该region中将存在大量的MOB文件。请参阅下图中的MOB体系结构。
Apache-HBase-MOB-Architecture.png

MOB体系结构
最初,MOB文件相对较小(少于1或2个HDFS块)。为了提高HDFS的效率,MOB文件通过称为MOB压缩方式,周期性地合并成较大的文件,该操作独立于正常的压缩过程。 MOB压缩的初始版本将当天的多个MOB文件重写为较大的MOB文件。通过下面示例我们可以更清楚了解这一过程。表t1有两个分区(r1,r2),一个列族f1,并且该表启用了MOB属性。你可以看到如下两个前缀:
D279186428a75016b17e4df5ea43d080  对应分区r1中startkey的散列值
D41d8cd98f00b204e9800998ecf8427e  对应分区r2中startkey的散列值 

r1分区在2016.1.1和2016.1.2各有两个MOB文件,r2分区在2016.1.1有三个MOB文件,具体我们可以通过下面命令查看
>ls  /hbase/data/mobdir/data/default/t1/78e317a6e78a0fceb27b9fa0cb9dcf5b/f1
D279186428a75016b17e4df5ea43d08020160101f9d9713ab2fb4a8b825485f6a8acfcd5
D279186428a75016b17e4df5ea43d08020160101af7713ab2fbf4a8abc5135f6a8467ca8
D279186428a75016b17e4df5ea43d080201601029013ab2fceda8b825485f6a8acfcd515
D279186428a75016b17e4df5ea43d080201601029a7978013ab2fceda8b825485f6a8acf
D41d8cd98f00b204e9800998ecf8427e20160101fc94af623c2345f1b241887721e32a48
D41d8cd98f00b204e9800998ecf8427e20160101d0954af623c2345f1b241887721e3259
D41d8cd98f00b204e9800998ecf8427e20160101439adf4af623c2345f1b241887721e32

通过MOB压缩之后,r1中20161.1和20161.2两天的MOB文件每天被压缩成一个文件,r2中2016.1.1的三个MOB文件被压缩成一个文件,结果如下:
D279186428a75016b17e4df5ea43d08020160101f49a9d9713ab2fb4a8b825485f6a8acf
D279186428a75016b17e4df5ea43d08020160102bc9176d09424e49a9d9065caf9713ab2
D41d8cd98f00b204e9800998ecf8427e20160101d9cb0954af623c2345f1b241887721e3

由于只有在同一区并且为同一天的MOB文件才可被压缩在一起,因此在一个MOB region中的目录下,一年产生的MOB文件数为365乘以region数目。若有1000个region通过MOB压缩,10年后将会有365 x 1000 x 10,3.65(百万)个文件产生并且文件数量会持续增长。但是,由于HDFS中一个目录的文件数目受内存限制[2],当MOB文件数超过HDFS限制后,MOB表将不再可写入文件。HDFS在一个目录下默认的最大文件数为100万,那么对于1000个分区来说,文件数量将在3年左右达到这个极限值。所以分区越多,文件数量将会越快达到这个极限值。
从HBASE-16981开始引入按周和月的MOB压缩分区聚合策略后,最终结果使得MOB文件存放比例相应提高了7%和30%。
HBASE-16981的基本思路是将一周或者一个月的MOB文件压缩合并为更大的文件。根据ISO8601定义的周(起始为周一结束为周日),若采用周策略进行MOB压缩后,则每个分区每周会产生一个文件,同理,用月MOB压缩后,每月会生成一个文件,最终在一个MOB区域目录下的文件数分别为52 乘以分区数和12乘以分区数。这样就大大减少了压缩后MOB文件的数量。
最初的方法
当MOB压缩发生时,HMaster会在一个日历月或一个日历周内将MOB文件合并到更大的文件中。根据MOB压缩发生的频率,文件可能多次被压缩。例如,若MOB采用每天压缩及每月聚合的策略,那么,第1天所有的MOB文件会被压缩为一个文件,第2天将第1天和第2天产生的MOB文件被压缩为一个新的文件,第3天将前两天产生的文件压缩为一个新文件,以此类推,一个月后,第1天的文件压缩会超过30次,因此也就将写的IO数量放大了30倍以上。
HBase MOB的设计目标是为了减少由MOB压缩而导致的写入放大。上述的这种方法没能达到设计目标。
最终的方法
为了克服最初方案的不足,在HBASE-16981中采用了新的按周和月分阶段压缩策略。图2展示了如何按月压缩策略,同时按周压缩策略与此类似。
Figure-2-Staging-MOB-compaction-with-monthly-policy.png

图2 按月MOB压缩策略
图2所示的MOB压缩发生在2016.11.15。根据配置的MOB阈值,日分区压缩当前日历周中的文件,上图中11.14和11.15的两天的文件各自压缩。当前月份(11月)中的文件基于周阈值(MOB阈值 x 7)分区压缩过去几个日历周中的文件,如11.1-11.6和11.7-11.13的文件分别压缩。11月之前的文件按月进行压缩,例如10.1-10.31文件压缩在一起。需要注意的是11月的第1个日历周是从10.31-11.6结束。由于10.31是10月的最后一天,因此当天的文件压缩是按照月分区进行压缩,这样11月的第一周压缩的天数只剩下6天(11.1-11.6),如果MOB压缩阈值和压缩大小设置合理,那么第一周会有5个压缩文件。
通过这种设计模式,MOB文件可以通过2个阶段或3个阶段完成压缩。在每个阶段,日、周、月分区都会随着MOB压缩阈值的增加而变化。通常情况下,MOB文件每月最多3次压缩,每周最多压缩2次。具体的设计细节可以参考[3]。
用法
在默认情况下,MOB压缩分区策略是每日一次。若要用周或月策略,可以在MOB列族中添加了一个新属性字段:MOB_COMPACT_PARTITION_POLICY。用户可通过HBase shell在创建表时设置该属性。例如:
>create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 1000000, MOB_COMPACT_PARTITION_POLICY => 'weekly’}
同时也可以改变该属性字段值,命令如下:
>alter 't1', {NAME => 'f1', MOB_COMPACT_PARTITION_POLICY => 'monthly'}
如果压缩策略从每日改为每周或每月,或从每周改为每月,则下一个MOB压缩将重新压缩之前压缩的MOB文件。如果压缩策略从每月或每周改为每日,或者将每月改为每周,则对已使用先前策略压缩的MOB文件将不会与新策略再次执行压缩。
结束语
HBASE-16981解决了文件数大量增加的问题,并在Apache HBase 2.0.0版本中使用。CDH的CDH5.4.0+及以后的版本开始使用HBase MOB特性,其中从5.11.0开始使用HBASE-16981修复的版本。
本文虽多次斟酌,但由于译者水平有限,有翻译不当之处还请大家多多指出,互相学习,若阅读原版可以点击阅读原文跳转。
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
1.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。
参考
[1]https://blog.cloudera.com/blog ... MOBs/
[2]https://blog.cloudera.com/blog ... blem/
[3]https://issues.apache.org/jira/browse/HBASE-16981

HBase行级事务模型

hbasegroup 发表了文章 • 0 个评论 • 326 次浏览 • 2018-05-07 12:46 • 来自相关话题

HBase是BigTable的开源实现,事务模型也与BigTable一脉相承 – 仅支持行级别的事务。虽然Jeff Dean大神在接受采访时公开承认目前在技术领域最后悔的事情就是没有在BigTable中加入跨行事务模型,以至于之后很多团队都在BigTable之上重复造各种各样的分布式事务轮子。这点笔者是认同的,现在确实有很多团队在HBase之上造了很多轮子(Tephra | Trafodian | Omid),试想如果这个工作做在了BigTable里面,这些团队的人是不是可以做更多其他有意义的事情了~ 所幸的是之后Google又发布了一篇介绍分布式事务模型的的paper – Percolator,现在很多团队都参考该论文实现分布式事务,包括TiDB、Omid等,也算是一种弥补吧。
虽说HBase目前只支持行级事务,但行级事务也是事务!麻雀虽小,肝脏具全。这篇文章一起看看HBase行级事务所满足的ACID特性。下文中隔离性部分基本翻译文章《Apache HBase Internals: Locking and Multiversion Concurrency Control》,大家可以阅读原文。
HBase事务原子性保证
HBase数据会首先写入WAL,再写入Memstore。写入Memstore异常很容易可以回滚,因此保证写入/更新原子性只需要保证写入WAL的原子性即可。HBase 0.98之前版本需要保证WAL写入的原子性并不容易,这由WAL的结构决定。假设一个行级事务更新R行中的3列(c1, c2, c3),来看看之前版本和当前版本的WAL结构:
1. 之前版本WAL结构:
<logseq1-for-edit1>:<KeyValue-for-edit-c1>
<logseq2-for-edit2>:<KeyValue-for-edit-c2>
<logseq3-for-edit3>:<KeyValue-for-edit-c3>
每个KV都会形成一个WAL单元,这样一行事务更新多少列就会产生多少个WAL单元。在将这些WAL单元append到日志文件的时候,一旦出现宕机或其他异常,就会出现部分写入成功的情况,原子性更新就无法保证。
2. 当前版本WAL结构:
<logseq#-for-entire-txn>:<WALEdit-for-entire-txn>
<logseq#-for-entire-txn>:<-1, 3, <Keyvalue-for-edit-c1>, <KeyValue-for-edit-c2>, <KeyValue-for-edit-c3>>
通过这种结构,每个事务只会产生一个WAL单元。这样就可以保证WAL写入时候的原子性。
HBase事务一致性保证:强一致性保证
HBase事务隔离性
写写并发控制
1. 为什么需要写写并发控制?
现在假设有两个并发写入请求同时进来,分别对同一行数据进行写入。下图所示RowKey为Greg,现在分别更新列族info下的Company列和Role列:




如果没有任何并发控制策略的话,写入数据(先写WAL,再写memstore)可能会出现不同KV写入”交叉”现象,如下图所示:




这样的话,用户最终读取到的数据就会产生不一致,如下:




2. 如何实现写写并发控制?
实现写写并发其实很简单,只需要在写入(或更新)之前先获取行锁,如果获取不到,说明已经有其他线程拿了该锁,就需要不断重试等待或者自旋等待,直至其他线程释放该锁。拿到锁之后开始写入数据,写入完成之后释放行锁即可。这种行锁机制是实现写写并发控制最常用的手段,后面可以看到MySQL也是使用行锁来实现写写并发的。
3. 如何实现批量写入多行的写写并发?
HBase支持批量写入(或批量更新),即一个线程同时更新同一个Region中的多行记录。那如何保证当前事务中的批量写入与其他事务中的批量写入的并发控制呢?思路还是一样的,使用行锁。但这里需要注意的是必须使用两阶段锁协议,即:
(1) 获取所有待写入(更新)行记录的行锁
(2) 开始执行写入(更新)操作
(3) 写入完成之后再统一释放所有行记录的行锁
不能更新一行锁定(释放)一行,多个事务之间容易形成死锁。两阶段锁协议就是为了避免死锁,MySQL事务写写并发控制同样使用两阶段锁协议。
4. 笔者疑惑
其实笔者一直在这里有个疑惑,还是使用上面例子说明吧。大家都知道,HBase是支持多版本的,那么在数据写入的时候加锁给待写入数据都打上版本信息,此时释放锁。即使之后出现交叉的现象,对于读请求来说,最终读到的数据都是根据最大版本号来的。即使该表只设置了一个版本号,那也可以根据版本号将之前版本的数据清理掉,和交叉不交叉并没有太大关系。不知道大家怎么理解这个问题?有兴趣的可以留言评论!
读写并发控制
1. 为什么需要读写并发控制?
现在我们通过在写入更新之前加锁、写入更新之后释放锁实现写写并发控制,那读写之间是不是也需要一定的并发控制呢?如果不加并发控制,会出现什么现象呢?接着看下图:




上图分别是两个事务更新同一行数据,现在假设第一个事务已经更新完成,在第二个事务更新到一半的时候进来一个读请求,如果没有任何并发控制的话,读请求就会读到不一致的数据,Company列为Restaurant,Role列为Engineer,如下图所示:




可见,读写之间也需要一种并发控制来保证读取的数据总能够保持一致性,不会出现各种诡异的不一致现象。
2. 如何实现读写并发控制?
实现读写并发最简单的方法就是仿照写写并发控制 – 加锁。但几乎所有数据库都不会这么做,性能太差,对于读多写少的应用来说必然不可接受。那还有其他方法吗?
当然,这就是今天要重点提到的MVCC机制 – Mutil Version Concurrent Control。HBase中MVCC机制实现主要分为两步:
(1) 为每一个写(更新)事务分配一个Region级别自增的序列号
(2) 为每一个读请求分配一个已完成的最大写事务序列号
示意图如下所示:




上图中两个写事务分别分配了序列号1和序列号2,读请求进来的时候事务1已经完成,事务2还未完成,因此分配事务1对应的序列号1给读请求。此时序列号1对本次读可见,序列号2对本次读不可见,读到的数据是:




具体实现中,所有的事务都会生成一个Region级别的自增序列,并添加到队列中,如下图最左侧队列,其中最底端为已经提交的事务,队列中的事务为未提交事务。现假设当前事务编号为15,并且写入完成(中间队列红色框框),但之前的写入事务还未完成(序列号为12、13、14的事务还未完成),此时当前事务必须等待,而且对读并不可见,直至之前所有事务完成之后才会对读可见(即读请求才能读取到该事务写入的数据)。如最右侧图,15号事务之前的所有事务都成功完成,此时Read Point就会移动到15号事务处,表示15号事务之前的所有改动都可见。




 Note:上文所讲的自增序列就是上一篇文章的SequenceId!!!可能有朋友有疑问:如果这两个自增序列是同一个序列,那是不是这个队列的顺序必须与事务写入WAL的顺序一致?如果不一致有什么问题?如果要求一致的话怎么才能实现?
千万不要查看1.1.2的代码,会把你彻底搞混的!建议阅读更高版本的相关代码!
所以,MVCC的精髓是写入的时候分配递增版本信息(SequenceId),读取的时候分配唯一的版本用于读取可见,比之大的版本不可见。这里需要注意版本必须递增,而且版本递增的范围一定程度上决定了事务是什么事务,比如HBase是Region级别的递增版本,那么事务就是region级别事务。MySQL中版本是单机递增版本,那么MySQL事务就支持单机跨行事务。Percolator中版本是集群递增版本,那么Percolator事务就是分布式事务。
HBase事务持久性保证
HBase事务持久化可以理解为WAL持久化,目前实现了多种持久化策略:SKIP_WAL,ASYNC_WAL,SYNC_WAL,FSYNC_WAL。SKIP_WAL表示不写WAL,这样写入更新性能最好,但在RegionServer宕机的时候有可能会丢失部分数据;ASYNC_WAL表示异步将WAL持久化到硬盘,因为是异步操作所以在异常的情况下也有可能丢失少量数据;SYNC_WAL表示同步将WAL持久化到操作系统缓存,再由操作系统将数据异步持久化到磁盘,这种场景下RS宕掉并不会丢失数据,当操作系统宕掉会导致部分数据丢失;FSYNC_WAL表示WAL写入之后立马落盘,性能相对最差。目前实现中FSYNC_WAL并没有实现!用户可以根据业务对数据丢失的敏感性在客户端配置相应的持久化策略。
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。 查看全部
HBase是BigTable的开源实现,事务模型也与BigTable一脉相承 – 仅支持行级别的事务。虽然Jeff Dean大神在接受采访时公开承认目前在技术领域最后悔的事情就是没有在BigTable中加入跨行事务模型,以至于之后很多团队都在BigTable之上重复造各种各样的分布式事务轮子。这点笔者是认同的,现在确实有很多团队在HBase之上造了很多轮子(Tephra | Trafodian | Omid),试想如果这个工作做在了BigTable里面,这些团队的人是不是可以做更多其他有意义的事情了~ 所幸的是之后Google又发布了一篇介绍分布式事务模型的的paper – Percolator,现在很多团队都参考该论文实现分布式事务,包括TiDB、Omid等,也算是一种弥补吧。
虽说HBase目前只支持行级事务,但行级事务也是事务!麻雀虽小,肝脏具全。这篇文章一起看看HBase行级事务所满足的ACID特性。下文中隔离性部分基本翻译文章《Apache HBase Internals: Locking and Multiversion Concurrency Control》,大家可以阅读原文。
HBase事务原子性保证
HBase数据会首先写入WAL,再写入Memstore。写入Memstore异常很容易可以回滚,因此保证写入/更新原子性只需要保证写入WAL的原子性即可。HBase 0.98之前版本需要保证WAL写入的原子性并不容易,这由WAL的结构决定。假设一个行级事务更新R行中的3列(c1, c2, c3),来看看之前版本和当前版本的WAL结构:
1. 之前版本WAL结构:
<logseq1-for-edit1>:<KeyValue-for-edit-c1>
<logseq2-for-edit2>:<KeyValue-for-edit-c2>
<logseq3-for-edit3>:<KeyValue-for-edit-c3>

每个KV都会形成一个WAL单元,这样一行事务更新多少列就会产生多少个WAL单元。在将这些WAL单元append到日志文件的时候,一旦出现宕机或其他异常,就会出现部分写入成功的情况,原子性更新就无法保证。
2. 当前版本WAL结构:
<logseq#-for-entire-txn>:<WALEdit-for-entire-txn>
<logseq#-for-entire-txn>:<-1, 3, <Keyvalue-for-edit-c1>, <KeyValue-for-edit-c2>, <KeyValue-for-edit-c3>>

通过这种结构,每个事务只会产生一个WAL单元。这样就可以保证WAL写入时候的原子性。
HBase事务一致性保证:强一致性保证
HBase事务隔离性

写写并发控制
1. 为什么需要写写并发控制?
现在假设有两个并发写入请求同时进来,分别对同一行数据进行写入。下图所示RowKey为Greg,现在分别更新列族info下的Company列和Role列:
2.png

如果没有任何并发控制策略的话,写入数据(先写WAL,再写memstore)可能会出现不同KV写入”交叉”现象,如下图所示:
3.png

这样的话,用户最终读取到的数据就会产生不一致,如下:
4.png

2. 如何实现写写并发控制?
实现写写并发其实很简单,只需要在写入(或更新)之前先获取行锁,如果获取不到,说明已经有其他线程拿了该锁,就需要不断重试等待或者自旋等待,直至其他线程释放该锁。拿到锁之后开始写入数据,写入完成之后释放行锁即可。这种行锁机制是实现写写并发控制最常用的手段,后面可以看到MySQL也是使用行锁来实现写写并发的。
3. 如何实现批量写入多行的写写并发?
HBase支持批量写入(或批量更新),即一个线程同时更新同一个Region中的多行记录。那如何保证当前事务中的批量写入与其他事务中的批量写入的并发控制呢?思路还是一样的,使用行锁。但这里需要注意的是必须使用两阶段锁协议,即:
(1) 获取所有待写入(更新)行记录的行锁
(2) 开始执行写入(更新)操作
(3) 写入完成之后再统一释放所有行记录的行锁
不能更新一行锁定(释放)一行,多个事务之间容易形成死锁。两阶段锁协议就是为了避免死锁,MySQL事务写写并发控制同样使用两阶段锁协议。
4. 笔者疑惑
其实笔者一直在这里有个疑惑,还是使用上面例子说明吧。大家都知道,HBase是支持多版本的,那么在数据写入的时候加锁给待写入数据都打上版本信息,此时释放锁。即使之后出现交叉的现象,对于读请求来说,最终读到的数据都是根据最大版本号来的。即使该表只设置了一个版本号,那也可以根据版本号将之前版本的数据清理掉,和交叉不交叉并没有太大关系。不知道大家怎么理解这个问题?有兴趣的可以留言评论!

读写并发控制
1. 为什么需要读写并发控制?
现在我们通过在写入更新之前加锁、写入更新之后释放锁实现写写并发控制,那读写之间是不是也需要一定的并发控制呢?如果不加并发控制,会出现什么现象呢?接着看下图:
5.png

上图分别是两个事务更新同一行数据,现在假设第一个事务已经更新完成,在第二个事务更新到一半的时候进来一个读请求,如果没有任何并发控制的话,读请求就会读到不一致的数据,Company列为Restaurant,Role列为Engineer,如下图所示:
6.png

可见,读写之间也需要一种并发控制来保证读取的数据总能够保持一致性,不会出现各种诡异的不一致现象。
2. 如何实现读写并发控制?
实现读写并发最简单的方法就是仿照写写并发控制 – 加锁。但几乎所有数据库都不会这么做,性能太差,对于读多写少的应用来说必然不可接受。那还有其他方法吗?
当然,这就是今天要重点提到的MVCC机制 – Mutil Version Concurrent Control。HBase中MVCC机制实现主要分为两步:
(1) 为每一个写(更新)事务分配一个Region级别自增的序列号
(2) 为每一个读请求分配一个已完成的最大写事务序列号
示意图如下所示:
7.png

上图中两个写事务分别分配了序列号1和序列号2,读请求进来的时候事务1已经完成,事务2还未完成,因此分配事务1对应的序列号1给读请求。此时序列号1对本次读可见,序列号2对本次读不可见,读到的数据是:
8.png

具体实现中,所有的事务都会生成一个Region级别的自增序列,并添加到队列中,如下图最左侧队列,其中最底端为已经提交的事务,队列中的事务为未提交事务。现假设当前事务编号为15,并且写入完成(中间队列红色框框),但之前的写入事务还未完成(序列号为12、13、14的事务还未完成),此时当前事务必须等待,而且对读并不可见,直至之前所有事务完成之后才会对读可见(即读请求才能读取到该事务写入的数据)。如最右侧图,15号事务之前的所有事务都成功完成,此时Read Point就会移动到15号事务处,表示15号事务之前的所有改动都可见。
9.png

 Note:上文所讲的自增序列就是上一篇文章的SequenceId!!!可能有朋友有疑问:如果这两个自增序列是同一个序列,那是不是这个队列的顺序必须与事务写入WAL的顺序一致?如果不一致有什么问题?如果要求一致的话怎么才能实现?
千万不要查看1.1.2的代码,会把你彻底搞混的!建议阅读更高版本的相关代码!
所以,MVCC的精髓是写入的时候分配递增版本信息(SequenceId),读取的时候分配唯一的版本用于读取可见,比之大的版本不可见。这里需要注意版本必须递增,而且版本递增的范围一定程度上决定了事务是什么事务,比如HBase是Region级别的递增版本,那么事务就是region级别事务。MySQL中版本是单机递增版本,那么MySQL事务就支持单机跨行事务。Percolator中版本是集群递增版本,那么Percolator事务就是分布式事务。
HBase事务持久性保证
HBase事务持久化可以理解为WAL持久化,目前实现了多种持久化策略:SKIP_WAL,ASYNC_WAL,SYNC_WAL,FSYNC_WAL。SKIP_WAL表示不写WAL,这样写入更新性能最好,但在RegionServer宕机的时候有可能会丢失部分数据;ASYNC_WAL表示异步将WAL持久化到硬盘,因为是异步操作所以在异常的情况下也有可能丢失少量数据;SYNC_WAL表示同步将WAL持久化到操作系统缓存,再由操作系统将数据异步持久化到磁盘,这种场景下RS宕掉并不会丢失数据,当操作系统宕掉会导致部分数据丢失;FSYNC_WAL表示WAL写入之后立马落盘,性能相对最差。目前实现中FSYNC_WAL并没有实现!用户可以根据业务对数据丢失的敏感性在客户端配置相应的持久化策略。
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
1.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。

HBase Read Replicas功能介绍系列

hbasegroup 发表了文章 • 0 个评论 • 431 次浏览 • 2018-05-07 12:35 • 来自相关话题

1.概述
对于HBase read replicas模块打算有几篇文章组成一个系列,详细的介绍这个功能,大概分read replicas综述、正常情况下的读写流程分析、异常情况下的读写流程分析;
本文主要介绍的有:概述、读流程链路、写流程链路、如何使用read replicas,example。我们知道HBase是一个强一致的系统,最初是因为一个regionserver下负责的多个region的读写都是经历这个regionserver去做处理,这样的话,该regionserver是单点的做读写,不会存在数据不一致的问题。但是相应的该regionserver如果挂掉了,会造成该regionserver负责的region都不能提供服务。这个降低了整个流程的服务可用性。那么为了解决该问题,HBase引入了 Read Replicas的功能,也就是对于一个region在多个节点上都有对应的副本,HBase可以通过balance保证各个region的各个副本在不同的机器,机架上。我们给主region 一个数字为0的replica_id,其余的副本都可以叫做secondary regions,他们的对应replica_id 是1、2、…,所有的写请求都是replica_id为0的节点(regionserver)做处理,然后异步的发送到1、2、…等节点。有了这个功能HBase的读流程的可用性就由原来的3个9变成了4个9。当然有利也有弊,我们做设计就是在做tradeoff,引入这个功能的话,对系统读取数据的一致性有一点影响。不过这个主要看业务方可否接受,为了提高服务可用性,牺牲一点点数据一致性是否可以考虑。




2.读流程链路
在HBase进行Get的时候,构造的Get对象里面有一个Consistency的子项,默认是Consistency.STRONG,除此之外还有一个Consistency.TIMELINE的选项。我们文章涉及到的replicas主要和这个东西有关系。如果你希望让你的读操作具有更高的可用性,你就需要在Get对象进行一个设置,设置它的Consistency属性为TIMELINE。那么通过这个设置的话,读请求就先会去replica_id为0的主replica上面去读数据,如果在一定时间内,HBase client没有等到主的响应,那么就会并发的发送请求到备份的replicas,这个时间默认是10ms,可以通过在client端的配置文件里面设置hbase.client.primaryCallTimeout.get来配置。那么你可能就会问了,这个数据可能不是主上面的数据,可能是replica_id为1、2、等上面的数据,那么这个数据不就存在老数据的可能么?对!HBase 提供了一个接口用于判别数据是不是最新的,叫做isStale()。
但是如果用户使用的是Consistency.STRONG这种的话,就不会存在读到老数据的可能性。世上很难有完美的方案,那么怎么去做选择,就是需要业务基于自己的需求做一定的选择了。这个方案的有点是:提高了读服务的可用性,同样的会引入一些弊端,造成一定的内存开销以及网络开销,因为数据需要在replicas上进行存储,也存在请求到replicas上的可能性,那么就会增加网络开销;
3.写流程链路
上面概述里面提到我们需要把HBase的写的数据先经replica_id为0 的节点,然后异步分发到replicas上面去,那么分发的过程是异步的,不然存在影响整个写流程的体验。既然设计的是异步的,在HBase 里面存在2阶段不同的实现方案,分别是在HBase1.0+和HBase1.1+这2个大版本上面实现的;在HBase的官方分别叫做: StoreFile Refresher 和 Asnyc WAL replication。
3.1.StoreFile Refresher
这种机制就是一个regionserver上一个特定的线程,阶段性的将主replica上的store file 刷新到secondary replicas上面。开启这个功能的配置是在HBase的里面把hbase.regionserver.storefile.refresh.period进行一个配置,单位是毫秒级别的。通过设置这个,定时刷新线程会看到主上的memstore 的flush,以及compaction,bulck load 操作。那么对于内存里面的数据,可能就会在备份上面读不到。
3.2.Asnyc WAL replication
在HBase1.1+的版本里面新的一种数据被复制到secondary replicas的方式是:类似HBase replication,但是是单集群内部replicas之间的数据复制,由于主和secondary replicas之间的数据共享一份持久化数据,那么数据备份到replicas的时候是需要保证内存之间的数据是相同的。主在做写,compaction,bulkload等操作的时候会写数据到wal log,然后通过这个机制secondary replicas会观察到变化,然后讲数据在本地内存回放。
这个功能默认情况下是被关闭的,通过设置“hbase.region.replica.replication.enabled” 为true即可开启这个功能。
4.使用配置和使用步骤
如果要使用功能的话,分服务端和客户端,下面这份配置是服务端的:<property>
<name>hbase.regionserver.storefile.refresh.period</name>
<value>0</value>
<description>
这个值是secondary replicas,用来多久进行数据更新的一个间隔,单位是毫秒;如果设置为0的话,表示这个功能被关闭,secondary regions 察觉到主region上的数据变化就会更新一遍文件列表。此外建议把HFile的ttl设置的比较大。
</description>
</property>

<property>
<name>hbase.regionserver.meta.storefile.refresh.period</name>
<value>300000</value>
<description>
这个配置主要用于把hbase:meta表的store file 在secondary regions上进行更新。0的话意味着关闭该功能。secondary regions上面可以观测到主上由于flush 以及compaction带来的文件更新。如果meta的replicas功能被开启了这个值建议不为0,单位是毫秒。
</description>
</property>

<property>
<name>hbase.region.replica.replication.enabled</name>
<value>true</value>
<description>
无论异步同步wal replication是否开启,如果开启,那么一个名为“region_replica_replication”的replicaion peer就会被创建,写的数据就会被复制到replicas上面。一旦被开启,需要关闭的话,同样需要关闭replication peer。
</description>
</property>
<property>
<name>hbase.region.replica.replication.memstore.enabled</name>
<value>true</value>
<description>
如果设置这个为false,replicas就不会收到主上memstore的更新。但是即使是设置诶true,你依旧可以关闭memstore的复制。这是表级别的,将表的“REGION_MEMSTORE_REPLICATION”属性设为false即可。如果设置的话secondary replicas将仅仅更新flush和bulkload的事件。
</description>
</property>
<property>
<name>hbase.master.hfilecleaner.ttl</name>
<value>3600000</value>
<description>
将store file 保留在archive 文件夹里面的时间,超过以后就删除。
</description>
</property>

<property>
<name>hbase.meta.replica.count</name>
<value>3</value>
<description>
meta表的replication个数,默认是1;
</description>
</property>


<property>
<name>hbase.region.replica.storefile.refresh.memstore.multiplier</name>
<value>4</value>
<description>
这是一个“store file 更新”的系数,如果rs 有内存压力,如果secondary replica的最大memstore 的大小比主memstore的最大的memstore还大这么多,那么secondary region将进行更新store file (refresher)。
</description>
</property>

<property>
<name>hbase.region.replica.wait.for.primary.flush</name>
<value>true</value>
<description>
是否等待检测一个全面主的刷新完成,然后开始在secondary上进行数据的服务。
</description>
</property>客户端上面的配置更新:<property>
<name>hbase.ipc.client.specificThreadForWriting</name>
<value>true</value>
<description>
是否开启中断RPC的线程。
</description>
</property>
<property>
<name>hbase.client.primaryCallTimeout.get</name>
<value>10000</value>
<description>
超过这个时间将并发发送请求给secondary replica,默认是10ms。
</description>
</property>
<property>
<name>hbase.client.primaryCallTimeout.multiget</name>
<value>10000</value>
<description>
也是类似上述的时间限制,但是对于multget操作而言。
</description>
</property>
<property>
<name>hbase.client.replicaCallTimeout.scan</name>
<value>1000000</value>
<description>
同样上述操作,但是默认的时间是1s;
</description>
</property>
<property>
<name>hbase.meta.replicas.use</name>
<value>true</value>
<description>
是否使用meta表的replica;
</description>
</property>新建一张具有region replica 的表:shell命令:create 'test', 'info', {REGION_REPLICATION => 3}java的api操作:HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(“test”));
htd.setRegionReplication(3);
...
admin.createTable(htd);读取数据:shell命令:hbase(main):001:0> get 'test','row', {CONSISTENCY => "TIMELINE"}java的api操作:Get get = new Get(row);
get.setConsistency(Consistency.TIMELINE);
...
Result result = table.get(get);结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。 查看全部
1.概述
对于HBase read replicas模块打算有几篇文章组成一个系列,详细的介绍这个功能,大概分read replicas综述、正常情况下的读写流程分析、异常情况下的读写流程分析;
本文主要介绍的有:概述、读流程链路、写流程链路、如何使用read replicas,example。我们知道HBase是一个强一致的系统,最初是因为一个regionserver下负责的多个region的读写都是经历这个regionserver去做处理,这样的话,该regionserver是单点的做读写,不会存在数据不一致的问题。但是相应的该regionserver如果挂掉了,会造成该regionserver负责的region都不能提供服务。这个降低了整个流程的服务可用性。那么为了解决该问题,HBase引入了 Read Replicas的功能,也就是对于一个region在多个节点上都有对应的副本,HBase可以通过balance保证各个region的各个副本在不同的机器,机架上。我们给主region 一个数字为0的replica_id,其余的副本都可以叫做secondary regions,他们的对应replica_id 是1、2、…,所有的写请求都是replica_id为0的节点(regionserver)做处理,然后异步的发送到1、2、…等节点。有了这个功能HBase的读流程的可用性就由原来的3个9变成了4个9。当然有利也有弊,我们做设计就是在做tradeoff,引入这个功能的话,对系统读取数据的一致性有一点影响。不过这个主要看业务方可否接受,为了提高服务可用性,牺牲一点点数据一致性是否可以考虑。
2.jpeg

2.读流程链路
在HBase进行Get的时候,构造的Get对象里面有一个Consistency的子项,默认是Consistency.STRONG,除此之外还有一个Consistency.TIMELINE的选项。我们文章涉及到的replicas主要和这个东西有关系。如果你希望让你的读操作具有更高的可用性,你就需要在Get对象进行一个设置,设置它的Consistency属性为TIMELINE。那么通过这个设置的话,读请求就先会去replica_id为0的主replica上面去读数据,如果在一定时间内,HBase client没有等到主的响应,那么就会并发的发送请求到备份的replicas,这个时间默认是10ms,可以通过在client端的配置文件里面设置hbase.client.primaryCallTimeout.get来配置。那么你可能就会问了,这个数据可能不是主上面的数据,可能是replica_id为1、2、等上面的数据,那么这个数据不就存在老数据的可能么?对!HBase 提供了一个接口用于判别数据是不是最新的,叫做isStale()。
但是如果用户使用的是Consistency.STRONG这种的话,就不会存在读到老数据的可能性。世上很难有完美的方案,那么怎么去做选择,就是需要业务基于自己的需求做一定的选择了。这个方案的有点是:提高了读服务的可用性,同样的会引入一些弊端,造成一定的内存开销以及网络开销,因为数据需要在replicas上进行存储,也存在请求到replicas上的可能性,那么就会增加网络开销;
3.写流程链路
上面概述里面提到我们需要把HBase的写的数据先经replica_id为0 的节点,然后异步分发到replicas上面去,那么分发的过程是异步的,不然存在影响整个写流程的体验。既然设计的是异步的,在HBase 里面存在2阶段不同的实现方案,分别是在HBase1.0+和HBase1.1+这2个大版本上面实现的;在HBase的官方分别叫做: StoreFile Refresher 和 Asnyc WAL replication。
3.1.StoreFile Refresher
这种机制就是一个regionserver上一个特定的线程,阶段性的将主replica上的store file 刷新到secondary replicas上面。开启这个功能的配置是在HBase的里面把hbase.regionserver.storefile.refresh.period进行一个配置,单位是毫秒级别的。通过设置这个,定时刷新线程会看到主上的memstore 的flush,以及compaction,bulck load 操作。那么对于内存里面的数据,可能就会在备份上面读不到。
3.2.Asnyc WAL replication
在HBase1.1+的版本里面新的一种数据被复制到secondary replicas的方式是:类似HBase replication,但是是单集群内部replicas之间的数据复制,由于主和secondary replicas之间的数据共享一份持久化数据,那么数据备份到replicas的时候是需要保证内存之间的数据是相同的。主在做写,compaction,bulkload等操作的时候会写数据到wal log,然后通过这个机制secondary replicas会观察到变化,然后讲数据在本地内存回放。
这个功能默认情况下是被关闭的,通过设置“hbase.region.replica.replication.enabled” 为true即可开启这个功能。
4.使用配置和使用步骤
如果要使用功能的话,分服务端和客户端,下面这份配置是服务端的:
<property>
<name>hbase.regionserver.storefile.refresh.period</name>
<value>0</value>
<description>
这个值是secondary replicas,用来多久进行数据更新的一个间隔,单位是毫秒;如果设置为0的话,表示这个功能被关闭,secondary regions 察觉到主region上的数据变化就会更新一遍文件列表。此外建议把HFile的ttl设置的比较大。
</description>
</property>

<property>
<name>hbase.regionserver.meta.storefile.refresh.period</name>
<value>300000</value>
<description>
这个配置主要用于把hbase:meta表的store file 在secondary regions上进行更新。0的话意味着关闭该功能。secondary regions上面可以观测到主上由于flush 以及compaction带来的文件更新。如果meta的replicas功能被开启了这个值建议不为0,单位是毫秒。
</description>
</property>

<property>
<name>hbase.region.replica.replication.enabled</name>
<value>true</value>
<description>
无论异步同步wal replication是否开启,如果开启,那么一个名为“region_replica_replication”的replicaion peer就会被创建,写的数据就会被复制到replicas上面。一旦被开启,需要关闭的话,同样需要关闭replication peer。
</description>
</property>
<property>
<name>hbase.region.replica.replication.memstore.enabled</name>
<value>true</value>
<description>
如果设置这个为false,replicas就不会收到主上memstore的更新。但是即使是设置诶true,你依旧可以关闭memstore的复制。这是表级别的,将表的“REGION_MEMSTORE_REPLICATION”属性设为false即可。如果设置的话secondary replicas将仅仅更新flush和bulkload的事件。
</description>
</property>
<property>
<name>hbase.master.hfilecleaner.ttl</name>
<value>3600000</value>
<description>
将store file 保留在archive 文件夹里面的时间,超过以后就删除。
</description>
</property>

<property>
<name>hbase.meta.replica.count</name>
<value>3</value>
<description>
meta表的replication个数,默认是1;
</description>
</property>


<property>
<name>hbase.region.replica.storefile.refresh.memstore.multiplier</name>
<value>4</value>
<description>
这是一个“store file 更新”的系数,如果rs 有内存压力,如果secondary replica的最大memstore 的大小比主memstore的最大的memstore还大这么多,那么secondary region将进行更新store file (refresher)。
</description>
</property>

<property>
<name>hbase.region.replica.wait.for.primary.flush</name>
<value>true</value>
<description>
是否等待检测一个全面主的刷新完成,然后开始在secondary上进行数据的服务。
</description>
</property>
客户端上面的配置更新:
<property>
<name>hbase.ipc.client.specificThreadForWriting</name>
<value>true</value>
<description>
是否开启中断RPC的线程。
</description>
</property>
<property>
<name>hbase.client.primaryCallTimeout.get</name>
<value>10000</value>
<description>
超过这个时间将并发发送请求给secondary replica,默认是10ms。
</description>
</property>
<property>
<name>hbase.client.primaryCallTimeout.multiget</name>
<value>10000</value>
<description>
也是类似上述的时间限制,但是对于multget操作而言。
</description>
</property>
<property>
<name>hbase.client.replicaCallTimeout.scan</name>
<value>1000000</value>
<description>
同样上述操作,但是默认的时间是1s;
</description>
</property>
<property>
<name>hbase.meta.replicas.use</name>
<value>true</value>
<description>
是否使用meta表的replica;
</description>
</property>
新建一张具有region replica 的表:shell命令:
create 'test', 'info', {REGION_REPLICATION => 3}
java的api操作:
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(“test”));
htd.setRegionReplication(3);
...
admin.createTable(htd);
读取数据:shell命令:
hbase(main):001:0> get 'test','row', {CONSISTENCY => "TIMELINE"}
java的api操作:
Get get = new Get(row);
get.setConsistency(Consistency.TIMELINE);
...
Result result = table.get(get);
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
1.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。

Accordion:HBase一种内存压缩算法

hbasegroup 发表了文章 • 0 个评论 • 286 次浏览 • 2018-05-07 12:26 • 来自相关话题

现如今,人们对基于HBase的产品的读写速度要求越来越高。在理想情况下,人们希望HBase 可以在保证其可靠的持久存储的前提下能并拥有内存数据读写的速度。为此,在HBase2.0中引入Accordion算法。
Hbase RegionServer 负责将数据划分到多个Region中。RegionServer 内部(垂直)的可伸缩性能对于最终用户体验以及整个系统的利用率至关重要。Accordion 算法通过提高对RAM利用来提升RegionServer扩展性。这样就使得内存中可以存放更多数据,从而降低了对磁盘的读取频率(即降低了HBase中磁盘占用和写入方法,更多的读写RAM,降低了对于磁盘的IO访问)。在HBase2.0之前,这些指标是不能同时满足的,并且相互限制,在引入Accordion之后,这一状况得到了改善。
According算法来源于HBase核心架构LSM算法。在HBase Region 中,数据是按照key-value形式映射为可查找的存放,其中put进来的新数据以及一些topmost(靠前)数据存放在内存中(MemStore),其余的为不变的HDFS文件,即HFile。当MemStore写满时,数据被flush到硬盘里,生成新的HFile文件。HBase采用多版本并发控制,MemStore将所有修改后的数据存储为独立版本。一条数据的多个版本可能同时存储在MemStore和HFile中。当读取一条多版本数据时,根据key从Hbas扫描BlockCache中的HFile获取最新的版本数据。为了降低对磁盘的访问频率,HFiles在后台合(即压缩过程,删除多余的cells,创建更大的文件)。
LSM通过将随机读写转换为顺序读写,从而提高了写入性能。之前的设计并未采用压缩内存数据,主要原因是在LSM树设计当初,RAM还是非常紧缺的资源,因此MemStore的容量很小。随着硬件不断提升,RegionServer管理的整个MemStore可能为数千兆字节,这就为HBase优化留下了大量空间。
According算法重新将LSM应用于MemStore,以便当数据仍在RAM中时可以消除冗余和其他开销。这样做可以减少flush到HDFS的频率,从而降低了写入放大和磁盘占用。 随着flush次数的减少,MemStore写入磁盘的频率会降低,进而提高HBase写入性能。磁盘上的数据较少也意味着对块缓存的压力较小,提高了读取的响应时间。最终,减少对磁盘写入也意味着在后台压缩次数降低,即读取和写入周期将缩短。总而言之,内存压缩算法的效果可以被看作是一个催化剂,它使整个系统的运行速度更快。
目前Accordion提供了两个级别的内存压缩:basic 级别和 eager 级别。前者适用于所有数据更新的优化,后者对于高数据流的应用非常有用,如生产-消费队列,购物车,共享计数器等。所有这些使用案例都会对rowkey进行频繁更新,生成多个冗余版本的数据,这些情况下Accordion算法将发挥其价值。但另一方面,eager 级压缩优化可能会增加计算开销(更多内存副本和垃圾收集),这可能会影响数据写入的响应时间。如果MemStore使用堆内MemStore-本地分配缓冲区(MSLAB),这会导致开销增大。所以建议不要将此配置与eager级压缩结合使用。
如何使用
内存压缩可以在全局和列族级别配置。目前支持三种级别配置:none(传统实现),basic和eager。
默认情况下,所有表都是basic内存压缩。此配置可以在hbase-site.xml中修改,如下所示:<property>
<name> hbase.hregion.compacting.memstore.type </name>
<value> <none|basic|eager> </value>
</property>也可在HBase shell中为每个列族进行单独配置,如下所示:create '<tablename>',{NAME =>'<cfname>',IN_MEMORY_COMPACTION =>' <NONE|BASIC|EAGER>' }性能提高
通过利用YCSB(Yahoo Cloud Service Benchmark)对HBase进行了全面测试。试验中采用数据集大小为100-200 GB,结果表明Accordion算法对于HBase性能有显著的提升。
Heavy-tailed (Zipf)分布:在测试负载中国,rowkey遵循大多数现实生活场景中出现的Zipf分布。在这种情况下,当100%的操作是写入操作时,Accordion实现写入放大率降低30%,写入吞吐量提高20%,GC降低22%。当50%的操作是读取时,tail读取延迟降低12%。
均匀分布:第二个测试中rowkey都均衡分布。当100%的操作是写入操作时,Accordion的写入放大率降低25%,写入吞吐量提高50%,GC降低36%。tail读取延迟不受影响(由于没有本地化)。
Accordion如何工作
High Level设计:
Accordion引入了MemStore的内部压缩(CompactingMemStore)实现方法。与默认的MemStore相比,Accordion将所有数据保存在一个整的数据结构中用segment来管理。最新的segment,称为active segment,是可变的,可用来接收Put操作,若active segment达到overflow条件(默认情况下32MB,MemStore的25%大小),它们将会被移到in-memory pipeline 中,并设为不可变segment,我们称这一过程为in-memory flush。Get操作通过扫描这些 segment和HFiles 取数据(后者操作通过块缓存进行访问,与平常访问HBase一样)。
CompactingMemStore 可能会不时在后台合并多个不可变segment,从而形成更大的segment。因此,pipeline是“会呼吸的”(扩张和收缩),类似于手风琴波纹管,所以我们也将Accordion 译为手风琴。
当RegionServer 刷入一个或多个MemStore到磁盘释放内存时,它会刷入 CompactingMemStore中已经移入pipeline中的segment到磁盘。基本原理是延长MemStore有效管理内存的生命周期,以减少整体I/O。当flush发生时,pipeline中所有的segment 段将被移出合成一个快照, 通过合并和流式传输形成新的HFile。图1展示了CompactingMemStore与传统设计的结构。




图1. CompactingMemStore与DefaultMemStore
Segment结构:
与默认的MemStore类似,CompactingMemStore在单元存储之上维护一个索引,这样可以通过key快速搜索。两者不同的是,MemStore索引实现是通过Java skiplist (ConcurrentSkipListMap--一种动态但奢侈的数据结构)管理大量小对象。CompactingMemStore 则在不可变的segment 索引之上实现了高效且节省空间的扁平化布局。这种优化可以帮助所有压缩策略减少RAM开销,甚至可以使数据几乎不存在冗余。当将一个Segment加入pipeline中,CompactingMemStore 就将其索引序列化为一个名为CellArrayMap 的有序数组,该数组可以快速进行二进制搜索。
CellArrayMap既支持从Java堆内直接分配单元,也支持MSLAB的自定义分配(堆内或堆外),实现差异通过被索引引用的KeyValue对象抽象出来(图2)。CellArrayMap本身始终分配在堆内。




图2.具有扁平CellArrayMap索引和MSLAB单元存储的不可变Segment
压缩算法:
内存中压缩算法在pipeline中的Segment上维护了一个单一的扁平化索引。这样的设计节省了存储空间,尤其是当数据项很小时,可以及时将数据刷入磁盘。单个索引可使搜索操作在单一空间进行,因此缩短了tail读取延迟。
当一个active segment被刷新到内存时,它将排列到压缩pipeline中,并会立即触发一个异步合并调度任务。该调度任务将同时扫描pipeline中的所有Segment(类似于磁盘上的压缩)并将它们的索引合并为一个。basic和eager 压缩策略之间的差异体现在它们处理单元数据的方式上。basic压缩不会消除冗余数据版本以避免物理复制,它只是重新排列KeyValue对象的引用。eager压缩则相反,它会过滤出冗余数据,但这是以额外的计算和数据迁移为代价的。例如,在MSLAB存储器中,surviving 单元被复制到新创建的MSLAB中。
未来的压缩可能会在basic压缩策略和eager压缩策略之间实现自动选择。例如,该算法可能会在一段时间内尝试eager压缩,并根据所传递的值(如:数据被删除的比例)安排下一次压缩。这种方法可以减轻系统管理员的先验决定,并适应不断变化的访问模式。
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。 查看全部
现如今,人们对基于HBase的产品的读写速度要求越来越高。在理想情况下,人们希望HBase 可以在保证其可靠的持久存储的前提下能并拥有内存数据读写的速度。为此,在HBase2.0中引入Accordion算法。
Hbase RegionServer 负责将数据划分到多个Region中。RegionServer 内部(垂直)的可伸缩性能对于最终用户体验以及整个系统的利用率至关重要。Accordion 算法通过提高对RAM利用来提升RegionServer扩展性。这样就使得内存中可以存放更多数据,从而降低了对磁盘的读取频率(即降低了HBase中磁盘占用和写入方法,更多的读写RAM,降低了对于磁盘的IO访问)。在HBase2.0之前,这些指标是不能同时满足的,并且相互限制,在引入Accordion之后,这一状况得到了改善。
According算法来源于HBase核心架构LSM算法。在HBase Region 中,数据是按照key-value形式映射为可查找的存放,其中put进来的新数据以及一些topmost(靠前)数据存放在内存中(MemStore),其余的为不变的HDFS文件,即HFile。当MemStore写满时,数据被flush到硬盘里,生成新的HFile文件。HBase采用多版本并发控制,MemStore将所有修改后的数据存储为独立版本。一条数据的多个版本可能同时存储在MemStore和HFile中。当读取一条多版本数据时,根据key从Hbas扫描BlockCache中的HFile获取最新的版本数据。为了降低对磁盘的访问频率,HFiles在后台合(即压缩过程,删除多余的cells,创建更大的文件)。
LSM通过将随机读写转换为顺序读写,从而提高了写入性能。之前的设计并未采用压缩内存数据,主要原因是在LSM树设计当初,RAM还是非常紧缺的资源,因此MemStore的容量很小。随着硬件不断提升,RegionServer管理的整个MemStore可能为数千兆字节,这就为HBase优化留下了大量空间。
According算法重新将LSM应用于MemStore,以便当数据仍在RAM中时可以消除冗余和其他开销。这样做可以减少flush到HDFS的频率,从而降低了写入放大和磁盘占用。 随着flush次数的减少,MemStore写入磁盘的频率会降低,进而提高HBase写入性能。磁盘上的数据较少也意味着对块缓存的压力较小,提高了读取的响应时间。最终,减少对磁盘写入也意味着在后台压缩次数降低,即读取和写入周期将缩短。总而言之,内存压缩算法的效果可以被看作是一个催化剂,它使整个系统的运行速度更快。
目前Accordion提供了两个级别的内存压缩:basic 级别和 eager 级别。前者适用于所有数据更新的优化,后者对于高数据流的应用非常有用,如生产-消费队列,购物车,共享计数器等。所有这些使用案例都会对rowkey进行频繁更新,生成多个冗余版本的数据,这些情况下Accordion算法将发挥其价值。但另一方面,eager 级压缩优化可能会增加计算开销(更多内存副本和垃圾收集),这可能会影响数据写入的响应时间。如果MemStore使用堆内MemStore-本地分配缓冲区(MSLAB),这会导致开销增大。所以建议不要将此配置与eager级压缩结合使用。
如何使用
内存压缩可以在全局和列族级别配置。目前支持三种级别配置:none(传统实现),basic和eager。
默认情况下,所有表都是basic内存压缩。此配置可以在hbase-site.xml中修改,如下所示:
<property>
<name> hbase.hregion.compacting.memstore.type </name>
<value> <none|basic|eager> </value>
</property>
也可在HBase shell中为每个列族进行单独配置,如下所示:
create '<tablename>',{NAME =>'<cfname>',IN_MEMORY_COMPACTION =>' <NONE|BASIC|EAGER>' }
性能提高
通过利用YCSB(Yahoo Cloud Service Benchmark)对HBase进行了全面测试。试验中采用数据集大小为100-200 GB,结果表明Accordion算法对于HBase性能有显著的提升。
Heavy-tailed (Zipf)分布:在测试负载中国,rowkey遵循大多数现实生活场景中出现的Zipf分布。在这种情况下,当100%的操作是写入操作时,Accordion实现写入放大率降低30%,写入吞吐量提高20%,GC降低22%。当50%的操作是读取时,tail读取延迟降低12%。
均匀分布:第二个测试中rowkey都均衡分布。当100%的操作是写入操作时,Accordion的写入放大率降低25%,写入吞吐量提高50%,GC降低36%。tail读取延迟不受影响(由于没有本地化)。
Accordion如何工作
High Level设计:
Accordion引入了MemStore的内部压缩(CompactingMemStore)实现方法。与默认的MemStore相比,Accordion将所有数据保存在一个整的数据结构中用segment来管理。最新的segment,称为active segment,是可变的,可用来接收Put操作,若active segment达到overflow条件(默认情况下32MB,MemStore的25%大小),它们将会被移到in-memory pipeline 中,并设为不可变segment,我们称这一过程为in-memory flush。Get操作通过扫描这些 segment和HFiles 取数据(后者操作通过块缓存进行访问,与平常访问HBase一样)。
CompactingMemStore 可能会不时在后台合并多个不可变segment,从而形成更大的segment。因此,pipeline是“会呼吸的”(扩张和收缩),类似于手风琴波纹管,所以我们也将Accordion 译为手风琴。
当RegionServer 刷入一个或多个MemStore到磁盘释放内存时,它会刷入 CompactingMemStore中已经移入pipeline中的segment到磁盘。基本原理是延长MemStore有效管理内存的生命周期,以减少整体I/O。当flush发生时,pipeline中所有的segment 段将被移出合成一个快照, 通过合并和流式传输形成新的HFile。图1展示了CompactingMemStore与传统设计的结构。
2.png

图1. CompactingMemStore与DefaultMemStore
Segment结构:
与默认的MemStore类似,CompactingMemStore在单元存储之上维护一个索引,这样可以通过key快速搜索。两者不同的是,MemStore索引实现是通过Java skiplist (ConcurrentSkipListMap--一种动态但奢侈的数据结构)管理大量小对象。CompactingMemStore 则在不可变的segment 索引之上实现了高效且节省空间的扁平化布局。这种优化可以帮助所有压缩策略减少RAM开销,甚至可以使数据几乎不存在冗余。当将一个Segment加入pipeline中,CompactingMemStore 就将其索引序列化为一个名为CellArrayMap 的有序数组,该数组可以快速进行二进制搜索。
CellArrayMap既支持从Java堆内直接分配单元,也支持MSLAB的自定义分配(堆内或堆外),实现差异通过被索引引用的KeyValue对象抽象出来(图2)。CellArrayMap本身始终分配在堆内。
3.png

图2.具有扁平CellArrayMap索引和MSLAB单元存储的不可变Segment
压缩算法:
内存中压缩算法在pipeline中的Segment上维护了一个单一的扁平化索引。这样的设计节省了存储空间,尤其是当数据项很小时,可以及时将数据刷入磁盘。单个索引可使搜索操作在单一空间进行,因此缩短了tail读取延迟。
当一个active segment被刷新到内存时,它将排列到压缩pipeline中,并会立即触发一个异步合并调度任务。该调度任务将同时扫描pipeline中的所有Segment(类似于磁盘上的压缩)并将它们的索引合并为一个。basic和eager 压缩策略之间的差异体现在它们处理单元数据的方式上。basic压缩不会消除冗余数据版本以避免物理复制,它只是重新排列KeyValue对象的引用。eager压缩则相反,它会过滤出冗余数据,但这是以额外的计算和数据迁移为代价的。例如,在MSLAB存储器中,surviving 单元被复制到新创建的MSLAB中。
未来的压缩可能会在basic压缩策略和eager压缩策略之间实现自动选择。例如,该算法可能会在一段时间内尝试eager压缩,并根据所传递的值(如:数据被删除的比例)安排下一次压缩。这种方法可以减轻系统管理员的先验决定,并适应不断变化的访问模式。
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
1.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。

HBase运维基础——元数据逆向修复原理

hbasegroup 发表了文章 • 0 个评论 • 337 次浏览 • 2018-05-07 12:16 • 来自相关话题

背景
鉴于上次一篇文章——“云HBase小组成功抢救某公司自建HBase集群,挽救30+T数据”的读者反馈,对HBase的逆向工程比较感兴趣,并咨询如何使用相应工具进行运维等等。总的来说,就是想更深层理解HBase运维原理,提高运维HBase生产环境的能力,应对各种常见异常现象。不同的读者对hbase的了解程度不同,本文不打算着重编写一个工具怎么使用,而是从HBase的运维基础知识介绍开始讲解。为了能帮助大部分读者提高HBase运维能力,后续会写个“HBase运维系列” 专题系列文章,欢迎大家关注社区公众号最新动态。
介绍
相信很多自建HBase的企业会经常碰到各种各样的hbase运维问题。比如使用HBase的时候,HBase写入一段时间后开始RegionServer节点开始挂掉,重启RegionServer发现启动很慢,很多region出现RTI问题,导致读写某个region的业务hang住了 。还有一些人的HBase集群多次运维尝试后,直接HBase启动不了了,meta表上线就开始报错,导致最终业务不能正常上线运行等等系列问题。本文就HBase运维的原理基础开始入手,重点讲解数据完整性,以及元数据“逆向工程”恢复数据完整性的原理方法。开启后续一系列的HBase运维知识讲解。
HBase目录结构
本文就1.x版本进行讲解,不同版本大致相通。HBase在HDFS上会单独使用一个目录为HBase文件目录的根目录,通常为 “/hbase”。基于这个目录下,会有以下目录组织结构:/hbase/archive (1)
/hbase/corrupt (2)
/hbase/data/default/TestTable/.tabledesc/.tableinfo.0000000001 (3)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/info/
2e58b3e274ba4d889408b05e526d4b7b (4)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/
recovered.edits/340.seqid (5)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.regioninfo (6)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.tmp (7)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.splits (8)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.merges (9)
/hbase/data/hbase/acl (10)
/hbase/data/hbase/meta (11)
/hbase/hbase.id (12)
/hbase/hbase.version (13)
/hbase/MasterProcWALs (14)
/hbase/oldWALs (15)
/hbase/.tmp (16)
/hbase/.trashtables/data (17)
/hbase/WALs/tins-donot-rm-test-hb1-004.hbase.9b78df04-b.rds.aliyuncs.com,16020,1523502350378/tins-donot-rm-test-hb1-004.hbase.9b78df04-b.rds.aliyuncs.com%2C16020%2C1523502350378.default.1524538284034 (18)(1) 进行snapshot或者升级的时候使用到的归档目录。compaction删除hfile的时  候,也会把就的hfile归档到这里等。
(2) splitlog的corrupt目录,以及corrupt hfile的目录。
(3) 表的基本属性信息元文件tableinfo。
(4) 对应表下的hfile数据文件。
(5) 当splitlog发生时,一个RS的wal会按照region级别split WALs写到对应目录下的的recovered.edits目录上,使得此region再次被open的时候,回放这些recovered.edits 日志。
(6) regioninfo文件。
(7) compaction等的临时tmp目录。
(8) split时临时目录,如果上次region的split没有完成被中断了,这个region再open的时候会自动清理这个目录,一般不需要人工干预。
(9) merges时的临时目录,和split一样,如果没有正常完成的时候被中断了,那么他会在下次被open的时候自动清理。一般也不需要人工干预。
(10) acl 开启HBase权限控制时的权限记录系统表。
(11) meta 元数据表,记录region相关信息。
(12) hbase.id 集群启动初始化的时候,创建的集群唯一id。可以重新fix生成。
(13) hbase.version hbase 软件版本文件,代码静态版本,现在都是8。
(14) master执行过程程序的状态保存,用于中断恢复执行使用。
(15) oldWALs 历史wal,即wal记录的数据已经确认持久化了,那么这些wal就会被移到这里。splitlog完成的那些就日志,也会被放到这里。
(16) tmp 临时辅助目录,比如写一个hbase.id文件,在这里写成功后,rename到 /hbase/hbase.id。
(17) /hbase/.trashtables/data 当truncate table或者delete table的时候,这些数据会临时放在这里,默认1小时内被清。
(18) 记录着一台RegionServer上的WAL日志文件。可以看到它是regionserver名字是有时间的,即下一次启动时RS的wal目录就会使用新的目录结构存放wal,这个旧的RS wal 目录就会被splitlog过程拆分回放。
HBase涉及的主要文件及用途
HDFS静态文件,HDFS上的HBase 数据完整性
1. hfile文件:数据文件,目前最高版本也是默认常用版本为 3。 hfile文件结构细节可以参考官网http://hbase.apache.org/book.html#_hfile_format_2。我们这里逆向生成元数据主要使用到了HFile fileinfo的firstkey、lastkey信息。
2. hfilelink文件: 在hbase snapshot时用到, migration upgrade 也会使用到。很少碰到这类文件的运维问题,这里不作过多介绍。
3. reference文件:用来指定half hfile,一个region有reference时,这个region不能split。split/merge会创建这个。进行compaction后生成新的hfile后,会把这个reference删除。hfile的reference文件名格式一般是 hfile.parentEncRegion。如:/hbase/data/default/table/region-one/family/hfilename。其region-two有reference hfile文件名格式为:/hbase/data/default/table/region-two/family/hfile.region-one 通常无效引用就是 region-one的hfile不存在了,那么这个引用就会失效。他的修复方法一般是把reference无效的引用移除。
4. ".regioninfo" 文件,保存着 endkey/offline标志/regionid/regionName/split标志/startkey/tablename等
5. tableinfo文件这类文件保存着 tableName/table属性信息/table级别config信息/family信息。其中family信息保存着 famliyName/famiy属性/famliy级别config信息等。
通常,table属性有:REGION_MEMSTORE_REPLICATION,PRIORITY,IS_ROOT_KEY等,一般这些属性默认也是根据配置的一样。family属性有:BLOCKSIZE,TTL,REPLICATION_SCOPE等,一般属性是根据配置使用默认的。
6. hbase:meta表数据内容格式
regionname, info:regioninfo, regioninfo的encodeValue值
regionname, info:seqnumDuringOpen, 序列号
regionname, info:server, region所在的server名
regionname, info:serverstartcode, regionserver 启动的timestamp
元数据逆向生成原理
上述介绍的数据文件中,HBase的主要的元数据主要由meta表、tableinfo、regioninfo构成。这里的逆向生成元数据指的是,根据数据hfile数据文件,反向生成regioninfo/tableinfo/meta表的过程。
1. 逆向生成tableinfo文件
case1. 通过从master进程内存中的tabledescritor cache 完整恢复tableinfo文件,此时恢复的tableinfo是完整的,和之前的完全一样。
case2. 当cache中没有加载过此表的tableinfo时,修复过程只能从表的目录结构list所有familyNames 来恢复tableinfo,这个时候只能得到的是列簇的名字,恢复tableinfo文件内容中,除了表名、列簇名一致,其他的属性均采用默认值。这个时候如果运维人员知道有什么属性是自定义进去的,那么就需要要手动再次添加进去。
2.  逆向生成regioninfo文件
hfile 中的fileinfo读取firstkey/lastkey 排好序,得到region下所有hfile的最大rowkey和最小rowkey,并根据tableinfo中的表名 完整恢复  regioninfo文件。主要这里只能恢复 表明/startkey/endkey,  其他属性如:offline标志,regionName,split标志,hashcode等均使用代码生成或者配置的默认值。
3. 逆向填充meta表行
regioninfo文件序列化,填入meta表 info:regioninfo 列,并同时写入默认的server,等它被再次open的时候,重新分配region到实际的regionserver上,并更新这里的数据行。
逆向工程除了上面的直接文件、数据内容修复外,还涉及到数据的完整性其他方面修复。一个表示由无穷小的rowkey到无穷大的rowkey范围组成,还可能会发生的问题如:region空洞、region重叠现象,如:




如果有region空洞的时候,就会使用他们的空洞边界作为startkey/endkey,再修复创建一个region目录及目录下的regioninfo文件。如果是region重叠,则会把重叠的region进行合并,取所有region的最大最小rowkey作为merge后新region的最大最小rowkey。
元数据工具修复
元数据的缺少或者完整性有问题,会影响系统运行,甚至集群直接不可用。最常见的如 meta表上线失败,region 上线open失败等。这里介绍两个工具,工具一: hbase hbck 在线修复完整性修复元数据信息,工具二:OfflineMetaRepair 离线重建 hbase:meta 元数据表。
在线hbck修复:
前提:HDFS fsck 确保 hbase跟目录下文件没有损坏丢失,如果有,则先进行corrupt block 移除。
步骤1. hbase hbck 检查输出所以ERROR信息,每个ERROR都会说明错误信息。
步骤2. hbase hbck -fixTableOrphones 先修复tableinfo缺失问题,根据内存cache或者hdfs table 目录结构,重新生成tableinfo文件。
步骤3. hbase hbck -fixHdfsOrphones 修复regioninfo缺失问题,根据region目录下的hfile重新生成regioninfo文件
步骤4. hbase hbck -fixHdfsOverlaps 修复region重叠问题,merge重叠的region为一个region目录,并从新生成一个regioninfo
步骤5. hbase hbck -fixHdfsHoles 修复region缺失,利用缺失的rowkey范围边界,生成新的region目录以及regioninfo填补这个空洞。
步骤6. hbase hbck -fixMeta 修复meta表信息,利用regioninfo信息,重新生成对应meta row填写到meta表中,并为其填写默认的分配regionserver
步骤7. hbase hbck -fixAssignment 把这些offline的region触发上线,当region开始重新open 上线的时候,会被重新分配到真实的RegionServer上 , 并更新meta表上对应的行信息。
离线OfflineMetaRepair重建:
前提:HDFS fsck 确保 hbase跟目录下文件没有损坏丢失,如果有,则先进行corrupt block 移除
步骤: 执行 hbase org.apache.hadoop.hbase.util.hbck.OfflineMetaRepair -fix
最后,两个工具使用说明都比较详细,经过上面的基础介绍,相信都会看的懂的。这里不对工具再细致说明,工具的说明可以参考官网或者工具提示。题外话,有些开源组件设计的时候,向hbase元数据文件写入一些特有的信息,但是并没有修改到hbase工具的修复工具,或者它自己没有维护修复工具,如果这类文件损坏、丢失了,那么相应的组件就会运行不正常。使用这类组件的用户,应该不仅记录好你的表的基本结构,还要记录表的属性配置等,当发生修复运维行为的时候,主要再次核对确认。
结束语
本文介绍了运维hbase基础原理中的数据完整性以及逆向元数据修复原理,并举例介绍两个逆向修复元数据的工具和实用执行步骤。后续会出系列文章,说明更多hbase运维基础、运作原理等,希望对大家的运维和使用HBase有所帮助。欢迎更多意见和HBase技术交流。
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。 查看全部
背景
鉴于上次一篇文章——“云HBase小组成功抢救某公司自建HBase集群,挽救30+T数据”的读者反馈,对HBase的逆向工程比较感兴趣,并咨询如何使用相应工具进行运维等等。总的来说,就是想更深层理解HBase运维原理,提高运维HBase生产环境的能力,应对各种常见异常现象。不同的读者对hbase的了解程度不同,本文不打算着重编写一个工具怎么使用,而是从HBase的运维基础知识介绍开始讲解。为了能帮助大部分读者提高HBase运维能力,后续会写个“HBase运维系列” 专题系列文章,欢迎大家关注社区公众号最新动态。
介绍
相信很多自建HBase的企业会经常碰到各种各样的hbase运维问题。比如使用HBase的时候,HBase写入一段时间后开始RegionServer节点开始挂掉,重启RegionServer发现启动很慢,很多region出现RTI问题,导致读写某个region的业务hang住了 。还有一些人的HBase集群多次运维尝试后,直接HBase启动不了了,meta表上线就开始报错,导致最终业务不能正常上线运行等等系列问题。本文就HBase运维的原理基础开始入手,重点讲解数据完整性,以及元数据“逆向工程”恢复数据完整性的原理方法。开启后续一系列的HBase运维知识讲解。
HBase目录结构
本文就1.x版本进行讲解,不同版本大致相通。HBase在HDFS上会单独使用一个目录为HBase文件目录的根目录,通常为 “/hbase”。基于这个目录下,会有以下目录组织结构:
/hbase/archive (1)
/hbase/corrupt (2)
/hbase/data/default/TestTable/.tabledesc/.tableinfo.0000000001 (3)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/info/
2e58b3e274ba4d889408b05e526d4b7b (4)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/
recovered.edits/340.seqid (5)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.regioninfo (6)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.tmp (7)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.splits (8)
/hbase/data/default/TestTable/fc06f27a6c5bc2ff57ea38018b4dd399/.merges (9)
/hbase/data/hbase/acl (10)
/hbase/data/hbase/meta (11)
/hbase/hbase.id (12)
/hbase/hbase.version (13)
/hbase/MasterProcWALs (14)
/hbase/oldWALs (15)
/hbase/.tmp (16)
/hbase/.trashtables/data (17)
/hbase/WALs/tins-donot-rm-test-hb1-004.hbase.9b78df04-b.rds.aliyuncs.com,16020,1523502350378/tins-donot-rm-test-hb1-004.hbase.9b78df04-b.rds.aliyuncs.com%2C16020%2C1523502350378.default.1524538284034 (18)
(1) 进行snapshot或者升级的时候使用到的归档目录。compaction删除hfile的时  候,也会把就的hfile归档到这里等。
(2) splitlog的corrupt目录,以及corrupt hfile的目录。
(3) 表的基本属性信息元文件tableinfo。
(4) 对应表下的hfile数据文件。
(5) 当splitlog发生时,一个RS的wal会按照region级别split WALs写到对应目录下的的recovered.edits目录上,使得此region再次被open的时候,回放这些recovered.edits 日志。
(6) regioninfo文件。
(7) compaction等的临时tmp目录。
(8) split时临时目录,如果上次region的split没有完成被中断了,这个region再open的时候会自动清理这个目录,一般不需要人工干预。
(9) merges时的临时目录,和split一样,如果没有正常完成的时候被中断了,那么他会在下次被open的时候自动清理。一般也不需要人工干预。
(10) acl 开启HBase权限控制时的权限记录系统表。
(11) meta 元数据表,记录region相关信息。
(12) hbase.id 集群启动初始化的时候,创建的集群唯一id。可以重新fix生成。
(13) hbase.version hbase 软件版本文件,代码静态版本,现在都是8。
(14) master执行过程程序的状态保存,用于中断恢复执行使用。
(15) oldWALs 历史wal,即wal记录的数据已经确认持久化了,那么这些wal就会被移到这里。splitlog完成的那些就日志,也会被放到这里。
(16) tmp 临时辅助目录,比如写一个hbase.id文件,在这里写成功后,rename到 /hbase/hbase.id。
(17) /hbase/.trashtables/data 当truncate table或者delete table的时候,这些数据会临时放在这里,默认1小时内被清。
(18) 记录着一台RegionServer上的WAL日志文件。可以看到它是regionserver名字是有时间的,即下一次启动时RS的wal目录就会使用新的目录结构存放wal,这个旧的RS wal 目录就会被splitlog过程拆分回放。
HBase涉及的主要文件及用途
HDFS静态文件,HDFS上的HBase 数据完整性
1. hfile文件:数据文件,目前最高版本也是默认常用版本为 3。 hfile文件结构细节可以参考官网http://hbase.apache.org/book.html#_hfile_format_2。我们这里逆向生成元数据主要使用到了HFile fileinfo的firstkey、lastkey信息。
2. hfilelink文件: 在hbase snapshot时用到, migration upgrade 也会使用到。很少碰到这类文件的运维问题,这里不作过多介绍。
3. reference文件:用来指定half hfile,一个region有reference时,这个region不能split。split/merge会创建这个。进行compaction后生成新的hfile后,会把这个reference删除。hfile的reference文件名格式一般是 hfile.parentEncRegion。如:/hbase/data/default/table/region-one/family/hfilename。其region-two有reference hfile文件名格式为:/hbase/data/default/table/region-two/family/hfile.region-one 通常无效引用就是 region-one的hfile不存在了,那么这个引用就会失效。他的修复方法一般是把reference无效的引用移除。
4. ".regioninfo" 文件,保存着 endkey/offline标志/regionid/regionName/split标志/startkey/tablename等
5. tableinfo文件这类文件保存着 tableName/table属性信息/table级别config信息/family信息。其中family信息保存着 famliyName/famiy属性/famliy级别config信息等。
通常,table属性有:REGION_MEMSTORE_REPLICATION,PRIORITY,IS_ROOT_KEY等,一般这些属性默认也是根据配置的一样。family属性有:BLOCKSIZE,TTL,REPLICATION_SCOPE等,一般属性是根据配置使用默认的。
6. hbase:meta表数据内容格式
regionname, info:regioninfo, regioninfo的encodeValue值
regionname, info:seqnumDuringOpen, 序列号
regionname, info:server, region所在的server名
regionname, info:serverstartcode, regionserver 启动的timestamp
元数据逆向生成原理
上述介绍的数据文件中,HBase的主要的元数据主要由meta表、tableinfo、regioninfo构成。这里的逆向生成元数据指的是,根据数据hfile数据文件,反向生成regioninfo/tableinfo/meta表的过程。
1. 逆向生成tableinfo文件
case1. 通过从master进程内存中的tabledescritor cache 完整恢复tableinfo文件,此时恢复的tableinfo是完整的,和之前的完全一样。
case2. 当cache中没有加载过此表的tableinfo时,修复过程只能从表的目录结构list所有familyNames 来恢复tableinfo,这个时候只能得到的是列簇的名字,恢复tableinfo文件内容中,除了表名、列簇名一致,其他的属性均采用默认值。这个时候如果运维人员知道有什么属性是自定义进去的,那么就需要要手动再次添加进去。
2.  逆向生成regioninfo文件
hfile 中的fileinfo读取firstkey/lastkey 排好序,得到region下所有hfile的最大rowkey和最小rowkey,并根据tableinfo中的表名 完整恢复  regioninfo文件。主要这里只能恢复 表明/startkey/endkey,  其他属性如:offline标志,regionName,split标志,hashcode等均使用代码生成或者配置的默认值。
3. 逆向填充meta表行
regioninfo文件序列化,填入meta表 info:regioninfo 列,并同时写入默认的server,等它被再次open的时候,重新分配region到实际的regionserver上,并更新这里的数据行。
逆向工程除了上面的直接文件、数据内容修复外,还涉及到数据的完整性其他方面修复。一个表示由无穷小的rowkey到无穷大的rowkey范围组成,还可能会发生的问题如:region空洞、region重叠现象,如:
2.png

如果有region空洞的时候,就会使用他们的空洞边界作为startkey/endkey,再修复创建一个region目录及目录下的regioninfo文件。如果是region重叠,则会把重叠的region进行合并,取所有region的最大最小rowkey作为merge后新region的最大最小rowkey。
元数据工具修复
元数据的缺少或者完整性有问题,会影响系统运行,甚至集群直接不可用。最常见的如 meta表上线失败,region 上线open失败等。这里介绍两个工具,工具一: hbase hbck 在线修复完整性修复元数据信息,工具二:OfflineMetaRepair 离线重建 hbase:meta 元数据表。
在线hbck修复:
前提:HDFS fsck 确保 hbase跟目录下文件没有损坏丢失,如果有,则先进行corrupt block 移除。
步骤1. hbase hbck 检查输出所以ERROR信息,每个ERROR都会说明错误信息。
步骤2. hbase hbck -fixTableOrphones 先修复tableinfo缺失问题,根据内存cache或者hdfs table 目录结构,重新生成tableinfo文件。
步骤3. hbase hbck -fixHdfsOrphones 修复regioninfo缺失问题,根据region目录下的hfile重新生成regioninfo文件
步骤4. hbase hbck -fixHdfsOverlaps 修复region重叠问题,merge重叠的region为一个region目录,并从新生成一个regioninfo
步骤5. hbase hbck -fixHdfsHoles 修复region缺失,利用缺失的rowkey范围边界,生成新的region目录以及regioninfo填补这个空洞。
步骤6. hbase hbck -fixMeta 修复meta表信息,利用regioninfo信息,重新生成对应meta row填写到meta表中,并为其填写默认的分配regionserver
步骤7. hbase hbck -fixAssignment 把这些offline的region触发上线,当region开始重新open 上线的时候,会被重新分配到真实的RegionServer上 , 并更新meta表上对应的行信息。
离线OfflineMetaRepair重建:
前提:HDFS fsck 确保 hbase跟目录下文件没有损坏丢失,如果有,则先进行corrupt block 移除
步骤: 执行 hbase org.apache.hadoop.hbase.util.hbck.OfflineMetaRepair -fix
最后,两个工具使用说明都比较详细,经过上面的基础介绍,相信都会看的懂的。这里不对工具再细致说明,工具的说明可以参考官网或者工具提示。题外话,有些开源组件设计的时候,向hbase元数据文件写入一些特有的信息,但是并没有修改到hbase工具的修复工具,或者它自己没有维护修复工具,如果这类文件损坏、丢失了,那么相应的组件就会运行不正常。使用这类组件的用户,应该不仅记录好你的表的基本结构,还要记录表的属性配置等,当发生修复运维行为的时候,主要再次核对确认。
结束语
本文介绍了运维hbase基础原理中的数据完整性以及逆向元数据修复原理,并举例介绍两个逆向修复元数据的工具和实用执行步骤。后续会出系列文章,说明更多hbase运维基础、运作原理等,希望对大家的运维和使用HBase有所帮助。欢迎更多意见和HBase技术交流。
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
1.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。

期待已久的Apache HBase2.0已经正式发布

hbasegroup 发表了文章 • 0 个评论 • 360 次浏览 • 2018-05-06 20:29 • 来自相关话题

激动
HBase2.0 啥时候发布?好奇宝宝也是期待了很久,曾几何时都把stack问“烦”了,就在2018年4月30日中午,期待已久的HBase 2.0发布啦!你是不是也很迫不及待想了解它?这次,作为一枚HBase搬运工,已经为你准备好了一大波 HBase 2.0.0导读材料,拿走不谢~北京时间2018年4月30日(星期一) 中午12:24,HBase的“掌门人”Michael Stack 在Announce Mail List中宣布了HBase 2.0.0 版本正式Release,大家可以开始下载使用了。
膜拜
拜读stack大神announce email原文,激动人心的时刻:The HBase team is happy to announce the immediate availability of Apache HBase 2.0.0. Apache HBase™ is the Hadoop database, a distributed, scalable, big data store. To learn more about HBase, see https://hbase.apache.org/. HBase 2.0.0 is our second major release, the first release off the HBase 2.0 line. Please review 'Upgrading from 1.x to 2.x' in the bundled HBase 2.0.0 Reference Guide before installing or upgrading for a list of notable incompatibilities, major changes, and features including a new Region assignment manager ("AMv2"), a means for configuring the read and/or write path to run off-heap, and an optional In-Memory Compaction ("IMC", A.K.A "Accordion") facility. According to our adopted Semantic Versioning guidelines[2], we allowed ourselves make breaking changes in this major version release. For example, Coprocessors will need to be recast to fit more constrained APIs and rolling upgrade of an hbase-1.x install to hbase-2.x without downtime is (currently) not possible. That said, a bunch of effort has been expended mitigating the differences; a hbase-1.x client can perform DML against an hbase-2 cluster. A bundled compatibility report showing difference from 1.2.6 may be of help [3]. For the complete list of fixes and improvements, see the included `CHANGES.md` (or online at [1]) and `RELEASENOTES.md`. ......邮件简述了HBase 2.0.0 有新版Assignment Manager V2,offhead read/write, in-memory compaction等。你是不是也很好奇,HBase 2.0 到底还有有哪些features?https://s.apache.org/hbase-2.0.0-JIRA-changes 上显示了HBase2.0.0相关的issue多达4551个issue, 这么多改动,还有哪些features值得关注一下呢?
了解
下面整理了一些HBase2.0.0 主要的feature介绍,更多特性,可以参考上述链接:
1.A new Region assignment manager ("AMv2") ,HBASE-14350 , HBASE-14614
AssignmentManager V2基于Procedure V2实现,能够更快速的分配Region,维护的region状态机存储不再依赖于ZooKeeper。亲可以搭建一个hbase2.0 集群,查看ZK节点列表,已经找不到类似region-in-transistion节点了。
2.Offheaping of Read/Write Path  HBASE-11425,HBASE-15179
读写路径中,使用Offheap区的内存,大大减少GC压力,提高稳定性、降低99延时。细节见下面offheap扩展阅读材料。
3.In-Memory Compaction  HBASE-17343
重新设计了CompactingMemStore 替代 DefaultMemStore,数据会在内存中事先进行合并compact,有效提高后续常规compaction的效率。
4.NettyRpcServer  HBASE-17263  
其实并不新鲜,早在1.x 淘宝就有使用,现在2.0 开始默认使用NettyRpcServer 。使用Netty替代HBase原生的RPC server,大大提升了HBaseRPC的吞吐能力,降低了延迟。
5.Async Client HBASE-16833 HBASE-15921
Client不在是原来同步等待,而是利用异步RPC机制,大大提高Client端请求并发度,有效提高资源利用率,扩大吞吐。
6. Support for MOB (Medium-Sized Objects)  HBASE-11339
MOB特性使得HBase支持存储小于10MB 的中等媒体对象数据,相比原来直接存储大对象插入hbase,其读写效率更高;Mob数据存储还是以hfile格式存储,兼容HBase现有特性,如snapshot、bulkload、replication等。MOB数据文件有独立的compaction和expire clean机制,稳定性更可控。
研究
还不过瘾?下面还真为热爱专研的砖友们网罗了一些hbase2.0特性详细的扩展阅读!都是大神执笔的干货:
1.  hbase2.0 in-memory compaction
2.  HBase 2.0 read replicas 功能介绍
3.  基于HBase2.0上的备份恢复
4.  HBase 2.0 offheap write
5.  HBase 2.0 offheap read
https://issues.apache.org/jira/browse/HBASE-11425
https://blogs.apache.org/hbase/search?q=offheap
6.  HBase 2.0 MOB 设计文档
7.  HBase 2.0 MOB 使用手册
8.  HBase 2.x Backup/Restore
9.  HBase 2.0 release issue
10. HBase 2.0 NettyRpcServer
11. HBase 2.0 In-memory compaction
12. HBase 2.0 AMv2
https://docs.google.com/docume ... /edit
https://docs.google.com/docume ... oycwj
https://docs.google.com/docume ... aring
13. HBase 2.0 ProcedureV2
官方下载&指南
HBase 2.0.0 安装包下载地址:
http://www.apache.org/dyn/closer.lua/hbase/2.0.0/ 
官方阅读:
1. https://s.apache.org/hbase-2.0.0-JIRA-changes  所有hbase2.0相关的jira,subtask 
2. http://hbase.apache.org/2.0/bo ... ost10  最新的HBase 2.0.0官方指南
3.http://apache.mirrors.tds.net/ ... .html  整理了v1.2.6和v2.0.0版本之间的兼容性报告
其他更多优化特性,不一一列举,后续可能会由HBase技术社区为你带来更多HBase 2.0细节上的特性优化文章分享。
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。




大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。 查看全部
激动
HBase2.0 啥时候发布?好奇宝宝也是期待了很久,曾几何时都把stack问“烦”了,就在2018年4月30日中午,期待已久的HBase 2.0发布啦!你是不是也很迫不及待想了解它?这次,作为一枚HBase搬运工,已经为你准备好了一大波 HBase 2.0.0导读材料,拿走不谢~北京时间2018年4月30日(星期一) 中午12:24,HBase的“掌门人”Michael Stack 在Announce Mail List中宣布了HBase 2.0.0 版本正式Release,大家可以开始下载使用了。
膜拜
拜读stack大神announce email原文,激动人心的时刻:
The HBase team is happy to announce the immediate availability of Apache HBase 2.0.0. Apache HBase™ is the Hadoop database, a distributed, scalable, big data store. To learn more about HBase, see https://hbase.apache.org/. HBase 2.0.0 is our second major release, the first release off the HBase 2.0 line. Please review 'Upgrading from 1.x to 2.x' in the bundled HBase 2.0.0 Reference Guide before installing or upgrading for a list of notable incompatibilities, major changes, and features including a new Region assignment manager ("AMv2"), a means for configuring the read and/or write path to run off-heap, and an optional In-Memory Compaction ("IMC", A.K.A "Accordion") facility. According to our adopted Semantic Versioning guidelines[2], we allowed ourselves make breaking changes in this major version release. For example, Coprocessors will need to be recast to fit more constrained APIs and rolling upgrade of an hbase-1.x install to hbase-2.x without downtime is (currently) not possible. That said, a bunch of effort has been expended mitigating the differences; a hbase-1.x client can perform DML against an hbase-2 cluster. A bundled compatibility report showing difference from 1.2.6 may be of help [3]. For the complete list of fixes and improvements, see the included `CHANGES.md` (or online at [1]) and `RELEASENOTES.md`. ......
邮件简述了HBase 2.0.0 有新版Assignment Manager V2,offhead read/write, in-memory compaction等。你是不是也很好奇,HBase 2.0 到底还有有哪些features?https://s.apache.org/hbase-2.0.0-JIRA-changes 上显示了HBase2.0.0相关的issue多达4551个issue, 这么多改动,还有哪些features值得关注一下呢?
了解
下面整理了一些HBase2.0.0 主要的feature介绍,更多特性,可以参考上述链接:
1.A new Region assignment manager ("AMv2") ,HBASE-14350 , HBASE-14614
AssignmentManager V2基于Procedure V2实现,能够更快速的分配Region,维护的region状态机存储不再依赖于ZooKeeper。亲可以搭建一个hbase2.0 集群,查看ZK节点列表,已经找不到类似region-in-transistion节点了。
2.Offheaping of Read/Write Path  HBASE-11425,HBASE-15179
读写路径中,使用Offheap区的内存,大大减少GC压力,提高稳定性、降低99延时。细节见下面offheap扩展阅读材料。
3.In-Memory Compaction  HBASE-17343
重新设计了CompactingMemStore 替代 DefaultMemStore,数据会在内存中事先进行合并compact,有效提高后续常规compaction的效率。
4.NettyRpcServer  HBASE-17263  
其实并不新鲜,早在1.x 淘宝就有使用,现在2.0 开始默认使用NettyRpcServer 。使用Netty替代HBase原生的RPC server,大大提升了HBaseRPC的吞吐能力,降低了延迟。
5.Async Client HBASE-16833 HBASE-15921
Client不在是原来同步等待,而是利用异步RPC机制,大大提高Client端请求并发度,有效提高资源利用率,扩大吞吐。
6. Support for MOB (Medium-Sized Objects)  HBASE-11339
MOB特性使得HBase支持存储小于10MB 的中等媒体对象数据,相比原来直接存储大对象插入hbase,其读写效率更高;Mob数据存储还是以hfile格式存储,兼容HBase现有特性,如snapshot、bulkload、replication等。MOB数据文件有独立的compaction和expire clean机制,稳定性更可控。
研究
还不过瘾?下面还真为热爱专研的砖友们网罗了一些hbase2.0特性详细的扩展阅读!都是大神执笔的干货:
1.  hbase2.0 in-memory compaction
2.  HBase 2.0 read replicas 功能介绍
3.  基于HBase2.0上的备份恢复
4.  HBase 2.0 offheap write
5.  HBase 2.0 offheap read
https://issues.apache.org/jira/browse/HBASE-11425
https://blogs.apache.org/hbase/search?q=offheap
6.  HBase 2.0 MOB 设计文档
7.  HBase 2.0 MOB 使用手册
8.  HBase 2.x Backup/Restore
9.  HBase 2.0 release issue
10. HBase 2.0 NettyRpcServer
11. HBase 2.0 In-memory compaction
12. HBase 2.0 AMv2
https://docs.google.com/docume ... /edit
https://docs.google.com/docume ... oycwj
https://docs.google.com/docume ... aring
13. HBase 2.0 ProcedureV2
官方下载&指南
HBase 2.0.0 安装包下载地址:
http://www.apache.org/dyn/closer.lua/hbase/2.0.0/ 
官方阅读:
1. https://s.apache.org/hbase-2.0.0-JIRA-changes  所有hbase2.0相关的jira,subtask 
2. http://hbase.apache.org/2.0/bo ... ost10  最新的HBase 2.0.0官方指南
3.http://apache.mirrors.tds.net/ ... .html  整理了v1.2.6和v2.0.0版本之间的兼容性报告
其他更多优化特性,不一一列举,后续可能会由HBase技术社区为你带来更多HBase 2.0细节上的特性优化文章分享。
结束语
大家在工作学习中遇到HBase技术问题发布在HBase技术社区论坛http://hbase.group ,欢迎大家在上面提问留言。想了解更多HBase技术请关注HBase社区公众号(微信号:hbasegroup),扫描下面二维码关注,也欢迎大家积极投稿。
9949390940b1325a1378b7dc82c960f3.jpg

大家可以添加社区人员微信(微信号:HackerUncle或者u7758258f),进HBase技术社区微信群交流HBase技术栈。

中国HBase技术社区微信公众号:
hbasegroup

欢迎加入HBase生态+Spark社区钉钉大群