为什么在 HBase 中不建议单表列簇超过 3 个

2021-12-07 20:18:59 浏览数 (1)

发表于2019-03-192020-03-03 作者 Ryan

首先,我们来看一张 HBase 的存储结构图(图片来源于网络),如下:

HBase 的数据存储节点叫做 HRegionServer,每个 HRegionServer 管理很多个 HRegion,Region 是HBase你们数据管理的最小单元,不同的 Region 存放在不同的 HRegionServer 机器上。

每个 HRegion 由一个 HLog 和 一个或者多个 Store 组成。每个 Store 由保存一个列簇 (columns family) 。 每个Strore又由一个memStore和 零个至多个StoreFile 组成。memStore 存储在内存中, StoreFile 存储在HDFS上。

说到这里,我们可以很明显的感知到,多个 Region 会造成性能问题,具体是什么性能问题,接着往下看……但我们在想一个问题,Region 少一点绕开性能问题行不行。笔者直接告诉你,也不行!为什么? Region 数目太少就会妨碍可扩展性,导致单个 Region 变得很大降低了并行度。

回到正题,我们在定义 HBase 表的时候,在没有配置“hbase.hregion.max.filesize”的情况下,默认单个 Region 的大小为:10 * 1024 * 1024 * 1024,但写入数据量超过该值,会造成 Region 的 split 动作。这个 RegionSplitPolicy 策略有如下几种方式:

  • ConstantSizeRegionSplitPolicy : 这个是版本为 0.94.0 的默认region split 策略。根据公式min(r^2*flushSize,maxFileSize ) 确定split的maxFileSize,其中 r 为在线 Region个数,maxFileSize由hbase.hregion.max.filesize指定。
  • IncreasingToUpperBoundRegionSplitPolicy : 仅仅当region大小超过常量值(hbase.hregion.max.filesize大小)时,才进行拆分。
  • DelimitedKeyPrefixRegionSplitPolicy : 保证以分隔符前面的前缀为splitPoint,保证相同RowKey前缀的数据在一个Region中 。
  • KeyPrefixRegionSplitPolicy :保证具有相同前缀的 Row 在一个Region中(要求设计中前缀具有同样长度)。指定 Rowkey 前缀位数划分 Region ,通过读取 table 的 prefix_split_key_policy.prefix_length 属性,该属性为数字类型,表示前缀长度,在进行 split 时,按此长度对splitPoint进行截取。此种策略比较适合固定前缀的 Rowkey。当table中没有设置该属性,或其属性不为 Integer 类型时,指定此策略效果等同与使用IncreasingToUpperBoundRegionSplitPolicy。

在建表的时候可以直接手动分配分区方式,以避免热点数据,也可以通过配置分区策略,通过配置文件的方式生成的效果是全局的,这点需要注意!

上面说了 HBase 的分区策略,接下来我们回到正题, 进行 Region Split 的条件为:1. 该 Region 下所有的 StoreFile 中最大的 StoreFile 文件的大小超过阀值即进行 Split 在文件层次上,不同的列族,存储在不同的文件中。但是不同的列族,可能会共享一个 Region。(问题点就在这里了)

举个例子:比如你有 A ,B 两个列蔟,A 列蔟 有 1000w 行数据,B 列蔟有 10w 行数据,也就是说 A 列簇存储的数据量是 B 列簇存储数据量的 100 倍。 A 列簇会发生多次 Split 动作,提升 A 列簇的并发性,而 B 列簇由于跟 A 列簇共同属于一个 Region ,也会被动的 Split 掉了! B 列簇被 Split 后,单 Region 所持有的数据量变少了,这样的话,就导致了扫描 B 列簇的性能下降很多。

其次,存在多个列簇的时候,由于它们是共享的同一个 Region,如果其中的一个 列簇触发了 flush 动作,相应关联的其他列簇也会进行 flush 。导致系统整体产生更多的 IO , 耗费资源 。

我们总结一下:

主要有两点:

1. 多列簇导致持有数据量最少的列簇扫描性能下降,主要是因为数据太分散。

2. 系统产生更多的 IO ,耗费资源;

0 人点赞