HBase 是一个基于 Google BigTable 论文设计的高可靠性、高性能、可伸缩的分布式存储系统。 网上关于 HBase 的文章不少,官方文档介绍的也比较详细,本篇文章不介绍HBase基本的细节。apache
本文从 HBase 写链路开始分析,而后针对少许随机读和海量随机写入场景入手,全方面量化分析各类资源的开销, 从而作到如下两点:bash
HBase 的写入链路基于 LSM(Log-Structured Merge-Tree), 基本思想是把用户的随机写入转化为两部分写入:服务器
Memstore 内存中的 Map, 保存随机的随机写入,待 memstore 达到必定量的时候会异步执行 flush 操做,在 HDFS 中生成 HFile 中。 同时会按照写入顺序,把数据写入一份到 HDFS 的 WAL(Write Ahead Log)中,用来保证数据的可靠性,即在异常(宕机,进程异常退出)的场景下,可以恢复 Memstore 中还没来得及持久化成 HFile 的数据.网络
上一节中,介绍了 HBase 的写路径,其中 HFile 是 HBase 数据持久化的最终形态, 本节将介绍 HBase 如何生成 HFile 和管理 HFile。关于 HFile, 主要涉及到两个核心操做:异步
上一节中提到,HBase 的写入最早会放入内存中,提供实时的查询,当 Memstore 中数据达到必定量的阈值(128MB),会经过 Flush 操做生成 HFile 持久化到 HDFS 中,随着用户的写入,生成的 HFile 数目会逐步增多,这会影响用户的读操做,同时也会系统占用(HDFS 层 block 的数目, regionserver 服务器的文件描述符占用), region split 操做,region reopen 操做也会受到不一样程度影响。 HBase 经过 Compaction 机制将多个 HFile 合并成一个 HFile 以控制每一个 Region 内的 HFile 的数目在必定范围内, 固然 Compaction 还有其余的做用,好比数据本地化率,多版本数据的合并,数据删除标记的清理等等,本文不作展开。分布式
另外还有一点须要知道的是,HBase 中 Flush 操做和 Compaction 操做和读写链路是由独立线程完成的,互不干扰。性能
为了简化计算,本节针对事件类数据写吞吐型场景,对 HBase 系统中的开销作定量的分析,作如下假设:大数据
以上 11 个参数,是本次量化分析中须要使用到的变量,系统资源方面主要量化如下两个指标:优化
这里只考虑磁盘空间方面的占用,相关的变量有:网站
HFile的磁盘容量量化公式
V = TTL * 86400 * T * s * C * R1
假设 s = 1000, TTL = 365, T = 200000, C = 0.2 , R1 = 3 的状况下,HFile 磁盘空间需求是:
V = 30 * 86400 * 200000 * 1000 * 0.2 * 3
= 311040000000000.0 bytes
= 282T
复制代码
在这里咱们忽略了其余占用比较小的磁盘开销,好比:
HBase中会形成巨大网络开销的主要由一下三部分组成,他们是相互独立,异步进行的,这里作个比方,HBase 这三个操做和人吃饭很像,这里作个类比
回归正题,下面按照发生顺序,从三个角度分别分析:
写路径的网络开销,主要是写 WAL 日志方面, 相关的变量有:
写路径中,产生的网络流量分为两部分,一部分是写 WAL 产生的流量,一部分是外部用户 RPC 写入的流量, In 流量和 Out 流量计算公式为:
NInWrite = T * s * Cwal * (R2 - 1) + (T * s )
NOutWrite = T * s * Cwal * (R2 - 1)
假设 T = 20W,s = 1000, Cwal = 1.0, R2 = 3
NInwrite = 200000 * 1000 * 1 * (3-1) + 200000 * 1000
= 600000000 bytes/s
= 572MB/s
NOutwrite = 200000 * 1000* 1 * (3-1)
= 400000000 bytes/s
= 381MB/s
复制代码
Flush 的网络开销,主要是生成 HFile 后,将 HFile 写入到 HDFS 的过程,相关的变量有:
Flush 产生的 In 流量和 Out 流量计算公式为:
NInWrite = s * T * (R1 - 1) * C
NOutWrite = s * T * (R1 - 1) * C
假设 T = 20W, S = 1000, R1 = 3, C = 0.2
NInwrite = 200000 * 1000 * (3 - 1) * 0.2
= 80000000.0 bytes/s
=76.3MB/s
NOutwrite = 200000 * 1000 * (3 - 1) * 0.2
= 120000000.0 bytes/s
=76.3MB/s
复制代码
Compaction 比较复杂,在有预分区不考虑 Split 的状况下分为两类:
二者是独立的,下面将分别针对两种 Compaction 作分析,最后取和:
Major Compaction 的定义是由所有 HFile 参与的 Compaction, 通常在发生在 Split 后发生,或者到达系统的 MajorCompaction 周期, 默认的 MajorCompaction 周期为 20 天,这里咱们暂时忽略 Split 形成的 MajorCompaction 流量. 最终 Major Compaction 开销相关的变量是:
这里假设数据是有本地化的,因此 MajorCompaction 的读过程,走 ShortCircuit,不计算网络开销,而且写 HFile 的第一副本是本地流量,也不作流量计算,因此 MajorCompaction 的网络流量计算公式是:
NInMajor = D * (R1 - 1) / M
NOutMajor = D * (R1 - 1) / M
假设 D = 10T, R1 = 3, M = 20
NInMajor = 10 * 1024 * 1024 * 1024 * 1024 * (3 - 1) / (20 * 86400)
= 12725829bytes/s
= 12MB/s
NOutMajor = 10 * 1024 * 1024 * 1024 * 1024 * (3 - 1) / (20 * 86400)
= 12725829bytes /s
= 12MB/s
复制代码
量化以前,先问一个问题,每条数据在第一次 flush 成为 HFile 以后,会通过多少次 Minor Compaction?
要回答这个问题以前,要先了解如今 HBase 默认的 compaction 的文件选取策略,这里不展开,只作简单分析,MinorCompaction 选择的文件对象数目,通常处于 hbase.hstore.compaction.min(默认 3)和 hbase.hstore.compaction.max(默认 10)之间, 总文件大小小于 hbase.hstore.compaction.max.size(默认 Max), 若是文件的 Size 小于 hbase.hstore.compaction.min.size(默认是 flushsize), 则必定会被选中; 而且被选中的文件size的差距不会过大, 这个由参数 hbase.hstore.compaction.ratio 和 hbase.hstore.compaction.ratio.offpeak 控制,这里不作展开.
因此,在 Compaction 没有积压的状况下,每次 compaction 选中的文件数目会等于 hbase.hstore.compaction.min 而且文件 size 应该相同量级, 对稳定的表,对每条数据来讲,通过的 compaction 次数越多,其文件会越大. 其中每条数据参与 Minor Compaction 的最大次数能够用公式 math.log( 32000 / 25.6, 3) = 6 获得
这里用到的两个变量是:
因此刚刚 Flush 生成的 HFile 的大小在 25.6MB 左右,当集齐三个 25.6MB 的 HFile 后,会触发第一次 Minor Compaction, 生成一个 76.8MB 左右的 HFile
对于通常状况,单个 Region 的文件 Size 咱们会根据容量预分区好,而且控制单个 Region 的 HFile 的总大小 在 32G 之内,对于一个 Memstore 128MB, HFile 压缩比 0.2, 单个 Region 32G 的表,上表中各个 Size 的 HFile 数目不会超过 2 个(不然就知足了触发 Minor Compaction 的条件)
32G = 18.6G + 6.2G + 6.2G + 690MB + 230MB + 76.8MB + 76.8MB
到这里,咱们知道每条写入的数据,从写入到 TTL 过时,通过 Minor Compaction 的次数是能够计算出来的。 因此只要计算出每次 Compaction 的网络开销,就能够计算出,HBase 经过 Minor Compaction 消化每条数据,所占用的总的开销是多少,这里用到的变量有:
计算公式以下:
NInMinor = S * T * (R1-1) * C * 总次数
NOutMinor = S * T * (R1-1) * C * 总次数
假设 S = 1000, T = 20W, R1 = 3, C = 0.2, 总次数 = 6
NInminor = 1000 * 200000 * (3 - 1) * 0.2 * 6
= 480000000.0bytes/s
= 457.8MB/s
NOutminor = 1000 * 200000 * (3 - 1) * 0.2 * 6
= 480000000.0bytes/s
= 457.8MB/s
复制代码
在用户写入 TPS 20W, 单条数据大小 1000 bytes的场景下,总体网络吞吐为:
NIntotal = NInwrite + NInflush + NInmajor + NInminor
= 572MB/s + 76.3MB/s + 12MB/s + 457.8MB/s
= 1118.1MB/s
NOuttotal = NOutwrite + NOutflush + NOutmajor + NOutminor
= 381MB/s + 76.3MB/s + 12MB/s + 457.8MB/s
= 927.1MB
复制代码
固然这是理想状况下的最小开销,有不少种状况,能够致使实际网络开销超过这个理论值, 如下状况都会致使实际流量的升高:
有了这个量化分析后,咱们能作什么优化呢? 这里不深刻展开,简单说几点已经在有赞生产环境获得验证具备实效的优化点:
到这里,HBase 的写吞吐场景的资源定量分析和优化的介绍就算结束了,本文基于 HBase1.2.6 版本。 对不少 HBase 的细节没有作展开说明,有些地方由于做者认知有限,不免纰漏,欢迎各位同行指出。
最后打个小广告,有赞大数据团队基础设施团队,主要负责有赞的数据平台(DP), 实时计算(Storm, Spark Streaming, Flink),离线计算(HDFS,YARN,HIVE, SPARK SQL),在线存储(HBase),实时 OLAP(Druid) 等数个技术产品,欢迎感兴趣的小伙伴联系 hefei@youzan.com
参考文献