HBase 0.94 --之数据压缩(DataBlock compression,HLog compression)

来源:互联网 发布:文字读取软件在线 编辑:程序博客网 时间:2024/06/05 11:11
众所周知,HBase 0.94对性能做了很多优化,记录一下个人对其实现细节及如何更好应用的理解。 


0.94引入了两个在HBase层的数据压缩: 

一.DataBlock compression 

1.1 作用 
DataBlock compression指的是对HFile v2中的Data Block进行压缩,Data Block既存储在Disk上(HDFS中),也会存在于LRU Cache中,所以此压缩特性支持: 
a)Disk、Cache上都不开启 
b)Disk、Cache上都开启 
c)Cache上开启,Disk上开启 
但不支持 
d)Cache上不开启,Disk开启 

由此可见,此压缩特性的作用是: 
a)节省LRU Cache的空间使用,提升cache命中率,优化读性能 
b)节省Disk空间使用 

当然,前者是主要目的,后者我们有对HFile的全局压缩算法,如LZO 

1.2 副作用 
目前,DataBlock压缩特性默认是关闭的,显然,其能优化某些业务场景,但盲然使用肯定会带来副作用: 
a)Data Block解压缩,(如果一个Block(默认64KB)中包含很多KV,这个开销会比较大) 
b)某些场景,压缩后数据更大 

1.3 压缩算法 
a)PREFIX 
向Block中写入KV时,和前一条KV比较Key(这里的Key=Row+Family+Qualifier+Timestamp+Type,具体可见附件),对于相同的前缀byte, 则不再重复写入 
根据KeyValue结构(见附件),某KV具体压缩后的内容: 
*KeyLength压缩为1~5个字节(使用7-bit encoding,见附注) 
*ValueLength压缩为1~5个字节 
*和上个KV比较Key的内容,写入相同的前缀byte的长度,1~5个字节 
*除相同前缀部分,剩余的Key内容 
*Value内容 

在最坏情况下,一条KV经过此算法压缩后会大小会增加3个字节 

b)DIFF 
向Block中写入KV时,会和前一条KV进行全面比较(如Key长度,value长度,Row,timestamp,type),对于相同的信息则不再写入,同时KV中的family内容只写一次(因为同个Block中,他们的family肯定是相同的) 
某KV具体压缩后的内容: 
*一个字节的flag(这个flag的作用后面解释) 
*如果和上个KV的Key长度不一样,则写入1~5个字节的KeyLength 
*如果和上个KV的Value长度不一样,则写入1~5个字节的KeyLength 
*和上个KV比较Key的内容,写入相同的前缀byte的长度,1~5个字节(此比较不包含timestamp和type,而PREFIX算法中是包含的) 
*剩余的Row内容(如果相同前缀比较少) 
*如果是第一条KV,写入family内容 
*剩余的qualifier内容 
*写入1~8字节的timestamp或者与上个KV的timestamp的差(是原值还是写与上个KV的差,取决于哪个字节更小) 
*如果和上个KV的type不一样,则写入1字节的type 
*Value内容 

在解压缩时,怎么判断和上个KV的Key长度是否一样,Value长度是否一样,写入的timestamp是原值还是差呢等等,这些都是通过最早写入的1个字节的flag来实现的, 
这个字节中的8位bit,含义是: 
第0位,如果为1,Key长度一样 
第1位,如果为1,Value长度一样 
第2位,如果为1,type一样 
第3位,如果为1,则写入的timestamp是差值 
第4,5,6位,这3位组合起来的值(能表示0~7),表示写入的timestamp或差值的字节数 
第7位,如果为1,表示写入的timestamp或差值取反了(比如timestamp差值为负数,为了节省空间,会写入绝对值) 

由此可见,DIFF算法是针对KeyValue的结构而量身设计的 

c)FAST_DIFF 
FAST_DIFF与DIFF的原理一样,只是减小了压缩量,提升了压缩速度, 
某KV具体压缩后的内容: 
*一个字节的flag 
*如果和上个KV的Key长度不一样,则写入1~5个字节的KeyLength 
*如果和上个KV的Value长度不一样,则写入1~5个字节的KeyLength 
*和上个KV比较Key的内容,写入相同的前缀byte的长度,1~5个字节(此比较不包含timestamp和type,而PREFIX算法中是包含的) 
*剩余的Row内容(如果相同前缀比较少) 
*如果是第一条KV,写入family内容 
*剩余的qualifier内容 
*写入1~8字节的timestamp 
*如果和上个KV的type不一样,则写入1字节的type 
*如果和上个KV的Value内容不一样,则写入Value内容 

1个字节的flag的8位bit含义: 
第0,1,2位,这3位组合起来的值(能表示0~7),表示写入的timestamp的字节数 
第3位,如果为1,Key长度一样 
第4位,如果为1,Value长度一样 
第5位,如果为1,type一样 
第6位,如果为1,Value内容一样 
第7位,闲置... 

由此可见,相比DIFF,FAST_DIFF只是减少了对timestamp的压缩,但是增加了Value内容是否一样的判断,在某些情景(如value只是用来计数,或者value是一种类型选项值),那么可以大幅减少相同value内容的重复写入 

1.4 应用场景及如何配置 
上面介绍了3种压缩算法的原理,由此可简单分析下他们的应用场景: 
1)PREFIX,这是一个比较公用的压缩算法,其压缩过程也比较简单快速,通用于存在相同的Row前缀的情景 

2)DIFF, 相比于PREFIX,同样是需要应用在存在相同的Row前缀的情景,但其只写一份family内容,写入timestamp的差值,比较长度是否一样等特性,使其压缩幅度会更大,当然压缩的CPU开销也会稍大 

3)FAST_DIFF,和DIFF类似,但是对于存在相同Value内容的场景,那肯定是使用它了 

空口无凭,实验为据,具体场景,数据为准 

如何配置? 
Data Block的压缩算法选择是表中的一个列族属性,你可以通过api HColumnDescriptor#setDataBlockEncoding来开启或关闭或更改压缩算法,另外在开启压缩时,你可以通过HColumnDescriptor#setEncodeOnDisk决定是否在写入Disk时也采用压缩 


二.HLog compression 

2.1 为什么使用HLog压缩 
为了保证数据安全性,每put一次,都会写入一条hlog记录,每一条hlog记录都会包含:table name、region name、row、family、qualifier等,如果数据写入集中在某表、某region乃至某row、某family,那么HLog的文件中就会存在大量重复的内容,压缩由此而生 

2.2实现原理 
HLog压缩采用的是词典压缩法,其写入一条log记录时的压缩行为: 
*查找table是否在table词典中,如果不是,该table name写入到hlog 文件中,并加入到table词典中,对应一个short值;如果是,则hlog文件中写入一个short值,以代表该table name 
*region family qualifier row,也是按照上述方法写入到hlog文件中 
所以,写一个hlog文件时,会维护5个词典,即table词典、region词典、family词典、qualifier词典、row词典 


2.3 作用 
压缩的作用自然是减小hlog记录的写入大小,加快写hlog的速度,提升写性能;但是,个人认为,单条hlog记录压缩后减少几十或上百字节,对于其本身就不大而言,并不能提高多少HBase的写数据速度。 
不过,其还存在着一个侧面作用,增加单个hlog文件的数据记录量,这会一定程度上提高memstore的内存使用率,从而提升全局的flush效率、compaction效率。 

2.4如何配置及应用场景 
Server端修改配置hbase.regionserver.wal.enablecompression为true(默认false)开启HLog压缩特性 

应用场景: 
*数据写入比较分散在各个表,各个region的,就不要考虑了 
*数据写入比较集中的可以考虑开启,但测试数据为准,如果写性能没啥优化,那还是别尝这个鲜了,新特性免不了会有风险 


以上只是个人见解,欢迎指正 

附注: 
7-bit 压缩法,针对Integer数据的一种压缩算法,可以将4个字节的Int型数据压缩为1~5个字节,数值越小,压缩后的字节数越少,所以对值小的Int型数据会有比较好的压缩效果,其具体压缩原理,简单介绍如下: 
1.将一个Int型数据转换成32位; 
2.0~7位,按原值写入 
3.如果原值的第8位及以后存在1,则写入1,否则写入0,结束写入(即压缩为了1个字节) 
4.如果没结束,则写入原值的第8~14位,如果原值的第15位及以后存在1,则写入1,否则写入0,结束写入 
5...重复上述行为,直到写完 

KV结构图: 
 

HFileV2结构 
0 0
原创粉丝点击