hbase hfilev2
版权声明:本文为博主原创文章。未经博主同意不得转载。 https://blog.csdn.net/u014393917/article/details/25508809
HFileV2文件
HFileV2文件写入通过StoreFile.Writer-->HFileWriterV2进行写入。
文件格式通过。也仅仅有2这个值在0.96可用。
可通过cf中配置DATA_BLOCK_ENCODING配置dataBlock的encoding,
可配置值:NONE,PREFIX,DIFF,FAST_DIFF,PREFIX_TREE,
通过在family的配置属性中配置
通过在family的配置属性中配置BLOOMFILTER。来设置是否启用BLOOMFILTER。默认值为ROW,可选值:NONE。ROW。ROWCOL。
假设io.storefile.bloom.enabled配置的值为true,默觉得true.在writer中生成一个全局的bloomfilter的Writer
在StoreFile.Writer中生成的generalBloomFilterWriter。实现类为:CompoundBloomFilterWriter,
bloomfilter的blocksize通过io.storefile.bloom.block.size配置,默觉得128*1024(128k)
假设bloomfilter属性不是ROWCOL时。同一时候io.storefile.delete.family.bloom.enabled配置为true,默认值为true,
在StoreFile.Writer中生成的deleteFamilyBloomFilterWriter,实现类:CompoundBloomFilterWriter
writer.append操作
写HFileV2文件时,在store进行flush时,会生成StoreFile.Writer实例,通过Writer.append写入kv.
publicvoid append(finalKeyValue
kv) throws IOException {
假设是一个新的kv,也就是row与bloomfilter中的最后一个kv的row不同样,表示须要加入到bloomblock中。
此部分眼下是在一个缓冲区中。
appendGeneralBloomfilter(kv);
假设kv是删除的KV,把row加入到deletebloomfilter的block中。
此部分眼下是在一个缓冲区中。
appendDeleteFamilyBloomFilter(kv);
通过HFileWriterV2.append写入kv到datablock,
writer.append(kv);
trackTimestamps(kv);
}
HFileWriterV2.append(kv)直接调用例如以下方法:
privatevoid append(finallong
memstoreTS, finalbyte[] key,
finalint koffset,
finalint klength,
finalbyte[]value,
finalintvoffset,
finalintvlength)
throwsIOException {
检查key是否合法,首先检查上一个加入的key假设比当前的key大,表示有问题。由于hfile的写入须要排序写入。
假设当前的key比上次写入的key要小,返回值为false,假设返回值为true,表示两个key同样。
我指的key是rowkey
booleandupKey = checkKey(key, koffset,
klength);
检查value是否为null,
checkValue(value, voffset,vlength);
假设rowkey与上一次的rowkey不是同一个key时,检查hfile的block是否超过了指定的大小。
假设当前的rowkey与上一次写入的rowkey同样时,
就算是block大小超过了指定的大小。同样的rowkey的kv都会写到一个block中。
if(!dupKey) {
此处是检查fsBlockWriter中的大小是否超过了blocksize的大小。假设起过了。
须要运行block的flush操作。
checkBlockBoundary();
}
第一次进行入时,fsBlockWriter的状态为State.INIT;此时须要生成一个新的block。并设置State为State.WRITING;
在运行newBlock操作时。生成一个DataOutputStream,使用一个baosInMemory(ByteArrayOutputStream),
每个block中,basosInMemory的缓冲区是重用的。因此。每个block中都会运行baosInMemory.reset操作。
并写入block的header信息。
if(!fsBlockWriter.isWriting())
newBlock();
写入kv到datablock的缓冲区中。
//Write length of key and value and then actual key and value bytes.
//Additionally, we may also write down the memstoreTS.
{
DataOutputStream out =fsBlockWriter.getUserDataStream();
out.writeInt(klength);
totalKeyLength+= klength;
out.writeInt(vlength);
totalValueLength+= vlength;
out.write(key, koffset, klength);
out.write(value, voffset,vlength);
if(this.includeMemstoreTS){
WritableUtils.writeVLong(out,memstoreTS);
}
}
记录住此block的第一个key,firstkey主要是blockindex(leaf-level-index)记录每个block的firstkey.
//Are we the first key in this block?
if(firstKeyInBlock==
null){
//Copy the key.
firstKeyInBlock=
newbyte[klength];
System.arraycopy(key,koffset,
firstKeyInBlock,0, klength);
}
记录最后一个key的值。
lastKeyBuffer= key;
lastKeyOffset= koffset;
lastKeyLength= klength;
entryCount++;
}
flush data block数据刷新
datablock的大小默觉得65536(64k),当达到此值时,会对block进行flush操作。
在HFileWriterV2中通过append会对block进行检查。
检查是否是新的一个rowkey的值,假设是检查是否须要flush当前的block,并又一次创建一个新的block
boolean dupKey =checkKey(key, koffset, klength);
checkValue(value, voffset,vlength);
if(!dupKey) {
checkBlockBoundary();
}
检查是否达到flush的值。并进行flush操作。
privatevoid checkBlockBoundary()
throwsIOException {
检查block是否达到指定的值。
if(fsBlockWriter.blockSizeWritten()<
blockSize)
return;
对datablock进行flush操作,
finishBlock();
写入索引数据到block中。
writeInlineBlocks(false);
生成一个新的block.
newBlock();
}
finishBlock方法:
privatevoid finishBlock()
throwsIOException {
。不做操作。
if(!fsBlockWriter.isWriting()||
fsBlockWriter.blockSizeWritten()== 0)
return;
longstartTimeNs = System.nanoTime();
//Update the first data block offset for scanning.
if(firstDataBlockOffset==
-1) {
假设是第一个block,设置block的offset的值为0,也就是block的開始位置。
firstDataBlockOffset=
outputStream.getPos();
}
记录上一个block的偏移量。
主要是用来记录blockindex的一些个准备信息。
此outputStream是每次write一个block后pos的值就会添加。
//Update the last data block offset
lastDataBlockOffset=
outputStream.getPos();
设置fsBlockWriter的状态为State.BLOCK_READY;这样就能够又一次运行写入操作。
通过读取buffer中的kv的值,通过encoder对block进行操作。如profix_free等。
会写入到一个buffer中。
最后把数据写入到HDFS文件里。
fsBlockWriter.writeHeaderAndData(outputStream);
intonDiskSize =
fsBlockWriter.getOnDiskSizeWithHeader();
byte[]indexKey =
comparator.calcIndexKey(lastKeyOfPreviousBlock,firstKeyInBlock);
把当前block的key与当前block的偏移量,当前block的大写和小写入到leaflevel
index(BlockIndex)中。
每个block就会有一条block的index记录。
dataBlockIndexWriter.addEntry(indexKey,lastDataBlockOffset,onDiskSize);
totalUncompressedBytes+=
fsBlockWriter.getUncompressedSizeWithHeader();
HFile.offerWriteLatency(System.nanoTime()- startTimeNs);
是否须要写入kv到cache中。
假设是须要,写入到readcache中。
if(cacheConf.shouldCacheDataOnWrite()){
doCacheOnWrite(lastDataBlockOffset);
}
}
DataBlock的格式:
|
8byte |
4byte |
4byte |
8byte |
1byte |
4byte |
4byte |
... |
|
blockType |
onDiskSize+checsumSize |
unCompressedSize |
prevOffset |
checksumType |
bytesPerChecksum |
onDiskSize |
data |
BlockType是block类型
第二个是压缩部分下checksumsize的大小
第三部分是未压缩部分的大小
部分是上一个block的偏移号
部分是checksumtype的类型
部分是是每个checksum的字节数,默觉得16*1024
部分是压缩部分的大小,但不包括checksunsize
最后是数据部分。
写入索引的block数据,要写入的索引包括例如以下几个:
blockIndex也就是dataBlockIndexWriter的默认实现是HFileBlockIndex.BlockIndexWriter.
BloomFilterIndex,也就是CompoundBloomFilterWriter实现。
DeleteBloomFilterIndex,也就是CompoundBloomFilterWriter实现。
privatevoid writeInlineBlocks(booleanclosing)
throws IOException {
for(InlineBlockWriter ibw :
inlineBlockWriters){
while(ibw.shouldWriteBlock(closing))
{
longoffset =
outputStream.getPos();
booleancacheThisBlock = ibw.getCacheOnWrite();
ibw.writeInlineBlock(fsBlockWriter.startWriting(
ibw.getInlineBlockType()));
fsBlockWriter.writeHeaderAndData(outputStream);
ibw.blockWritten(offset,fsBlockWriter.getOnDiskSizeWithHeader(),
fsBlockWriter.getUncompressedSizeWithoutHeader());
totalUncompressedBytes+=
fsBlockWriter.getUncompressedSizeWithHeader();
if(cacheThisBlock) {
doCacheOnWrite(offset);
}
}
}
}
1.blockIndex的shouldWriteBlock主要检查大小(非rootindex)是否大于128*1024(128kb),
2.bloomFilterIndex与deleteBloomFilterIndex的shouldWriteBlock,
仅仅要bloomfilter中有值,也就是chunk中有数据。shouldWriteBlock的方法返回就为true,
把block写入到HDFS中。
blockIndex的blockType为LEAF_INDEX,
bloomfilter的blockType为BLOOM_CHUNK。
也就是说:
blockIndex中记录有每个dataBlock的firstKey,offset,blockSize,
bloomFilterIndex中记录有每个(row)rowkey,(rowcol)或者rowkey与Qualifier,的hash值,
此处的hash主要是bloomfilter的相关信息。
每个dataBlock进行flush后,都会强制flush到bloomfilter的block.
在flush后bloomfilter后,
会在rootBloomFilter(bloomBlockIndexWriter)的缓冲区中记录此bloomfliter的firstkey.offset,blocksize.
在每个blockindex进行flush后,这个在datablock进行flush时不会强制flsuh,仅仅有达到指定的值时,才进行flush.
在每一次对blockindex进行flush后,会在rootindex的缓冲区中记录住此blockindex的firstkey,offset,blocksize.
最后:
1.在运行writer.close时,写入rootindex的block
假设blockindex的大小超过了128k,会把rootindex的每128k写入一个INTERMEDIATE_INDEX。
记录住全部的INTERMEDIATE_INDEX的firstkey,offset,blocksize,
此处是一个反复的迭代过程,仅仅有当ROOT_INDEX。能够写入的blocksize小于128kb时,把最后一个写入为ROOT_INDEX。
在trailer中记录ROOTINDEX的offset.
2.接下来写入meta,也就是root的bloomfilter的信息。
3.写入FILE_INFO。会在trailer中记录住fileInfo的offset.
4.写入trailer.
Fileinfo中包括:
MAX_SEQ_ID_KEY,记录hfile最大的seqid,
MAJOR_COMPACTION_KEY,是否做过majorcompaction。
TIMERANGE,记录hfile中的timeRangeTracker.
EARLIEST_PUT_TS,hfile中最老的timestamp
DATA_BLOCK_ENCODING,记录hfile的encoding的配置值
BLOOM_FILTER_TYPE,记录有全局的bloomfilter的类型
DELETE_FAMILY_COUNT。记录有delete的family的个数。
Hfile.LASTKEY,记录此hfile中最后一个key的值,
hfile.AVG_KEY_LEN,记录key的平均长度。
Hfile.AVG_VALUE_LEN,记录value的平均长度。
Trailer中的内容:
,
minorVersion,hfile的最大版本,3.
loadOnOpenDataOffset。datablockrootindex的offset
fileInfoOffset,fileinfo的offset,
numDataIndexLevels,rootindex的层级。在上面提到过的INTERMEDIATE_INDEX有几个层级。
UncompressedDataIndexSize,Uncompressedsize总大小。
firstDataBlockOffset。第一个block的offset
lastDataBlockOffset,最后一个block的offset.
ComparatorClassName,比較器的类名称。
dataIndexCount,rootindex中存储的index个数。
.......
hbase hfilev2的更多相关文章
- HBASE架构解析(一)
http://www.blogjava.net/DLevin/archive/2015/08/22/426877.html 前记 公司内部使用的是MapR版本的Hadoop生态系统,因而从MapR的官 ...
- hbase基本结构
HBASE 基本结构一.overview1. hbase <=> NOSQL 不错,hbase 就是某种类型的nosql 数据库,唯一的区别就是他支持海量的数据. hbas ...
- HBase架构深度解析
原文出处: DLevin(@雪地脚印_) 前记 公司内部使用的是MapR版本的Hadoop生态系统,因而从MapR的官网看到了这篇文文章:An In-Depth Look at the HBase A ...
- Hbase学习02
第2章 Apache HBase配置 本章在“入门”一章中进行了扩展,以进一步解释Apache HBase的配置. 请仔细阅读本章,特别是基本先决条件,确保您的HBase测试和部署顺利进行,并防止数据 ...
- HBase:分布式列式NoSQL数据库
传统的ACID数据库,可扩展性上受到了巨大的挑战.而HBase这类系统,兼具可扩展性的同时,也提出了类SQL的接口. HBase架构组成 HBase采用Master/Slave架构搭建集群,它隶属于H ...
- 深入HBase架构解析(一)[转]
前记 公司内部使用的是MapR版本的Hadoop生态系统,因而从MapR的官网看到了这篇文文章:An In-Depth Look at the HBase Architecture,原本想翻译全文,然 ...
- hbase源码系列(九)StoreFile存储格式
从这一章开始要讲Region Server这块的了,但是在讲Region Server这块之前得讲一下StoreFile,否则后面的不好讲下去,这块是基础,Region Sever上面的操作,大部分都 ...
- 【转】HBase架构解析
转载地址:http://www.blogjava.net/DLevin/archive/2015/08/22/426877.html HBase架构组成 HBase采用Master/Slave架构搭建 ...
- hbase(一)region
前言 文章不含源码,只是一些官方资料的整理和个人理解 架构总览 这张图在大街小巷里都能看到,感觉是hbase架构中最详细最清晰的一张,稍微再补充几点. 1) Hlog是低版本hbase术语,现在称为W ...
随机推荐
- Java入门系列-20-异常
为什么要进行异常处理 下面这段代码能否正常执行 public class DemoCalc { public static void main(String[] args) { int a=0; in ...
- 一个Java小菜鸟的实习之路
博主今年大四,六月份毕业,之前一直对编程感兴趣,于是在大学里自学了Java,(本专业是通信工程).在今年过年的时候,父母让来南方过年,于是博主自己也想着能不能在南方找份java的实习先干着,了解一下行 ...
- 【AAA】AAA协议介绍
AAA AAA简介 AAA是认证(Authentication).授权(Authorization)和计费(Accounting)的简称,是网络安全中进行访问控制的一种安全管理机制,提供认证.授权和计 ...
- 007.ASP.NET MVC控制器依赖注入
原文链接:http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be 前 ...
- linux免密登录ssh验证配置方法及常见错误解决
目标:从服务器A免密登录服务器B [配置方法] 1.在服务器A生成密钥文件,直接使用以下命令: ssh-keygen 中间遇到输入内容一路回车即可,完成后会在 ~/.ssh 目录下生成两个文件:id_ ...
- HttpContext在多线程异步调用中的使用方案
1.在线程调用中,有时候会碰到操作文件之类的功能.对于开发人员来说,他们并不知道网站会被部署在服务器的那个角落里面,因此根本无法确定真实的物理路径(当然可以使用配置文件来配置物理路径),他们唯一知道的 ...
- ASP.NET MVC4 新手入门教程之六 ---6.编辑视图与编辑方法
在本节中,您会为电影控制器检查生成的操作方法和视图.然后,您将添加一个自定义的搜索页面. 运行该应用程序,然后浏览到Movies控制器通过将/Movies追加到您的浏览器的地址栏中的 URL.将鼠标指 ...
- JVM(五) class类文件的结构
概述 class类文件的结构可见下面这样图(出处见参考资料),可以参照下面的例子,对应十六进制码,找出找出相应的信息. 其中u2 , u4 表示的意思是占用两个字节和占用四个字节,下面我们将会各项说明 ...
- 初学zookeeper--自定义事件监听
zk有四种节点类型: 持久节点,持久顺序节点,临时节点,临时顺序节点. 自定义监听事件时,在节点的创建,修改,删除的方法第一行都需要加入是否监听的一个方法: //开启监听的方法.第二个参数表示是否开启 ...
- C Primer Plus note1
C语言编译错误:multiple definition of `main' main多重定义,在同一个工程中定义了多个main函数 出现如下图的错误: 这是因为在第一张图中,有一个main.c的mai ...