`
hongs_yang
  • 浏览: 60977 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

hbase hfilev2文件

阅读更多

HFileV2文件

 

HFileV2文件写入通过StoreFile.Writer-->HFileWriterV2进行写入。

 

文件格式通过hfile.format.version配置。默认为2,也只有2这个值在0.96可用。

 

可通过cf中配置DATA_BLOCK_ENCODING配置dataBlockencoding,

 

可配置值:NONE,PREFIX,DIFF,FAST_DIFF,PREFIX_TREE,

 

通过在family的配置属性中配置BLOCKSIZE,来设置hfileblock大小,默认为65536

 

 

 

通过在family的配置属性中配置BLOOMFILTER,来设置是否启用BLOOMFILTER,默认值为ROW,可选值:NONEROWROWCOL

 

如果io.storefile.bloom.enabled配置的值为true,默认为true.writer中生成一个全局的bloomfilterWriter

 

StoreFile.Writer中生成的generalBloomFilterWriter,实现类为:CompoundBloomFilterWriter,

 

bloomfilterblocksize通过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.

 

public void append(final KeyValue kv) throws IOException {

 

如果是一个新的kv,也就是rowbloomfilter中的最后一个kvrow不相同,表示需要添加到bloomblock中。

 

此部分目前是在一个缓冲区中。

 

appendGeneralBloomfilter(kv);

 

如果kv是删除的KV,把row添加到deletebloomfilterblock中。

 

此部分目前是在一个缓冲区中。

 

appendDeleteFamilyBloomFilter(kv);

 

通过HFileWriterV2.append写入kvdatablock,

 

writer.append(kv);

 

trackTimestamps(kv);

 

}

 

 

 

HFileWriterV2.append(kv)直接调用如下方法:

 

private void append(final long memstoreTS, final byte[] key,

 

final int koffset, final int klength,

 

finalbyte[] value, finalint voffset, finalint vlength)

 

throws IOException {

 

检查key是否合法,首先检查上一个添加的key如果比当前的key大,表示有问题,因为hfile的写入需要排序写入。

 

如果当前的key比上次写入的key要小,返回值为false,如果返回值为true,表示两个key相同。我指的keyrowkey

 

boolean dupKey = checkKey(key, koffset, klength);

 

检查value是否为null

 

checkValue(value, voffset, vlength);

 

如果rowkey与上一次的rowkey不是同一个key时,检查hfileblock是否超过了指定的大小。

 

如果当前的rowkey与上一次写入的rowkey相同时,

 

就算是block大小超过了指定的大小,相同的rowkeykv都会写到一个block中。

 

if (!dupKey) {

 

此处是检查fsBlockWriter中的大小是否超过了blocksize的大小,如果起过了。需要执行blockflush操作。

 

checkBlockBoundary();

 

}

 

第一次进行入时,fsBlockWriter的状态为State.INIT;此时需要生成一个新的block,并设置StateState.WRITING;

 

在执行newBlock操作时,生成一个DataOutputStream,使用一个baosInMemory(ByteArrayOutputStream)

 

每一个block中,basosInMemory的缓冲区是重用的,因此,每一个block中都会执行baosInMemory.reset操作。

 

并写入blockheader信息。

 

if (!fsBlockWriter.isWriting())

 

newBlock();

 

 

 

写入kvdata block的缓冲区中。

 

// 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主要是block index(leaf-level-index)记录每一个blockfirst key.

 

// 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数据刷新

 

data block的大小默认为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操作。

 

private void checkBlockBoundary() throws IOException {

 

检查block是否达到指定的值。

 

if (fsBlockWriter.blockSizeWritten() < blockSize)

 

return;

 

datablock进行flush操作,

 

finishBlock();

 

写入索引数据到block中。

 

writeInlineBlocks(false);

 

生成一个新的block.

 

newBlock();

 

}

 

 

 

finishBlock方法:

 

private void finishBlock() throws IOException {

 

检查当前的fsBlockWriter的状态非State.WRITING;或者block中的值为0,不做操作。

 

if (!fsBlockWriter.isWriting() || fsBlockWriter.blockSizeWritten() == 0)

 

return;

 

 

 

long startTimeNs = System.nanoTime();

 

// Update the first data block offset for scanning.

 

if (firstDataBlockOffset == -1) {

 

如果是第一个block,设置blockoffset的值为0,也就是block的开始位置。

 

firstDataBlockOffset = outputStream.getPos();

 

}

 

记录上一个block的偏移量。主要是用来记录block index的一些个准备信息。

 

outputStream是每次write一个blockpos的值就会增加。

 

// Update the last data block offset

 

lastDataBlockOffset = outputStream.getPos();

 

设置fsBlockWriter的状态为State.BLOCK_READY;这样就可以重新执行写入操作。

 

通过读取buffer中的kv的值,通过encoderblock进行操作。如profix_free等。会写入到一个buffer中。

 

最后把数据写入到HDFS文件中。

 

fsBlockWriter.writeHeaderAndData(outputStream);

 

int onDiskSize = fsBlockWriter.getOnDiskSizeWithHeader();

 

 

 

byte[] indexKey = comparator.calcIndexKey(lastKeyOfPreviousBlock, firstKeyInBlock);

 

把当前blockkey与当前block的偏移量,当前block的大小写入到leaf level index(BlockIndex)中。

 

每一个block就会有一条blockindex记录。

 

dataBlockIndexWriter.addEntry(indexKey, lastDataBlockOffset, onDiskSize);

 

totalUncompressedBytes += fsBlockWriter.getUncompressedSizeWithHeader();

 

HFile.offerWriteLatency(System.nanoTime() - startTimeNs);

 

是否需要写入kvcache中。如果是需要,写入到readcache中。

 

if (cacheConf.shouldCacheDataOnWrite()) {

 

doCacheOnWrite(lastDataBlockOffset);

 

}

 

}

 

 

 

 

 

 

 

DataBlock的格式:

 

8byte

4byte

4byte

8byte

1byte

4byte

4byte

...

blockType

onDiskSize+checsumSize

unCompressedSize

prevOffset

checksumType

bytesPerChecksum

onDiskSize

data

 

 

 

BlockTypeblock类型

 

第二个是压缩部分下checksumsize的大小

 

第三部分是未压缩部分的大小

 

4部分是上一个block的偏移号

 

5部分是checksumtype的类型

 

6部分是是每个checksum的字节数,默认为16*1024

 

7部分是压缩部分的大小,但不包含checksunsize

 

最后是数据部分。

 

 

 

 

 

写入索引的block数据,要写入的索引包含如下几个:

 

blockIndex也就是dataBlockIndexWriter的默认实现是HFileBlockIndex.BlockIndexWriter.

 

BloomFilterIndex,也就是CompoundBloomFilterWriter实现。

 

DeleteBloomFilterIndex,也就是CompoundBloomFilterWriter实现。

 

private void writeInlineBlocks(boolean closing) throws IOException {

 

for (InlineBlockWriter ibw : inlineBlockWriters) {

 

while (ibw.shouldWriteBlock(closing)) {

 

long offset = outputStream.getPos();

 

boolean cacheThisBlock = 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.blockIndexshouldWriteBlock主要检查大小(rootindex)是否大于128*1024(128kb),

 

2.bloomFilterIndexdeleteBloomFilterIndexshouldWriteBlock

 

只要bloomfilter中有值,也就是chunk中有数据,shouldWriteBlock的方法返回就为true,

 

block写入到HDFS中。

 

blockIndexblockTypeLEAF_INDEX,

 

bloomfilterblockTypeBLOOM_CHUNK

 

 

 

也就是说:

 

blockIndex中记录有每一个dataBlockfirstKey,offset,blockSize,

 

bloomFilterIndex中记录有每一个(row)rowkey,(rowcol)或者rowkeyQualifier,hash值,

 

此处的hash主要是bloomfilter的相关信息。

 

 

 

每一个dataBlock进行flush后,都会强制flushbloomfilterblock.

 

flushbloomfilter后,

 

会在rootBloomFilter(bloomBlockIndexWriter)的缓冲区中记录此bloomfliterfirstkey.offset,blocksize.

 

 

 

在每一个blockindex进行flush后,这个在datablock进行flush时不会强制flsuh,只有达到指定的值时,才进行flush.

 

在每一次对blockindex进行flush后,会在rootindex的缓冲区中记录住此blockindexfirstkey,offset,blocksize.

 

 

 

最后:

 

1.在执行writer.close时,写入rootindexblock

 

如果blockindex的大小超过了128k,会把rootindex的每128k写入一个INTERMEDIATE_INDEX

 

记录住所有的INTERMEDIATE_INDEXfirstkey,offset,blocksize,

 

此处是一个重复的迭代过程,只有当ROOT_INDEX。可以写入的blocksize小于128kb时,把最后一个写入为ROOT_INDEX

 

trailer中记录ROOTINDEXoffset.

 

2.接下来写入meta,也就是rootbloomfilter的信息。

 

3.写入FILE_INFO。会在trailer中记录住fileInfooffset.

 

4.写入trailer.

 

 

 

Fileinfo中包含:

 

MAX_SEQ_ID_KEY,记录hfile最大的seqid,

 

MAJOR_COMPACTION_KEY,是否做过major compaction

 

TIMERANGE,记录hfile中的timeRangeTracker.

 

EARLIEST_PUT_TS,hfile中最老的timestamp

 

DATA_BLOCK_ENCODING,记录hfileencoding的配置值

 

BLOOM_FILTER_TYPE,记录有全局的bloomfilter的类型

 

DELETE_FAMILY_COUNT,记录有deletefamily的个数。

 

Hfile.LASTKEY,记录此hfile中最后一个key的值,

 

hfile.AVG_KEY_LEN,记录key的平均长度。

 

Hfile.AVG_VALUE_LEN,记录value的平均长度。

 

 

 

Trailer中的内容:

 

majorVersion:hfile的版本号,固定的值2

 

minorVersion,hfile的最大版本号,3.

 

loadOnOpenDataOffsetdatablockrootindexoffset

 

fileInfoOffset,fileinfooffset,

 

numDataIndexLevels,rootindex的层级,在上面提到过的INTERMEDIATE_INDEX有几个层级。

 

UncompressedDataIndexSize,Uncompressedsize总大小。

 

firstDataBlockOffset,第一个blockoffset

 

lastDataBlockOffset,最后一个blockoffset.

 

ComparatorClassName,比较器的类名称。

 

dataIndexCountrootindex中存储的index个数。

 

.......

 

 

 

 

 

 

 

0
0
分享到:
评论

相关推荐

    hbase2.2安装文件

    1. `hbase-2.2.2-bin.tar.gz`:这是HBase的二进制发行版,包含了运行HBase所需的所有可执行文件、库和配置文件。解压后,你可以直接在支持Java的环境中启动HBase服务,进行集群或单机模式的部署。 2. `hbase-2.2.2-...

    hbase导出csv,文本,html文件

    2. **数据导入Hive**:创建一个Hive外部表,该表与HBase表结构对应,然后使用`LOAD DATA`命令将HBase查询结果导入Hive。这一步需要配置HBase与Hive之间的连接,例如通过设置`hbase-site.xml`和`core-site.xml`的属性...

    指导手册06:HBase安装部署 hbase配置文件

    指导手册06:HBase安装部署 hbase配置文件

    基于虚拟机集hbase1.2.1配置文件

    在IT领域,HBase是一个分布式、面向列的开源数据库,它是构建在Apache Hadoop文件系统(HDFS)之上的,特别适合处理大规模数据。这里提到的"基于虚拟机集hbase1.2.1配置文件"是针对一个由一个Master节点和三个Slave...

    Python访问Hbase的库文件

    2. **ttypes.py**:TTYPES代表Thrift Types,HBase使用Apache Thrift作为其跨语言通信协议。ttypes.py文件是 Thrift编译后的Python接口定义,它包含了HBase服务的结构体和方法声明,这些结构体定义了客户端和服务端...

    hbase2.x-hbck2 jar包及测试命令

    HBCK2 jar包是这个工具的可执行文件,通常在HBase的lib目录下可以找到,名为`hbase-hbck2-x.x.x.jar`,其中`x.x.x`表示具体的HBase版本号。这个jar包包含了所有执行HBCK2命令所需的功能和类。你可以通过Hadoop的`...

    huaweicloudDocs#mrs#HBase-version文件损坏导致启动失败1

    问题背景HBase启动失败。原因分析HBase启动时会读取hbase.version文件,但是日志显示读取存在异常。通过hadoop fs -cat /hbas

    java从本地读文件并上传Hbase

    在Java编程环境中,将本地文件读取并上传到HBase是一项常见的任务,特别是在大数据处理和存储的场景下。HBase是一个分布式、版本化的NoSQL数据库,基于Apache Hadoop,适用于大规模数据存储。以下是一个详细的过程,...

    HBase配置文件与HBase doc文档

    本文件包可能包含了关于HBase的配置文件以及详细的官方文档,这些内容对于理解和管理HBase系统至关重要。 ### HBase配置文件 HBase的配置文件通常位于`conf`目录下,主要包括以下几个关键文件: 1. **hbase-site....

    HBase配置文件

    2. **hbase-default.xml**:这个文件包含了所有HBase的默认配置,一般不需要直接修改。如果你需要改变某个默认值,应当在`hbase-site.xml`中进行。 3. **regionservers**:此文件列出集群中的RegionServer节点,每...

    hbase专题配套文件

    《HBase专题配套文件解析》 HBase,全称Apache HBase,是构建在Hadoop分布式文件系统(HDFS)之上、面向列的开源数据库,主要用于处理大规模数据。HBase的设计理念是支持实时读写,适合大数据场景下的快速随机访问...

    Hbase配置所需要的配置文件.zip

    2. **hbase-env.sh**: 这个脚本文件用于设置HBase运行时的环境变量,如JVM参数。你可以调整`JAVA_HOME`指向你的Java安装目录,以及设置`HBASE_OPTS`以增加堆内存或开启其他性能优化选项。 3. **regionservers**: ...

    hbase专题测试文件

    【标题】:“HBase专题测试文件” 【描述】:这篇内容是与HBase相关的测试资料,配合某博主的博客文章进行深入学习。博客链接指向了CSDN平台的一篇文章,详细介绍了HBase的相关知识和实战操作,这可能是对HBase进行...

    hbase监控文件.zip

    2. **配置主机**:接着,配置你的HBase Master节点作为Zabbix的监控目标。在“配置”-&gt;“主机”中创建或选择已有的HBase Master主机,然后关联导入的HBase模板。 3. **验证监控**:配置完成后,Zabbix会自动发现并...

    hbase合并小文件Demo项目包

    为解决小文件的存储Hadoop自身提供了两种机制来解决相关的问题,包括HAR和SequeueFile,这两种方式在某些方面解决了本层面的问题,单仍然存在着各自...我们在进行多次的测试实现后最终觉得Hbase合并小文件更为靠谱些,

    Hadoop和Hbase 配置文件-完整好的

    1. `hbase-site.xml`: 这是HBase的核心配置文件,包含了HBase的主节点(Master)、ZooKeeper的连接信息(`hbase.zookeeper.quorum`),以及HBase的数据存储位置(`hbase.rootdir`)等。 2. `hbase-env.sh`: 这是一...

    hbase hbck2 jar

    hbase hbck2 jar; 完整打包; 适用于hbase 2.x维护,hbase 1.x不适用; 使用命令:hbase hbck -j hbase-hbck2-1.3.0-SNAPSHOT.jar fixMeta,最后两个参数分别代表 hbck2 jar包路径,维护命令(hbase-hbck2-1.3.0-...

    hbase-hbck2-1.1.0-SNAPSHOT.jar

    hbase-hbck2-1.1.0-SNAPSHOT.jar

    hbase-hbck2-1.2.0-SNAPSHOT.jar

    HBCK是HBase1.x中的命令,到了HBase2.x中,HBCK命令不适用,且它的写功能(-fix)已删除; HBCK2已经被剥离出HBase成为了一个单独的项目,如果你想要使用这个工具,需要根据自己HBase的版本,编译源码。其GitHub地址...

Global site tag (gtag.js) - Google Analytics