我们知道,一张 HBase 表包含一个或多个列族。
HBase 的官方文档中关于 HBase 表的列族的个数有两处描述:

A typical schema has between 1 and 3 column families per table. HBase tables should not be designed to mimic RDBMS tables. 以及 HBase currently does not do well with anything above two or three column families so keep the number of column families in your schema low.

上面两句话其实都是说一件事,HBase 中每张表的列族个数建议设在1~3之间。
其实,HBase 支持的列族个数并没有限制,但为什么文档建议在1~3之间呢?
我将从几个方面来阐述这么做的原因。

列族数对 Flush 的影响

在 HBase 中,调用 API 往对应的表插入数据是会写到 MemStore 的,而 MemStore 是一种内存结构,每个列族对应一个 MemStore(和零个或多个 HFile)。如果我们的表有两个列族,那么相应的 Region 中存在两个 MemStore,如下图:

从上图可以看出,越多的列族,将会导致内存中存在越多的 MemStore;
而储存在 MemStore 中的数据在满足一定条件的时候将会进行 Flush 操作;
每次 Flush 的时候,每个 MemStore 将在磁盘生产一个 HFile 文件,如下:

这样会导致越多的列族最终持久化到磁盘的 HFile 越多。更要命的是,当前 Flush 操作是 Region 级别的(当然,从HBase 1.1,HBase 2.0 开始 Flush 已经可以设置成列族级别的了),也就是说, Region 中某个 MemStore 被 Flush,同一个 Region 的其他 MemStore 也会进行 Flush 操作。当表有很多列族,而且列族之间数据不均匀,比如一个列族有100W行,一个列族只有10行,这样会导致持久化到磁盘的文件数很多,同时有很多小文件,而且每次 Flush 操作也涉及到一定的 IO 操作。

为了解决每次 Flush 都对整个 Region 中 MemStore 进行的,HBASE-10201/HBASE-3149引入了对 Flush 策略进行选择的功能(hbase.regionserver.flush.policy),可以仅对超过阈值(hbase.hregion.percolumnfamilyflush.size.lower.bound.min)的 MemStore 进行 Flush 操作。但是如果没有 MemStore 大于这个阈值,还是会对所有的 MemStore 进行 Flush 操作。

此外,如果我们的列族数过多,这可能会导致触发 RegionServer 级别的 Flush 操作;这将会导致落在该 RegionServer上的更新操作被阻塞,而且阻塞时间可能会达到分钟级别。

列族数对 Split 的影响

我们知道,当 HBase 表中某个 Region 过大(比如大于 hbase.hregion.max.filesize 配置的大小。当然,Region 分裂并不是说整个 Region 大小加起来大于 hbase.hregion.max.filesize 就拆分,而是说 Region 中某个最大的 Store/HFile/storeFile 大于 hbase.hregion.max.filesize 才会触发 Region 拆分的),会被拆分成两个。如果我们有很多个列族,而这些列族之间的数据量相差悬殊,比如有些列族有 100W 行,而有些列族只有10行,这样在 Region Split 的时候会导致原本数据量很小的 HFile 文件进一步被拆分,从而产生更多的小文件。注意,Region Split 是针对所有的列族进行的,这样做的目的是同一行的数据即使在 Split 后也是存在同一个 Region 的。

列族数对 Compaction 的影响

与 Flush 操作一样,目前 HBase 的 Compaction 操作也是 Region 级别的,过多的列族也会产生不必要的 IO。

列族数对 HDFS 的影响

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

列族数对 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。如果我们有很多的列族,而且一般一个 RegionServer 上会存在很多个 Region,这么算起来光 MemStore 的缓存就会占用很多的内存。要注意的是,如果没有往 MemStore 里面写数据,那么 MemStore 的 MSLAB 是不占用空间的。

关于列族数设置的建议

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

为什么不建议在 HBase 中使用过多的列族的更多相关文章

  1. 为什么不建议在hbase中使用过多的列簇

    我们知道,hbase表可以设置一个至多个列簇(column families),但是为什么说越少的列簇越好呢? 官网原文: HBase currently does not do well with ...

  2. HBase中Memstore存在的意义以及多列族引起的问题和设计

    Memstore存在的意义 HBase在WAL机制开启的情况下,不考虑块缓存,数据日志会先写入HLog,然后进入Memstore,最后持久化到HFile中.HFile是存储在hdfs上的,WAL预写日 ...

  3. 从HBase底层原理解析HBASE列族不能设计太多的原因?

    在之前的文章<深入探讨HBASE>中,笔者详细介绍了: HBase基础知识(包括简介.表结构).系统架构.数据存储 WAL log和HBase中LSM树的应用 HBase寻址机制 mino ...

  4. Hbase篇--HBase中一对多和多对多的表设计

    一.前述 今天分享一篇关于HBase的一对多和多对多的案例的分析. 二.具体案例 案例一.多对多    人员-角色   人员有多个角色  角色优先级   角色有多个人员   人员 删除添加角色   角 ...

  5. HBase中的压缩算法比较 GZIP、LZO、Zippy、Snappy [转]

    网址: http://www.cnblogs.com/panfeng412/archive/2012/12/24/applications-scenario-summary-of-compressio ...

  6. Flink 使用(一)——从kafka中读取数据写入到HBASE中

    1.前言 本文是在<如何计算实时热门商品>[1]一文上做的扩展,仅在功能上验证了利用Flink消费Kafka数据,把处理后的数据写入到HBase的流程,其具体性能未做调优.此外,文中并未就 ...

  7. HBase中的备份和故障恢复方法

    本文将对Apache HBase可用的数据备份机制和大量数据的故障恢复/容灾机制做简要介绍. 随着HBase在重要的商业系统中应用的大量添加,很多企业须要通过对它们的HBase集群建立健壮的备份和故障 ...

  8. 关于hbase中的hbase-site.xml 配置详解

    该文档是用Hbase默认配置文件生成的,文件源是 hbase-default.xml hbase.rootdir 这个目录是region server的共享目录,用来持久化HBase.URL需要是'完 ...

  9. Hbase中HMaster作用

    HMaster在功能上主要负责Table表和HRegion的管理工作,具体包括: 1.管理用户对Table表的增.删.改.查操作: 2.管理HRegion服务器的负载均衡,调整HRegion分布: 3 ...

随机推荐

  1. MVC中Model元数据及绑定机制

    ASP.NET MVC的Model为View Model,表示最终呈现在View上的数据,而Model元数据的一个重要的作用在于控制对象在View上的呈现方式.说得更加具体点,就是基于某种数据类型的M ...

  2. 并发编程(四)—— ThreadLocal源码分析及内存泄露预防

    今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...

  3. 使用ML.NET + ASP.NET Core + Docker + Azure Container Instances部署.NET机器学习模型

    本文将使用ML.NET创建机器学习分类模型,通过ASP.NET Core Web API公开它,将其打包到Docker容器中,并通过Azure Container Instances将其部署到云中. ...

  4. HUSTOJ:Transit Tree Path

    问题 D: Transit Tree Path   You are given a tree with N vertices.Here, a tree is a kind of graph, and ...

  5. 一文读懂MapReduce

    Hadoop解决大规模数据分布式计算的方案是MapReduce.MapReduce既是一个编程模型,又是一个计算框架.也就是说,开发人员必须基于MapReduce编程模型进行编程开发,然后将程序通过M ...

  6. springboot+springcloud集成jar

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  7. leetcode — pascals-triangle-ii

    import java.util.Arrays; /** * * Source : https://oj.leetcode.com/problems/pascals-triangle-ii/ * * ...

  8. jumpserver篇--安装

    参考:https://github.com/jumpserver/jumpserver/wiki/%E5%AE%89%E8%A3%85%E5%9B%BE%E8%A7%A3 服务器环境: ip:192. ...

  9. [九]JavaIO之ObjectInputStream 和 ObjectOutputStream

    序列化 序列化是指把Java对象保存为二进制字节码的过程,Java反序列化是指把二进制码重新转换成Java对象的过程 序列化是一种轻量级的持久化,对象都是存活在内存中的,当JVM运行结束,对象便不存在 ...

  10. Linux常用命令详解(week1_day1_3)--技术流ken

    本节内容 pidofpstopipuptimewgetcurltrddtargrepfind 命令详解 1.pidof 获取正在运行程序的PID 实例1: [root@ken ~]# pidof ss ...