1.列族是什么?

HBASE表中的每个列,都归属于某个列族。列族是表的schema的一部 分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如 courses:history,courses:math都属于courses 这个列族。

2. 列族的设计

Hbase官网建议每张表的列族数建议设在1-3之间,所以说列族的设计并不是越多越好。

3.为什么不是越多越好

其实可以大致分为5个方面来理解。

3.1 对Flush的影响

回顾一下HBase,每张表会根据RowKey值被切分为多个region,每个region也就是表的一部分子集,region会分散到HBase集群regionserver上;region中每个columnFamily也就是列族的数据组成一个Store。每个Store由一个MemStore和多个HFile组成(一个列族对应一个memstore和N个HFile),如果我们的表有两个列族,那么相应的 Region 中存在两个 MemStore,列族越多,将会导致内存中存在越多的 MemStore;而储存在 MemStore 中的数据在满足一定条件的时候将会进行 Flush 操作;每次 Flush 的时候,每个 MemStore 将在磁盘生产一个 HFile 文件,如下:
在这里插入图片描述
比如在flush时候,如果有多个memstore(多个列簇),只要有一个memstore达到flush条件,其他的memstore即使数据很小也要跟着执行flush,这也就导致了很多不必要的I/O开销。触发flush的条件如下:

  • Memstore级别限制:当Region中任意一个MemStore的大小达到了上限(hbase.hregion.memstore.flush.size,默认128MB),会触发Memstore刷新。

  • Region级别限制:当Region中所有Memstore的大小总和达到了上限(hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size,默认 2* 128M = 256M),会触发memstore刷新。

  • Region Server级别限制:当一个Region
    Server中所有Memstore的大小总和达到了上限(hbase.regionserver.global.memstore.upperLimit
    * hbase_heapsize,默认40%的JVM内存使用量),会触发部分Memstore刷新。Flush顺序是按照Memstore由大到小执行,先FlushMemstore最大的Region,再执行次大的,直至总体Memstore内存使用量低于阈值(hbase.regionserver.global.memstore.lowerLimit* hbase_heapsize,默认 38%的JVM内存使用量)。

  • 当一个RegionServer中HLog数量达到上限(可通过参数hbase.regionserver.maxlogs配置)时,系统会选取最早的一个
    HLog对应的一个或多个Region进行flush

  • HBase定期刷新Memstore:默认周期为1小时,确保Memstore不会长时间没有持久化。为避免所有的MemStore在同一时间都进行flush导致的问题,定期的flush操作有20000左右的随机延时。
    从HBase 1.1开始,Flush已经不是整个Region进行了,而仅对部分Family进行的

3.2 对Split的影响

hbase split是由参数hbase.hregion.max.filesize值来控制的,但是,触发region split不是说该region下所有的HFile文件大小达到这个值就会触发split,而是region下某个HFile文件达到了这个值才会执行split,也就是说这里ColumnFamilyB在做split时候,ColumnFamilyA的数据量还很小很小,但是也会被带着执行split,这也就会导致更多的HDFS小文件,并且分散到更多的region和regionservers上,注意,Region Split 是针对所有的列族进行的,这样做的目的是同一行的数据即使在 Split 后也是存在同一个 Region 的。

3.3 对 Compaction 的影响

在compact时候,由于是建立在region的基础上,同样会产生不必要的I/O开销,触发compcat(minor_compact)条件:
hbase.hstore.compactionThreshold:default 3

3.4 对 HDFS 的影响

dfs.namenode.fs-limits.max-directory-items是说HDFS的子目录下文件个数的限制,一个列族是对应到HDFS上的一个子目录的,不过相同表的数据是放一个目录的,如果我们有 N 个列族,M 个 Region,那么我们持久化到 HDFS 至少会产生 NM 个文件;而每个列族对应底层的 HFile 文件往往不止一个,我们假设为 K 个,那么最终表在 HDFS 目录下的文件数将是 NM*K,这可能会操作 HDFS 的限制。

3.5 对 RegionServer 内存的影响

一个列族在 RegionServer 中对应于一个 MemStore。而 HBase 从 0.90.1 版本开始引入了 MSLAB(Memstore-Local Allocation Buffers,参考HBASE-3455),这个功能默认是开启的(通过hbase.hregion.memstore.mslab.enabled),这使得每个 MemStore 在内存占用了 2MB (通过hbase.hregion.memstore.mslab.chunksize 配置)的 buffer。如果我们有很多的列族,那么光 MemStore 的缓存就会占用很多的内存。

4. 建议

在设置列族之前,我们最好想想,有没有必要将不同的列放到不同的列族里面。如果没有必要最好放一个列族。如果真要设置多个列族,但是其中一些列族相对于其他列族数据量相差非常悬殊,比如1000W相比100行,是不是考虑用另外一张表来存储相对小的列族。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐