hbaseregion

Posted ulysses_you

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hbaseregion相关的知识,希望对你有一定的参考价值。

前言

文章不含源码,只是一些官方资料的整理和个人理解

 

架构总览

 

 

这张图在大街小巷里都能看到,感觉是hbase架构中最详细最清晰的一张,稍微再补充几点。

1) Hlog是低版本hbase术语,现在称为WALs。

2) 1个region包含了多个store,1个store包含了1个colum family,这样就比较好理解

3) 1个store包含了多个storefile,1个sotrefile就是1个hfile文件

这在HDFS路径也能体现,大概长这样

table/region/column family/hfile

 

region

region就是一些连续的hfile集合,也就是说连续的hfile被存储在一个region目录下。

我们知道,hbase索引一个数据其实是通过遍历的方式,当然是经过优化的遍历,而region就起到了一个很大的作用。想象一下,如果你要在一堆文件中找到你要的内容,怎么样的文件结构才是更快。

·有序

假如你要找的文件有关键字a,那么如果所有文件是按关键字(hbase的rowkey)排序的,那么a就有迹可循,Hbase采用了lexicographic order(这个单词有点不想单词..)也就是字典排序(ASCII码),对每个rowkey从高位到地位排序。

·分块

Rowkey已经是排序的,但还是要遍历啊,万一有个rowkey是z开头的,不是要哭死。Hfile就出现了,一个hfile里有一段连续的rowkey,并且记录了所有rowkey的长度和整个hfile的rowkey是起始和终止。这样就方便了很多,遍历的时候只要看一个文件夹是否包含了该rowkey,而不用一个一个对比。(先忽略column family机制,bloom filter机制)

·进一步分块

但是hfile还是很多啊,要是把hfile容量扩大也不利用读。

最容易想到的就是把多个hfile统一管理,再做封装,这里就引申出了region。一些连续的hfile被一个region管理,region记录了rowkey的起始和终止等信息。这样遍历起来又快了很多。

 

region split

上面说的解决了遍历的性能问题,但是region也会变大,就像hfile会变大一样。这时候region split就出现了。

当region被认为需要split的时候(max size超过阈值),一系列操作就出现了。

 

1) region是否需要分割是否regionserver决定的,当需要的时候,通过zookeeper和master沟通一下

2) regionserver关闭该region,并且把memstore的相关数据flush到hfile。这时候有client来请求,则会抛出NotServingRegionException异常

3) 找到分割点,也就是midkey,查找流程是这样的。先找到该region中最大的一个hfile,然后找到这个hfile的midkey(在hfilev2版本以上,会在hile末记录midkey,否则需要找到data block数据/2的那个block的startkey作为midkey)

4) 准备子region的相关环境(路径啊,文件夹啊什么的,都是临时的),创建两个文件来指向父region(也就是待split的region)

5) 创建两个真正的子region(文件夹),并把那两个文件移过去

6) regionserver向hbase:meta表发起Put请求,把待分割的region设置为offline,并且增加子region的信息。在这过程中,客户端并不能真正看到子region(还不是独立的region),只是能知道有个父region在split。当put请求成功后,父region才会正真的split。(如果put请求失败了,那么由master分配新的regionserver来重新region split,在此之前会把上一次split失败的相关脏数据清除)

7) 打开子region,接收写操作。为之后无缝接入服务做准备

8) regionserver再向hbase:meta表添加相关信息。然后客户端再请求就能搜索到子region。当然由于region是新建的,所以之前的缓存都不可用。

9) regionserver通过zookeeper和master交互,让master知道有新region split好了。Master可以决定新region由哪个regionserver管理

10) 最后就是善后工作,由于新region实际上没有父region的数据,只有一些引用来指向父region。所以在子region compaction的时候,会重写这些数据。另外hbase的master还有一个GC task(不是jvm的GC),来定期轮询,查看是否还有引用父region,当没有的时候就删除父region

 

总结

整个流程虽然看上去很复杂,其实效率很高,region split的过程中是不可用的,但是这时间很短,因为不涉及大量的io,只有引用和交互。

master和regionserver之间的配合,master主要做协调,regionserver做实际的工作

 

Region compaction

其实用storefile compaction来表示更合适,compaction分为两种,compaction和major compaction。参考类`CompactionPolicy`,默认的实现是`ExploringCompactionPolicy`

 

Compaction

如果该列族下总hfile数量-正在合并的hfile数量 >= ` hbase.hstore.compaction.min`默认3,那么就会触发compaction,单次compaction的hfile数量上限是`hbase.hstore.compaction.max`默认10。compaction的定位是主要合并一些小的相邻的hfile,重写进一个新的hfile。重写的过程不包括数据的drop,filter,delete等移除操作,只是简单的把小文件合并成大文件。

 

Major Compaction

参考RatioBasedCompactionPolicy的实现,首先是计算major compaction的时间周期,默认周期是1周,通过配置`hbase.hregion.majorcompaction`。为了避免major compaction风暴(多个region同时major compaction导致hbase服务不可用),hbase还引用了时间偏差`hbase.hregion.majorcompaction.jitter`,默认是0.5,也就是说实际major compaction的时间是总周期上下浮动0.5个周期内的时间。如果需要合并hfiles中最小的文件修改时间戳比当前时间-合并周期小,那么视为可进行major compaction,但是如果只有一个hfile需要marjor compaction,那么hbase还会深入判断ttl和hfile的block本地化系数,从而获取最优解。

major compaction会把所有需要清除的数据都移除,最终合并成一个storefile。合并过程中服务还是可以使用,但是合并过程中会读取全量的数据,这样会大量的占用磁盘的IO,导致查询效率大幅下降,甚至不可用。

数据需要被移除一般有三种情况

1) 客户端显示的声明delete

2) 某些column family的version超过max version

3) 某些设置了TTL的column family

 

RegionServer和Region

官方建议一个RegionServer的Region数量控制在100个以内,但是这还受到RegionServer分配的内存大小,由于每个Region都有自己的memstore,而默认的memstore大小为128MB(hbase.hregion.memstore.flush.size),那么100个region直接就会使用10GB的内存

当全局MemStore的大小超过了该RegionServer内存的hbase.regionserver.global.memstore.upperLimit大小,默认40%的内存使用量。那么此时当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush顺序是MemStore大小的倒序,直到总体的MemStore使用量低于RegionServer的hbase.regionserver.global.memstore.lowerLimit,默认38%的内存使用量。

 

参考资料

//hbase官网推荐的region split 博客

https://hortonworks.com/blog/apache-hbase-region-splitting-and-merging/

 

以上是关于hbaseregion的主要内容,如果未能解决你的问题,请参考以下文章