8

大白话详解大数据HBase核心知识点,老刘真的很用心(2)

 3 years ago
source link: http://www.cnblogs.com/bigdatalaoliu/p/14053296.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

vqi6var.jpg!mobile

前言:老刘目前为明年校招而努力,写文章主要是想用大白话把自己复习的大数据知识点详细解释出来,拒绝资料上的生搬硬套,做到有自己的理解!

01 HBase知识点

RBFVbq7.png!mobile

第6点:HRegionServer架构

zeMj2q.jpg!mobile

为什么要了解HRegionServer的架构呢?因为HBase集群中数据的存储和HRegionServer有着非常大的关系,只有搞清楚了它的架构,才能理清楚数据存储的逻辑。

那就让老刘好好介绍下HRegionServer架构。

StoreFile

在HRegionServer架构图中,StoreFile是保存实际数据的物理文件,StoreFile是以HFile的形式存储在HDFS上,每个Store会有一个或多个StoreFile,并且数据在每个StoreFile中都是有序的。为什么是有序的,会在MEMStore中介绍。

对于HFile是什么,老刘目前只能理解为它是StoreFile存在HDFS上的存储格式,也就是说StoreFile是以HFile这种形式存储在HDFS上。

MemStore

它是写缓存的意思。由于HFile是要求数据是有序的,要按照存储在HDFS上的数据需要按照rowkey排序,所以数据先存储在MemStore中,排好序后,达到阈值后才会flush到StoreFile中,每次flush生成一个新的StoreFIle。

那MemStore是如何将数据排序的呢?

很多机构的教学资料都没讲,老刘查了很多资料后,老刘只有一个相对较浅的理解,实现MemStore模型的数据结构是SkipList跳表,跳表它可以实现高效的查询、插入、删除操作。因为跳表本质上是由有序链表构成的,很多KV数据库都会使用跳表实现有序数据集合。所以呢,数据传入MemStore后,会利用跳表实现这些数据的有序。

WAL

WAL,全称是Write Ahead Log,预先写日志的意思。由于数据要经MemStore排序后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失的,所以为了解决这个问题,数据会先写在一个叫做Write Ahead Log的文件中,然后再写入MemStore中。所以当系统出现故障的时候,数据就可以通过这个日志文件重建,避免数据丢失。

BlockCache

它是读缓存的意思。每次查询出来的数据会先缓存在BlockCache中,方便下次查询数据。

第7点:HBase读数据流程

em6BFzv.jpg!mobile

首先要说的是,在HBase中只有一张meta表(元数据表),此表只有一个region表,该region数据保存在一个HRegionServer上。

还记得HBase的第一篇文章说的ZooKeeper的作用吗,ZooKeeper里面保存了HBase的元数据meta。再想想我们要读取数据,是不是相当于去学校访问一个老师,是不是要先在校门口登记,搞清楚这个老师在学校哪个部门、哪个办公室之类的。

所以呢,HBase读数据流程如下:

1、HBase读取数据首先要与zk进行连接,从zk找到meta表的region位置,就是查找meta表存储在哪个HRegionServer,得到消息后,客户端就会立马与这个HRegionServer建立连接,然后读取meta表中的数据,这个meta表中的信息有:HBase集群有哪些表、每个表有哪些Region、都保存在哪些RegionServer上以及存储了所有用户表的Region信息。

2、我们根据要查询的namespace(命名空间,相当于关系型数据库的数据库名称)、表名和rowkey信息。找到写入数据对应的Region信息。

3、然后找到这个Region对应的RegionServer,然后发送请求。

4、现在就可以查找并定位到对应的Region了。

5、我们会先从MemStore中查找数据,如果没有,就会再从BlockCache上读取,如果BlockCache中也没有找到,那就会从最后的StoreFile中读取,从StoreFile中读取到数据之后,并不是直接把结果数据返回到客户端,而是把数据先写入到BlockCache中,目的是为了加快后续的查询;然后在返回结果给客户端。

第8点:HBase写数据流程

Y73uean.jpg!mobile

1、客户端首先会从zk找到meta表的region位置,然后读到meta表中的数据,meta表中存储了用户表的region信息。

2、根据我们根据要写入数据的namespace(命名空间,相当于关系型数据库的数据库名称)、表名和rowkey信息。找到写入数据对应的Region信息。

3、然后找到这个Region对应的RegionServer,然后发送请求。

4、现在就可以把数据顺序写入(追加)到WAL。

5、将数据写入对应的MemStore,数据会在MemStore进行排序。

6、达到MemStore的刷写时机后,将数据刷写到StoreHFile中。

但是大家好好想想,如果数据不停的写入,是不是会产生很多很多StoreFile?

在HBase集群中,针对产生的很多很多StoreFile,它会把它们合并为一个大的StoreFile(这是一个小合并),最终所有的StoreFile会进行一个大合并。但是在数据不断写入过程中,Region中的数据会越来越大,此时Region就会进行拆分(一分为二),拆分过程比较耗性能,就有了预分区。老刘大致说了下HBase中为什么会有flush和compact机制、Region拆分合并以及预分区,下面就详细讲讲这些知识点。

第9点:HBase中的flush、compact机制

Flush机制

maQnYvB.jpg!mobile

数据要刷写到磁盘,它是有很多刷写时机的,并不是想刷写就刷写的。

第一个是达到Memtore级别的限制,当Region中任意一个MemStore的大小达到了上限,默认是128M,就会触发MemStore刷新。这个上限的设置如下:

<property>
  <name>hbase.hregion.memstore.flush.size</name>
  <value>134217728</value>
</property>

第二个是达到Region级别的限制,当Region中所有的MemStore的大小总和达到了上限,默认是2*128M=256M,会触发MemStore刷新。这个上限的设置如下:

<property>
  <name>hbase.hregion.memstore.flush.size</name>
  <value>134217728</value>
</property>
<property>
  <name>hbase.hregion.memstore.block.multiplier</name>
  <value>2</value>
</property>

第三个是达到RegionServer级别限制,当一个RegionServer中所有MemStore的大小总和超过低水位阈值,RegionServer开始强制Flush;先Flush MemStore最大的Region,再执行次大的,依次执行;

如果写入速度大于flush写出的速度,最后导致总MemStore大小超过高水位阈值(默认为JVM内存的40%),此时RegionServer会阻塞更新并强制执行flush,直到总MemStore大小低于低水位阈值。这些阈值的设置如下:

<property>
  <name>hbase.regionserver.global.memstore.size.lower.limit</name>
  <value>0.95</value>
</property>
<property>
  <name>hbase.regionserver.global.memstore.size</name>
  <value>0.4</value>
</property>

第四个是当WAL文件的数量超过hbase.regionserver.max.logs,region会按照时间顺序依次进行刷写,直到WAL文件数量减小到hbase.regionserver.max.log以下(该属性名已经废弃,现无需手动设置,最大值为32)。

第五个是定期刷新MemStore,默认周期为1小时,确保MemStroe不会长时间没有持久化。为避免所有的MemStore在同一时间都进行flush导致的问题,定期的flush操作会有20000左右的随机延时。

Compact合并机制

为什么有Compact合并机制?

hbase为了防止小文件过多,以保证查询效率,hbase需要在必要的时候将这些小的store file合并成相对较大的store file,这个过程就称之为compaction。

在hbase中主要存在两种类型的compaction合并:

naM7juq.png!mobile

minor compaction 小合并

Mv6FNzu.jpg!mobile

它会将Store中多个HFile合并为一个HFile。在这个过程中它会选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile。

对于超过了TTL(生存时间)的数据、更新的数据、删除的数据仅仅只是做了标记。并没有进行物理删除,进行一次Minor Compaction的结果是产生数量上更少并且内存上更大的StoreFile。这种合并的触发频率很高。

minor compaction触发条件由以下几个参数共同决定:

<!--表示至少需要三个满足条件的store file时,minor compaction才会启动-->
<property>
  <name>hbase.hstore.compactionThreshold</name>
  <value>3</value>
</property>

<!--表示一次minor compaction中最多选取10个store file-->
<property>
  <name>hbase.hstore.compaction.max</name>
  <value>10</value>
</property>

<!--默认值为128m,
表示文件大小小于该值的store file 一定会加入到minor compaction的store file中
-->
<property>
  <name>hbase.hstore.compaction.min.size</name>
  <value>134217728</value>
</property>

<!--默认值为LONG.MAX_VALUE,
表示文件大小大于该值的store file 一定会被minor compaction排除-->
<property>
  <name>hbase.hstore.compaction.max.size</name>
  <value>9223372036854775807</value>
</property>

major compaction 大合并

IZFBjiB.jpg!mobile

将所有的StoreFile合并成一个StoreFile,在这个过程中还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。它的合并频率比较低,默认7天执行一次,并且性能的消耗是非常大的,一般建议生产关闭,在应用空闲时间手动触发。一般可以是手动控制进行合并,这样可以防止出现在业务高峰期。

major compaction触发时间条件(7天)

<!--默认值为7天进行一次大合并,-->
<property>
  <name>hbase.hregion.majorcompaction</name>
  <value>604800000</value>
</property>

手动触发

#使用major_compact命令
major_compact tableName

第10点:Region拆分

region中存储的是大量的rowkey数据,当region中的数据条数过多的时候,直接影响查询效率。当region过大的时候。hbase会拆分region,这也是Hbase的一个优点。

HBase的region split策略一共有以下几种,先说说3种。

1、ConstantSizeRegionSplitPolicy

它是0.94版本前默认切分策略。

当region的大小大于某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个region会等分为2个region。但是这种切分策略却有相当大的弊端:切分策略对于大表和小表没有明显的区分。阈值设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,这对业务来说并不是什么好事。如果设置较小则对小表友好,但一个大表就会在整个集群产生大量的region,这对于集群的管理、资源使用、failover来说都不是一件好事。

2、IncreasingToUpperBoundRegionSplitPolicy

它是0.94版本~2.0版本默认切分策略。

切分策略稍微有点复杂,总体看和ConstantSizeRegionSplitPolicy思路相同,一个region大小大于设置阈值就会触发切分。但是这个阈值并不像ConstantSizeRegionSplitPolicy是一个固定的值,而是会在一定条件下不断调整,调整规则和region所属表在当前regionserver上的region个数有关系。

3、SteppingSplitPolicy

它是2.0版本默认切分策略

这种切分策略的切分阈值又发生了变化,就是一般刚设计出来都会存在一些不合理的地方,随着慢慢的发展,设计师们逐渐完善。

相比之前的IncreasingToUpperBoundRegionSplitPolicy,它会简单一些,依然和待分裂region所属表在当前regionserver上的region个数有关系,如果region个数等于1,切分阈值为flush size * 2,否则为MaxRegionFileSize。这种切分策略对于大集群中的大表、小表会比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小表不会再产生大量的小region,而是适可而止。

还有几个不讲了,老刘快记不住了。

第11点:Region合并

什么时候需要Region合并?

比如有一张表在拆分后,一分为二,但是在使用过程中,对这两个表进行了数据的删除,数据量变小了,为了方便管理之类的,可以把他们合并。

又比如删除了大量的数据 ,这个时候每个Region都变得很小 ,存储多个Region就浪费了 ,这个时候可以把Region合并起来,进而可以减少一些Region服务器节点 。

总之,Region合并不是为了性能,而是为了方便维护管理。

第12点:HBase表的预分区

当一个table表刚被创建的时候,HBase会默认的分配一个region给这个table。这就相当于说,在这个时候,所有的读写请求都会访问到同一个regionServer的同一个region中,这个时候就达不到负载均衡的效果了,因为集群中的其他regionServer就可能会处于比较空闲的状态。出现了一人干活,其他人看戏的现象。

解决这个问题可以用预分区,在创建table表的时候就配置好,生成多个region。

预分区原理

每一个region都维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,就会把该数据交给这个region维护。如何手动指定预分区

方式一:

create 'person','info1','info2',SPLITS => ['1000','2000','3000','4000']

就会有如下这种效果:

6BFbAfy.png!mobile

方式二:

把分区规则创建于文件中

cd /kkb/install

vim split.txt

在里面添加这样的内容:

aaa
bbb
ccc
ddd

在执行这样的命令:

create 'student','info',SPLITS_FILE => '/kkb/install/split.txt'

就会得到这样的效果:

NRJNjmB.png!mobile

02 总结

好啦,大数据HBase的第二部分知识点就总结的差不多了,内容比较多,大家需要仔细理解,争取做到用自己的话把这些知识点讲述出来。

最后,如果觉得有哪里写的不好或者有错误的地方,可以联系公众号:努力的老刘,进行交流哦!希望能够对大数据开发感兴趣的同学有帮助,希望能够得到同学们的指导。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK