HBase MemStore与HStoreFile 的大小分析

Sumary:

  MemStore结构
  KeyValue构成细节
  HFile分析
  Maven

项目例子使用了Maven来管理Dependency,要运行例子,需要有maven环境,后面提到的HFile,StoreFile,HStoreFile指的是同一样东西,也就是HBase中Region每个CF对应的数据文件。
 
  HBase一直有一个问题,困扰着我一段时间了.时而思考一下,终不得解。
   
问题发生于5月某天,在做大量Put测试去观察MemStore的flush,
HStoreFile的Split和Compact操作时,奇怪的事情发生了,默认MemStore的size为128M,headSize达到128M,进行flush之后,MemStore恢复为0M,生成snapshot写hfile,最终生在hdfs的大小却是30M左右。

    百思不得奇怪,为什么会减少了这么多,压缩?NO!
   
最近开始研究HFile的相关内容时,又想起了MemStore size和HFile size不一致问题,再次做试验。最终找到了答案.

场景设置:
  环境: 64位 CentOS VM 伪分布Hadoop ,standalone方式的HBase 连接本机hdfs. 4G内存
4核
  Hadoop 2.3 HBase 0.98.1-hadoop2 HFileReader(Writer)
V2
  单个表,1个CF, 10W rows,即 70WKV,每个KV heapSize占100+byte左右,目测KV headSize会占有
70M

具体见测试代码。

1. 执行App.java 结束后,查看后台 master:60010 ,memStore的内存达到 112.9M

图1
2.通常,数据不会被flush至HFile中,重启HBase,强制flush memStore,再次查看后台web gui.

stop-hbase.sh
start-hbase.sh

图2
查看HFile只有26M。只有源数据的25%不到,很好,是我想要的结果。
也可以在stop后,直接使用hadoop
命令查看dfs中的文件大小 :hadoop fs -ls -R /hbase/data/default/t_sample/

图3
至此,第一个小实验做完了,结果很明显,MemStore 112.9M
flush到StoreFile中只有26M,不到1/4的容量,why?

首先我们看一个KeyValue的构成

图4
从图中可以得知KeyValue的细节,我们继续一些有趣的小实验。
1.构建一个KeyValue


 public static void main(String[] args) throws Exception {
final byte[] row = Bytes.toBytes("u1");
final byte[] family = Bytes.toBytes("info");
final byte[] qualifier = Bytes.toBytes("sex");
final byte[] value = Bytes.toBytes("M");

KeyValue kv = new KeyValue(row, family, qualifier, value);
kv.setMvccVersion(System.currentTimeMillis());
System.out.println(kv.heapSize());
}

输出: 96

顺手抓了一幅图如下:

图5
结合KeyValue结构图4及实际一个KeyValue的字节码图5我们分析一下:

第0-3个字节 为 int类型 Key的长度,在这里是 21
第4-7个字节 为 int类型
Value的长度,在这里只有1
第8-28个字节为Key的内容
8-9 short类型,指定了 rowKey的长度 值为 2.

10-11 对应的rowKey,转为原String为u1
12 byte型的ColumnFamility Length,值为4

13-16 对应CF值,转为原String为info
28为KeyType,由于我们创建KeyValue时没有显式指定,默认为Put(4)

20-27为8字节的Long型,对应timestamp.
所以剩下的为 17-19
三字节为Qualifier,转为原String为sex
第29,即最后一字节,是Value内容 : "M"

好,假设我们KeyValue的真实内容,就是这堆长度为30的字节码,我们简单算一下, 30 * 70 * 10000 /
1024 / 1024 =
20M,这个数值是不是和我们的HFile的大小有点接近呢?我们试想一下,文件中还有一些Index、MetaBlock、Meta、FileInfo等信息,七七八八加起来,再加上本身其它column的
value就不止1字节,所以已经非常接近我们这26M的目标大小了。
好的,我们假设这些字节码,就是直接存入到HFile中的,那么MemStore呢,存的又是哪样?我们再简单地算一下,
96 * 70*10000 / 1024 / 1024 = 64M,离 112.9M差了近一倍。

走另一条路,我们想另一个问题,再来看看,为什么KeyValue本身只有30byte,但是打印出来是在MemStore的heapSize是96?看看heapSize()方法。


public long heapSize() {
int sum = 0;
sum += ClassSize.OBJECT;// the KeyValue object itself 16字节
sum += ClassSize.REFERENCE;// pointer to "bytes" 8字节
sum += ClassSize.align(ClassSize.ARRAY);// "bytes" 24字节
sum += ClassSize.align(length);// number of bytes of data in the "bytes" array 以刚才的为例,30,会转化为32字节.
sum += 2 * Bytes.SIZEOF_INT;// offset, length 2字节
sum += Bytes.SIZEOF_LONG;// memstoreTS 8字节
return ClassSize.align(sum);
}

OK,由于在内存中的原因,一个KeyValue对象除了本身实际内容外,还有
64byte是对象的内部实例等占用了部分空间,从而会这么大。
    另外,我们查看MemStore的结构:


volatile KeyValueSkipListSet kvset;

KeyValue是放在SkipListSet中的,内部其实就是一个Map,那么我们每个KeyValue存在Map中其实是一个又一个是Entry.其中每一个Entry又占了64byte.所以,一个KeyValue占MemStore的空间大约是160bytes.
 
  我们取168个字节为一个KeyValue大概算一算 168 * 70 * 10000 / 1024 / 1024 = 112.1
,之所以取168其实也就是一行中7个KeyValue肉眼大约算出来的平均值,112.1M已经非常接近112.9M了.
   
假设我们用38* 70 * 10000 / 1024 /
1024来算,25.3M,更为精确点,所以结合二个size,我们假定,这就是它们的真实的内存大小和文件大小。

为了论证这一点,我们还是做一个实例。具体源码见附件中。


我们直接通过HFileReader去读取HDFS中的HFile,然后Scan里面所有的KeyValue进行统计。结果输出为:
MemStoreSize:118391920,HFileSize:27723608,KeyValue
Count:700000 转化单位
MemStoreSize:112.9M,HFileSize:26.4M,KeyValue Count:700000

好了,真相大白,完全证明了上面的推断是正确的。

项目源码下载: http://files.cnblogs.com/bdifn/MemStore_HStore_sample.zip

HBase MemStore与HStoreFile 的大小分析,布布扣,bubuko.com

时间: 2024-10-13 22:01:44

HBase MemStore与HStoreFile 的大小分析的相关文章

HBase的put流程源码分析

hbase是一个nosql型数据库,本文我们会分析一下客户的数据是通过什么样的路径写入到hbase的. HBase作为一种列族数据库,其将相关性较高的列聚合成一个列族单元,不同的列族单元物理上存储在不同的文件(HFile)内.一个表的数据会水平切割成不同的region分布在集群中不同的regionserver上.客户端访问集群时会首先得到该表的region在集群中的分布,之后的数据交换由客户端和regionserver间通过rpc通信实现,下面我们从hbase源码里探究客户端put数据的流程.本

HBase – Memstore Flush和flush shell操作 深度解析

//memstore flush机制 和flush shell命令刷新//Memstore是HBase框架中非常重要的组成部分之一,是HBase能够实现高性能随机读写至关重要的一环.深入理解Memstore的工作原理.运行机制以及相关配置,对hbase集群管理.性能调优都有着非常重要的帮助. 写机制(大约)1.HBase是基于LSM-Tree模型的,2.所有的数据更新插入操作都首先写入Memstore中(同时会顺序写到日志HLog中),3.达到指定大小之后再将这些修改操作批量写入磁盘,生成一个新

MemStore刷写线程—MemStoreFlusher源代码分析

在HBase中表由一个或多个Region组成,而Region由一个或者多个Store组成,Store又由一个MenStore和若干个StoreFile组成.无论是向HBase写入数据还是请求读数据,都首先经过MemStore,对于写请求来说就是将数据直接写入MemStore,对于读请求来说就是先检查MenStore中是否包含相应的数据,如果有则直接读取该数据,否则在StoreFile中检索并读取数据.当写入MemStore中的数据达到一定的数量时,就需要将其中的数据刷写到StoreFile中,这

Hbase regionserver 逐个挂掉的问题分析

最近遇到一个比较诡异的问题,一个regionserver由于GC的原因,导致与zookeeper链接超时,最终被踢出集群.但是,接下来的现象,才是噩梦的开始!!! 一个regionserver由于GC的原因,导致与zookeeper链接超时,最终被踢出集群. ~~~Hbase regionserver log~~~ 2018-05-31 11:42:17,739 INFO  [MemStoreFlusher.0] regionserver.HRegion: Started memstore fl

HBase写入性能改造(续)--MemStore、flush、compact参数调优及压缩卡的使用【转】

首先续上篇测试: 经过上一篇文章中对代码及参数的修改,Hbase的写入性能在不开Hlog的情况下从3~4万提高到了11万左右. 本篇主要介绍参数调整的方法,在HDFS上加上压缩卡,最后能达到的写入性能为17W行每秒(全部测试都不开Hlog). 上篇测试内容: 详情 http://blog.csdn.net/kalaamong/article/details/7275242. 测试数据 http://blog.csdn.net/kalaamong/article/details/7290192 同

hbase split 源码分析之split策略

在工作中接触到split,于是查看了这块的源代码,先看到了split的策略,今天就说说这个吧,后续还会有split的其他源码分析和compact相关的源码分析. 看了很多其他人的博客,很多都是转发的,原创的也都没有注明是哪个版本.其实给很多读者造成混淆,我这里是基于Hbase-0.98.13  版本作为分析的,注意:不同版本的此部分源码很可能不一样. 在这个版本中使用的split策略是IncreasingToUpperBoundRegionSplitPolicy.确切来说他是0.94版本以后的策

hbase源码系列(十三)缓存机制MemStore与Block Cache

这一章讲hbase的缓存机制,这里面涉及的内容也是比较多,呵呵,我理解中的缓存是保存在内存中的特定的便于检索的数据结构就是缓存. 之前在讲put的时候,put是被添加到Store里面,这个Store是个接口,实现是在HStore里面,MemStore其实是它底下的小子. 那它和Region Server.Region是什么关系? Region Server下面有若干个Region,每个Region下面有若干的列族,每个列族对应着一个HStore. HStore里面有三个很重要的类,在这章的内容都

[转帖]深度分析HBase架构

深度分析HBase架构 https://zhuanlan.zhihu.com/p/30414252 原文链接(https://mapr.com/blog/in-depth-look-hbase-architecture/) HBase的架构 物理上看, HBase系统有3种类型的后台服务程序, 分别是Region server, Master server 和 zookeeper. Region server负责实际数据的读写. 当访问数据时, 客户端与HBase的Region server直接

HBase一次客户端读写异常解读分析与优化全过程(干货)

大数据时代,HBase作为一款扩展性极佳的分布式存储系统,越来越多地受到各种业务的青睐,以求在大数据存储的前提下实现高效的随机读写操作.对于业务方来讲,一方面关注HBase本身服务的读写性能,另一方面也需要更多地关注HBase客户端参数的具体意义.这篇文章就从一个具体的HBase客户端异常入手,定位异常发生的原因以及相应的客户端参数优化. 案发现场 最近某业务在使用HBase客户端读取数据时出现了大量线程block的情况,业务方保留了当时的线程堆栈信息,如下图所示: 看到这样的问题,首先从日志和