hfile,compact and split of hbase

40
HBase Source Code Analysis 1. HFile 2. HBase Compact 3. HBase Split 基于 HBase0.96 FX__Bull -- 移动数据组

Upload: jhao-niu

Post on 10-May-2015

892 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: HFile,Compact And Split of HBase

HBase  Source  Code  Analysis    

1.  HFile 2.  HBase Compact 3.  HBase Split

基于HBase0.96

FX__Bull -- 移动数据组

Page 2: HFile,Compact And Split of HBase

·正⽂文级别1   ·正⽂文级别2   ·正⽂文级别3    ·正⽂文级别4     ·正⽂文级别5

·HFIle 是什么?   ·⽤用来解决什么问题?   ·⾃自⼰己设计怎么实现?    ·HFile如何做的?     ·HFile有何优缺点?

Page 3: HFile,Compact And Split of HBase

HFile是什么

一种文件格式  •    采用SStable的思想,HBase的底层存储是HFile;  •    存储的基本数据是key-­‐value对        与HDFS天然集成                      

Page 4: HFile,Compact And Split of HBase

⽤用来解决什么问题

要解决的问题就是:

1.  以何种方式将按照Key排好序的KeyValue数据存储到磁盘,以便高效的操作数据:low-latency reads and writes。

2.  HFile的依赖的分布式文件系统是HDFS,决定了写HFile也只能采用append操作实现,一旦写入数据便是immutable的,我们不能对特定的key进行编辑、删除等操作。

HFile文件格式对特定字节存储什么内容做了规定,以便可以按照格式读取数据。

Page 5: HFile,Compact And Split of HBase

⾃自⼰己如何设计?

1、首先检索排好序的数据首先会想到?    2、HFile可能会包含上亿条数据如何做?    3、为什么不用B-­‐Tree                  

Page 6: HFile,Compact And Split of HBase

HFile如何实现的 1、分块 + 分级索引    2、布隆过滤器过滤掉集合中不存在的Key    3、⽂文件存磁盘,需记录索引的位置等信息  

Page 7: HFile,Compact And Split of HBase

HFile如何实现的 分析文件格式 好的方法,其实就是看他源码的读和写过程;  分析HBase向磁盘写了什么内容,便可以分析出格式;    

HBase  write  path  

Page 8: HFile,Compact And Split of HBase

HFile如何实现的 实现写HFile首先需要构建一个HFile.Writer对象。    跟踪KeyValue对象的创建过程和HFileWriterV2对象的append(KeyValue  kv  )方法,构造出每个Record的格式:  

key=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZI/info:city/LATEST_TIMESTAMP/Put  

Page 9: HFile,Compact And Split of HBase

HFile如何实现的 随着不断地加入新的KeyValue对,当DataBlock达到一定的阀值时(fsBlockWriter.blockSizeWritten() < blockSize),会执行finishBlock()操作

1、按照指定压缩方式,对DataBlock(KeyValue部分)进行压缩。2、进行组装Header,添加循环冗余校验信息等操作3、添加一条索引记录,将这个块的firstKey,lastDataBlockOffset,onDiskDataSize加入LEAF_INDEX索引项。

备注:索大小大概为(56+AvgKeySize)*NumBlocks

假如BlockSize为64K ,假如HFile大小达到100G,那么索引将近200M

 

Page 10: HFile,Compact And Split of HBase

HFile如何实现的

Page 11: HFile,Compact And Split of HBase

HFile如何实现的

当索引的达到一定阀值时(默认HFileBlockIndex.DEFAULT_MAX_CHUNK_SIZE 128KB),会在写一个LEAF_INDEX。

Page 12: HFile,Compact And Split of HBase

HFile如何实现的

当写完之后,调用write的close方法,首先执行finishBlock()将剩余的数据加入输出流,并写InlineBlockIndex等;

顺序添加metadata、rootIndex、metaBlockIndex、FileInfo、Trailer等信息。

ROOT_INDEX:

1.  添加ROOT_INDEX对这个InlineBlockIndex的索引项。

2.  发现如果root_index的size达到一定阀值(128K),便会加一级索引,达到3级

Page 13: HFile,Compact And Split of HBase

HFile如何实现的

HFile的fix_trailer 包含了指向其它块的offsets信息,各个模块的内容: 执行 bin/hbase org.apache.hadoop.hbase.io.hfie.HFile -m -f /opt/local/hbase/uuid_rtgeo/06faaf5e0ea384d277061bf00757710e/info/a596111cbc8f4e1b96da230fd588f8a5

Page 14: HFile,Compact And Split of HBase

HFile如何实现的

到此为止写过程结束:      详细内容请看,欢迎交流:hVp://wiki.sankuai.com/pages/viewpage.acYon?pageId=78479497      阅读HBase代码时maven依赖hadoop源码无法查看

解决办法:�1、下载hadoop-1.1.2.tar.gz �2、找到其源码包,打包jar,buildpath添加、刷新即可

             

Page 15: HFile,Compact And Split of HBase

HFile如何实现的

相对于HFileV1:    1、写过程索引以及布隆过滤器不用一直保存在内存里,当达到阀值变写到磁盘,同样由于分级读过程不需要将所有索引在启动时便加载到内存,降低内存使用和启动时间,思路都是将它们切分为多个block.  2、对压缩数据的支持,记录compressed size可以在扫描HFile时不用解压,不用查找索引,直接skip过当前块进入下一块。

V1:  hVp://wiki.sankuai.com/download/aVachments/78479497/image2013-­‐12-­‐9%2014%3A43%3A27.png?version=1&modificaYonDate=1386571406000&api=v2  

         

Page 16: HFile,Compact And Split of HBase

HFile如何实现的 那么读该如何实现?1、创建HFile.Reader时,加载Trailer,进而加载FileInfo,RootIndex等内容。2、查找的过程实质上就是对各级索引进行二分查找,并根据BlockType来判断块是索引还是Data已决定是否需要继续向下寻找。

3、load块,然后顺序扫描,seek到指定位置。

Page 17: HFile,Compact And Split of HBase

HFile⼀一些性能点 1、大的块适合顺序扫描,但是随机读写性能降低,(大的快解压速度会变慢),小的HFile block更加适合随机读写,但是需要更多地内存来存放index.

2、将块加到cache,默认策略为LRU,对GC不太友好。//TODO bucketCache

3、HFileV2的分级索引,虽然可以减少内存的使用量,加快启动速度,但是多了1-2次IO,尤其是HFile文件较大时,随机读很可能比V1要多2次IO操作,进而读取速度变慢。

Page 18: HFile,Compact And Split of HBase

·正⽂文级别1   ·正⽂文级别2   ·正⽂文级别3    ·正⽂文级别4     ·正⽂文级别5

·概述   ·触发条件   ·如何选择

•  如何合并       

HBase Compact

Page 19: HFile,Compact And Split of HBase

HBase Compact •  HBase stores rows of data in tables. Tables are split into chunks

of rows called “regions”. Those regions are distributed across the cluster, hosted and made available to client processes by the RegionServer process.

•  A region is a continuous range within the key space, meaning all rows in the table that sort between the region’s start key and end key are stored in the same region. a single row key belongs to exactly one region at any point in time

•  A Region in turn, consists of many “Stores”, which correspond to column families. A store contains one memstore and zero or more store files. The data for each column family is stored and accessed separately. �

Page 20: HFile,Compact And Split of HBase

HBase Compact

Page 21: HFile,Compact And Split of HBase

HBase Compact

HBase  bulk-­‐load  就是先根据region分区等条件,先生成storeFile,之后mv到相应的store目录下,及时生效的    

Page 22: HFile,Compact And Split of HBase

HBase Compact

�对于HBase,执行一个写操作时,首先会将内容写到内存中的MemStore,当MemStore达到一定阀值时,这个MemStore就会冻结,同时产生一个新的MemStore来响应写操作,之前的MemSore会flush到磁盘,形成一个StoreFile文件。

�随着MemStore不断地向磁盘flush StoreFile文件,会对读性能造成影响,导致性能变慢,因为每个读操作都需要打开所有的StoreFile文件,并且合并查询,compact做的操作就是将多个文件中的内容合并,是Famliy上的操作。

Page 23: HFile,Compact And Split of HBase

HBase Compact

There are two types of compactions: minor and major.

Minor compactions will usually pick up a couple of the smaller adjacent StoreFiles and rewrite them as one. Minors do not drop deletes or expired cells, only major compactions do this.

Sometimes a minor compaction will pick up all the StoreFiles in the Store

and in this case it actually promotes itself to being a major compaction.

Page 24: HFile,Compact And Split of HBase

HBase Compact

主要入口:    HregionServer启动时,会启动一个任务,定期扫描RegionServer托管的所有Hregion下面的所有store,检查是否需要进行compact.

在不做配置的情况下10000s,大概3个小时左右check一次。

see : org.apache.hadoop.hbase.regionserver.CompactionChecker;

Page 25: HFile,Compact And Split of HBase

HBase Compact HStore中StoreFIles的个数  –  正在执⾏行CompacYng的文件个数  >  minFilesToCompact  org.apache.hadoop.hbase.regionserver.compacYons.RaYoBasedCompacYonPolicy    minor  CompacYon条件  

判断是否需要major_compact  :public  boolean  isMajorCompacYon(final  CollecYon<StoreFile>  filesToCompact)  

Page 26: HFile,Compact And Split of HBase

HBase Compact 如果符合条件,则由CompactSplitThread.requestSystemCompaction发起compact请求; 接着:

1、selectCompaction(r, s, priority, request),选取需要合并的StoreFile文件列表,作为compact候选者.<到 后过小于 小数,则结束,大于 大数则取其子集进行compact>

2、pool.execute(new CompactionRunner(s, r, compaction, pool)),执行compact

Page 27: HFile,Compact And Split of HBase

HBase Compact select StoreFileToCompct:

1.  选出待执行Compact的storefiles。由于在Store中的文件可能已经在进行Compacting,因此,这里取出未执行Compacting的文件,将其加入到Candidates中。

2.  执行compactSelection,在Candidates中选出需要进行compact的文件,并封装成CompactSelection对象当中。

•  选出过期的store files•  过滤对于大文件进行Compaction操作。判断fileToCompact队列中的文件是否超过了

maxCompactSize,如果超过,则过滤掉该文件,避免对于大文件进行compaction。•  判断是否需要进行major_compact,判断上次进行majorCompaction到当前的时间间隔,

如果超过设置值等。

•  如果不是major 则执行下面算法,筛选出需要合并的StoreFile;

-----http://hbase.apache.org/book/regions.arch.html#compaction,这样做使得Compaction尽可能工作在 近刷入hdfs的小文件的合并,从而使得提高Compaction的执行

效率。

Page 28: HFile,Compact And Split of HBase

HBase Compact 合并过程:

1、根据StoreFileScanner 列表等参数,创建InternalScanner (这是一个StoreScanner)

2、生成StoreFile.Writer 负责向 ./tmp目录下写新的StoreFile.

3、performCompaction(scanner, writer, smallestReadPoint) 执行合并操作,将数据写到./tmp,关闭writer,生成新生成的StoreFile。

4、moveCompatedFilesIntoPlace(cr, newFiles);移动到相应Store的目录下

5、删掉旧的StoreFiles .this.fs.removeStoreFiles(this.getColumnFamilyName(), compactedFiles)

备注:StoreScanner的next方法会ScanQueryMatcher.MatchCode qcode = matcher.match(kv);过滤掉一些不符合要求的KeyValue,比如Major的delete等

Page 29: HFile,Compact And Split of HBase

HBase Compact 一些配置参数  

Page 30: HFile,Compact And Split of HBase

HBase Compact 总结:

HBase的合并操作其实就是扫描各个StoreFile并将其写入一个较大的文件,之后用这个大的StoreFile文件替换到之前的多个小文件。

1、在实际使用过程中,通常会禁用major Compact,在集群压力小的时候,定时天/周/月 进行compact操作

2、合并过程不影响读写服务。

3、根据应用的需求设置ttl,并且设置minVersions=0,根据selectCompation优选清理过期不保留版本的文件的策略,这样会使得这部分数据在CompactionChecker的周期内被清理。

http://wiki.sankuai.com/pages/viewpage.action?pageId=77466463

Page 31: HFile,Compact And Split of HBase

HBase Split Why  Hbase  needs  split?    

�A table typically consists of many regions, which are in turn hosted by many region servers. Thus, regions are the physical mechanism used to distribute the write and query load across region servers. When a table is first created, HBase, by default, will allocate only one region for the table. This means that initially, all requests will go to a single region server, regardless of the number of region servers. This is the primary reason why initial phases of loading data into an empty table cannot utilize the whole capacity of the cluster.

�实现较为复杂,涉及到旧Region下线,以及新的Region上线。

Page 32: HFile,Compact And Split of HBase

HBase Split 入口:

�compactSplitThread.requestSplit(region)

Page 33: HFile,Compact And Split of HBase

HBase Split 判断是否分裂主要通过RegionSplitPolicy接口:其实现有ConstantSizeRegionSplitPolicy, IncreasingToUpperBoundRegionSplitPolicy, KeyPrefixRegionSplitPolicy

•  0.94之前版本默认分裂策略为ConstantSizeRegionSplitPolicy,只是简单的判断下store.getSize() > desiredMaxFileSize ,可以通过“hbase.hregion.max.filesize"进行

配置,default10GB •  0.94之后默认的为IncreasingToUpperBoundRegionSplitPolicy,判断策略: Min (R^2 *

“hbase.hregion.memstore.flush.size”, “hbase.hregion.max.filesize”),R代表当前table在这个regionserver上面所有在线的region的个数。假如 memStoreSize 为128M,则第一次split为128M,之后 512MB, 1152MB, 2GB, 3.2GB, 4.6GB, 6.2GB, etc. 当第9次分裂之后,大小增大到10G之后,则达到10G进行分裂。所以分裂时机和这个hregionServer负责的

region的个数有很大关系。 •  splitKey均为midKey,通过DataBlockIndex获取 •  如果我们能大体遇见key的分布,并且不希望表经常分裂,可以建表时分裂策略采用

ConstantSizeRegionSplitPolicy,并且设置hbase.hregion.max.filesize为一个很大的值。

Page 34: HFile,Compact And Split of HBase

HBase Split 总体步骤:

SplitTransaction.execute,真正进行split的代码:

第一步:createDaughters,第二步:openDaughters,第三步: transitionZKNode。

Page 35: HFile,Compact And Split of HBase

HBase Split

create  daughter    1、创建znode节点,/hbase/region-­‐in-­‐transiYon/region-­‐name      2、因为HMater是 /hbase/region-­‐in-­‐transiYon的观察值,进而更新这个region的信息。    3、RegionServer在当前region目录下创建.splits/子目录    4、HRegionServer  close  ParentHRegion,同时将MemStore里的数据Flush到磁盘,此时client对这个Region的读取和写入操作已经得不到响应了,    5、生成daughter  A 和 B 的Reference  ,并存放在 .splits/[daughter]_EncodedName/familyName/storefileName.RegionEncodedName下,分别指向parent的上半部分和下半部分。    6、创建真正的region目录,并将生成的A和B  Reference文件拷贝到相应目录下,ef文件移动到正常目录下,参考HReionFileSystem  以下方法,其实就是一个mv操作。  

Page 36: HFile,Compact And Split of HBase

HBase Split

open  daughter      1、向.meta.表发起写请求,标注parent  region已经下线    2、初始化daughter  region    3、daughter的信息写入.meta.表。  

Page 37: HFile,Compact And Split of HBase

HBase Split

transiYonZKNode    1、修改zookeeper  /hbase/region-­‐in-­‐transiYon/region-­‐name/SPLIT  ,Hmaster分派daughter  region,进行负载均衡等。      2、对Reference文件执行compact操作,形成真正的HFile,  

Page 38: HFile,Compact And Split of HBase

HBase Split

Page 39: HFile,Compact And Split of HBase

HBase Split 一些经验:

•  根据使用场景采取不同的分裂策略:如果我们知道key的分布,可以采用预分区,并采用ConstantSizeRegionSplitPolicy分裂策略,并将分裂条件罚值设的大些如果不知道key的分布,就采用IncreasingToUpperBoundRegionSplitPolicy,且不采用预分区,开始只生成一个region,然后让其自行分裂。

•  禁用split,将region大小设置成较大值,参考值100G�

Page 40: HFile,Compact And Split of HBase

Thanks