HBase的Compact参数设置及数据读写流程剖析-OLAP商业环境实战

版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。版权声明:禁止转载,欢迎学习。QQ邮箱地址:[email protected],如有任何商业交流,可随时联系。 https://blog.csdn.net/shenshouniu/article/details/83902291

1 前言

Hbase适合存储PB级别的海量数据,在PB级别的数据以及采用廉价PC存储的情况下,能在几十到百毫秒内返回数据。这与Hbase的极易扩展性息息相关。正因为Hbase良好的扩展性,才为海量数据的存储提供了便利。根据Google的Chang等人发表的论文

             Bigtable:A Distributed Storage System for Strctured Data

来设计的。总体架构如下:

2010年5月,Hbase从Hadoop子项目升级成Apache顶级项目。简而言之:HBase是一个通过大量廉价的机器解决海量数据的高速存储和读取的分布式数据库解决方案。一图概括如下所示:

1.1 HBase 如何基于LSM树做索引


顺序写只是把动作写到磁盘上了,只有compact后才是真正的数据。

2 HBase 读写数据过程

2.1 HBase 写数据过程

  • 先将数据写到WAL中;
  • WAL 存放在HDFS之上;
  • 每次Put、Delete操作的数据均追加到WAL末端;
  • 持久化到WAL之后,再写到MemStore中;
  • 两者写完返回ACK到客户端。

2.2 HBase 内存结构

MemStore 其实是一种内存结构,一个Column Family 对应一个MemStore

2.3 HBase 读数据过程 (0.96版本以前)

  • 第1步:client请求ZK获得-ROOT-所在的RegionServer地址

  • 第2步:client请求-ROOT-所在的RS地址,获取.META.表的地址,client会将-ROOT-的相关信息cache下来,以便下一次快速访问

  • 第3步:client请求 .META.表的RS地址,获取访问数据所在RegionServer的地址,client会将.META.的相关信息cache下来,以便下一次快速访问

    扫描二维码关注公众号,回复: 4128991 查看本文章
  • 第4步:client请求访问数据所在RegionServer的地址,获取对应的数据

2.4 HBase 读数据过程 (0.96版本以后)

  • 第1步:Client请求ZK获取.META.所在的RegionServer的地址。

  • 第2步:Client请求.META.所在的RegionServer获取访问数据所在的RegionServer地址,client会将.META.的相关信息cache下来,以便下一次快速访问。

  • 第3步:Client请求数据所在的RegionServer,获取所需要的数据。

2.5 HBase 去掉-ROOT-的原因

  • 其一:提高性能

  • 其二:2层结构已经足以满足集群的需求

3 HBase Compact 功能剖析

Compaction会从一个region的一个store中选择一些hfile文件进行合并。合并说来原理很简单,先从这些待合并的数据文件中读出KeyValues,再按照由小到大排列后写入一个新的文件中。之后,这个新生成的文件就会取代之前待合并的所有文件对外提供服务。HBase根据合并规模将Compaction分为了两类:MinorCompaction和MajorCompaction

  • Minor Compaction是指选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile,在这个过程中不会处理已经Deleted或Expired的Cell。一次Minor Compaction的结果是更少并且更大的StoreFile。

  • Major Compaction是指将所有的StoreFile合并成一个StoreFile,这个过程还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。另外,一般情况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此线上业务都会将关闭自动触发Major Compaction功能,改为手动在业务低峰期触发。

  • 下列三个条件可能会触发compaction请求:

    1. memstore flush之后触发;

    2. 客户端通过shell或者API触发;

    3. 后台线程CompactionChecker定期触发,周期为:

       hbase.server.thread.wakefrequency*hbase.server.compactchecker.interval.multiplier。
      
    4. 对于MajorCompact,触发了compaction请求后,真正的compaction操作能否执行,还要进行一系列的条件验证,
      即由hbase.hregion.majorcompaction和hbase.hregion.majorcompaction.jitter控制的一组条件。

    5. 对于MiniCompact当文件大小小于hbase.hstore.compaction.min.size 则会立即被添加到合并队列,当storeFile数量超过hbase.hstore.compaction.min时,minor compaction才会启动。

1.1 Hbase MinorCompact 参数设置

hbase.hregion.memstore.flush.size:640M
hbase.hregion.max.filesize  :100M  触发split
hbase.hstore.compaction.min : 满足条件 3 minor compaction才会启动
hbase.hstore.compaction.ratio :默认为1.2
hbase.hregion.majorcompaction : 0 关掉major compact
hbase.hstore.compaction.max : 默认值为10,表示一次minor compaction中最多选取10个store file
hbase.hstore.compaction.min : 默认值为 3
hbase.hstore.compaction.min.size :640M (未压缩?为memestoreFlushSize)
  • hbase.hstore.compaction.ratio :默认为1.2 ,将store file 按照文件年龄排序(older to younger),minor compaction总是从older store file开始选择,如果该文件的size 小于它后面hbase.hstore.compaction.max 个store file size 之和乘以 该ratio,则该store file 也将加入到minor compaction 中。

  • hbase.hstore.blockingStoreFiles:HStore的storeFile的文件数大于配置值,则在flush memstore前先进行split或者compact,除非超过hbase.hstore.blockingWaitTime配置的时间,默认为7,可调大,比如:100,避免memstore不及时flush,当写入量大时,触发memstore的block,从而阻塞写操作。

  • hbase.hregion.max.filesize :默认值是256M 当hbase.hregion.max.filesize比较小时,触发split的机率更大,而split的时候会将region offline,因此在split结束的时间前,访问该region的请求将被block住,客户端自我block的时间默认为1s。当大量的region同时发生split时,系统的整体访问服务将大受影响。因此容易出现吞吐量及响应时间的不稳定现象

  • hbase.hregion.max.filesize : 当hbase.hregion.max.filesize比较大时,单个region中触发split的机率较小,大量region同时触发split的机率也较小,因此吞吐量较之小hfile尺寸更加稳定些。但是由于长期得不到split,因此同一个region内发生多次compaction的机会增加了。compaction的原理是将原有数据读一遍并重写一遍到hdfs上,然后再删除原有数据。无疑这种行为会降低以io为瓶颈的系统的速度,因此平均吞吐量会受到一些影响而下降

  • hbase.hregion.max.filesize 这个值过大,读写hbase的速度会变慢,因为底层对hdfs的读写操作由于文件数量少,很难做到高并发,高吞吐,过小会发生频繁的文件split,split过程会使数据短暂离线,会对数据的访问有一定影响,不太稳定,所以这个值不能太小也不能太大,100-200MB基本能满足需求

  • 基于文件大小进行合并

      hbase.hstore.compaction.min.size 表示文件大小小于该值的store file 一定会加入到minor compaction的store file中
      hbase.hstore.compaction.max.size Long.MAX_VALUE  表示文件大小大于该值的store file 一定会被minor compaction排除
    
  • 基于文件数量进行合并

      hbase.hstore.compaction.min :默认值为 3,表示至少需要三个满足条件的store file时,minor compaction才会启动
      hbase.hstore.compaction.max :默认值为10,表示一次minor compaction中最多选取10个store file
    
  • hbase.hstore.blockingWaitTime block的等待时间 线上配置:90000(90s) 默认配置:90000(90s)

  • hbase.regionserver.global.memstore.upperLimit,默认为整个heap内存的40%。但这并不意味着全局内存触发的刷盘操作会将所有的MemStore都进行输盘,而是通过另外一个参数hbase.regionserver.global.memstore.lowerLimit来控制,默认是整个heap内存的35%。当flush到所有memstore占整个heap内存的比率为35%的时候,就停止刷盘。这么做主要是为了减少刷盘对业务带来的影响,实现平滑系统负载的目的。

  • hbase.hregion.memstore.flush.size:当MemStore的大小达到hbase.hregion.memstore.flush.size大小的时候会触发刷盘,默认128M大小。

  • hase.regionserver.max.logs :前面说到Hlog为了保证Hbase数据的一致性,那么如果Hlog太多的话,会导致故障恢复的时间太长,因此Hbase会对Hlog的最大个数做限制。当达到Hlog的最大个数的时候,会强制刷盘。这个参数是hase.regionserver.max.logs,默认是32个。

1.2 Hbase MinorCompact 功能

    为了本文的主题,此处参考了一篇非常好的博客,仅限该小节:https://blog.csdn.net/u014297175/article/details/50456147
  • 刷入一个54.4M的文件,在此触发一次Minor合并。从最早的文件,66.5G的开始,它显然比它后面几个文件(按配置是10个文件Ratio的大小),但他后面本不足10个文件,因此直接计入所有文件大小总和1.2。显然,它的大小超过了这个值,因此不纳入Minor合并,同理一直到666.4M文件,它也不小于54.3M*1.2所以不纳入合并,因此这波参与合并的只有54.3M文件,暂且等待下一个刷写文件。

  • 刷入一个54M的文件,这时进入合并流程,因为hbase.hstore.compaction.min=3,两个54M文件并未参与到合并。

  • 最后刷入一个54M的文件,3个54M文件合并成为一个150M的文件,其实这是3个54M一起合并的文件。但是那个666.4M的文件仍然不能纳入合并队列。

         注意:后面会不断判断进行Older to younger 的合并,但是这个154M的文件会纳入合并队列,因为当文件大小小于
         hbase.hstore.compaction.min.size(为memestoreFlushSize) 则会立即被添加到合并队列。

1.2 Hbase MajorCompact 参数设置

MajorCompact 条件:

  • hbase.hregion.majorcompaction:默认是24小时 hbase.hregion.majorcompaction.jitter:抖动,默认是20%
    以上两个参数意味着major合并周期为随机取19.2小时~28.8小时之间的数值。当major合并周期还未到达时,执行minor合并。

1.3 split 参数设置

一个reion达到一定的大小,他会自动split称两个region。如果我们的Hbase版本是0.94 ,那么默认的有三种自动split的策略,ConstantSizeRegionSplitPolicy,IncreasingToUpperBoundRegionSplitPolicy还有 KeyPrefixRegionSplitPolicy.

1.4 Hlog的生命周期设置

  • hbase.regionserver.logroll.period :Hlog的大小通过参数hbase.regionserver.logroll.period控制,默认是1个小时,时间达到hbase.regionserver.logroll.period 设置的时间,Hbase会创建一个新的Hlog文件。这就实现了Hlog滚动的目的。
  • hbase.regionserver.maxlogs:Hbase通过hbase.regionserver.maxlogs参数控制Hlog的个数。滚动的目的,为了控制单个Hlog文件过大的情况,方便后续的过期和删除。

2 MVCC 多版本控制

目前Hbase仅支持行级事务,不支持跨行跨表事务要求。

2.1 HBase事务的强一致性保证

  • 写写并发控制
  • 批量写入多行的写写并发控制
  • 读写并发控制

2.2 WAL日志的原子性

2.3 写写并发控制,存在先后顺序:

提供一个基于行的独占锁来保证对同一行写的独立性,所以写的顺序是:

  • 获取行锁
  • 写WAL文件
  • 更新MemStore:将每个Cell写入到memstore
  • 释放行锁

2.4 批量写入多行的写写并发控制

两阶段锁协议:不是一行一行的获得锁,批量写多行场景,防止死锁场景
两阶段锁协议,过程如下:

  • 获取所有待写入(更新)行记录的行锁。
  • 开始执行写入(更新)操作
  • 写入完成之后再统一释放所有行记录的行锁。

两阶段锁协议:不是一行一行的获得锁,而是批量写多行场景,防止多个事务之间形成死锁场景。

2.5 读写并发控制

通过事务序列来控制顺序:
事务只有提交了才会出列,通过指针(Read Point)指到底部已提交事务号,指针之下的用户才能可见:

3 总结

还需要进一步完善Major Compact的脚本控制逻辑

秦凯新 于深圳

猜你喜欢

转载自blog.csdn.net/shenshouniu/article/details/83902291