hbase的一些问题总结

hbase的两个基本问题点

单个值是怎样存储在HBase的表中的

Table和Region

一个table可以理解成一个大的hashMap,这些hashMap是分布式存储的
table的最基本单元是Region,一个table是一个或多个Region,一个Region有很多的Column Family,Column Family里又有很多的Store,一个Store又有Memory Store和很多的HFile
Region的划分配置(控制每一个Region的大小,hbase-site.xml):

 <property>
       <name>hbase.hregion.max.filesize</name>
        <value>52428800</value> # 50M  默认是10G,生产上一般都是10G,所以这个可以不改,如果你是学习,可以根据你的需求来改
 </property>

下图就是代表只有一个region:
在这里插入图片描述
从table到region:
1.Region都是分布在所有的HRegionServer上的
2.每一个Region负责管理和存储一个Table中的某段数据
3.每一个table的RowKey是按照字符串的自然顺序升序排列的

从Region -> Column Family
1.一个Region负责管理和存储Table中所有的Column Family数据
2.一个Region负责管理和存储一个或者多个Column Family的数据

从Column Family -> Store
1.一个Column Family对应着一个Store(可以理解为一个java的类)
2.一个Store中含有一个MemoryStore和若干个HFile(就是hdfs里的一个文件)

从HFile -> Block
1.一个HFile含有若干个不同类型的Block(hbase里的不是hdfs里的)
2.Block的大小通常为8K到1MB,默认的大小是64KB
3.Block的类型有:Data Blocks(存储数据的)、Index Blocks(储存这个数据的索引的)、Bloom filter Blocks(存储过滤器的)以及Trailer block(用于追踪源数据的)
Block -> KeyValue
一个Block包含一个magic数字和若干个KeyValue的数据(如果key-value的大小到64K就会组成一个block)

查看HFile的内容
hbase org.apache.hadoop.hbase.io.hfile.HFile -f /hbase/data/namespace的名字/表名/Region的名字/字段名/对应的数据文件名(这些可以在hdfs的监控界面,比如master:50070/hbase 下去找) -p(是打印的意思) -b(打印index的信息) -m(打印元数据信息) pbm是通过hbase org.apache.hadoop.hbase.io.hfile.HFile去查看的
可以直接追加到文件中去看,加上 >> hfile.txt 这个文件名字是随便起的

一个HFile有若干个DataBlock 一个block index(这个是是用于随机读写的) 一个MetaData(文件的元数据
) 一个Trailer(文件数据的追踪者)一个FileInfo(文件信息)一个Bloom Filter(Bloom过滤器信息数据)
就好比一本书,datablock是书的内容,其他的都是书的相关信息

一个table的分布式存储单元就是region,就比如hdfs的最基本存储单元是block一样

这些值是怎么一起存储在文件中而组成一张表的

Block Encoder
1.Prefix,很慢
2.Diff,也很慢
3.Fast Diff 如果你的rowkey很长,并且有很多的Column的话,则推荐使用Fast Diff
一些文字解释请参考https://www.jianshu.com/p/a62e49f749f3
Block Compressors
1.none
2.Snappy
3.LZO
4.LZ4
5.GZ
怎么选择Block Encoders 和 Compressors
1、如果rowkey很长的话或者这个column family含有很多的column的话,则使用Block Encoder
推荐使用Fast Diff
2、如果value很大的话,则需要使用Block Compressors
3、对于访问不频繁的数据(code data),使用GZ压缩器,因为GZ需要更多的cpu资源,但是有很好的压缩率
4.对于访问频繁的数据(hot data),使用Snappy或者LZO压缩器,
因为Snappy或者LZO不需要更多的cpu资源,但是压缩率没有GZ高
5.大部分的场景下默认使用Snappy或者LZO就好,因为他们提供了更好的性能
Snappy比LZO表现还稍微好点
怎么使用:
create ‘tablename’, {NAME => ‘c’, COMPRESSION => ‘SNAPPY’, DATA_BLOCK_ENCODING => ‘FAST_DIFF’}, {NAME => ‘l’}
create ‘tablename’, {NAME => ‘c’, COMPRESSION => ‘GZ’, DATA_BLOCK_ENCODING => ‘FAST_DIFF’}, {NAME => ‘l’}
注意:
Snappy需要自己去装,暂不讲解

Bloom Filter
create ‘tablename’,{NAME => ‘c’, COMPRESSION => ‘GZ’, DATA_BLOCK_ENCODING => ‘FAST_DIFF’},
{NAME => ‘l’, BLOOMFILTER => ‘ROW’}

Bloom Filter取值: NONE, ROW, ROWCOL

ROW: 根据KeyValue中的row来过滤storefile
举个例子:假设有2个storefile文件sf1和sf2,
sf1包含kv1(r1 cf:q1 v)、kv2(r2 cf:q1 v)
sf2包含kv3(r3 cf:q1 v)、kv4(r4 cf:q1 v)
如果设置了CF属性中的bloomfilter为ROW,那么get(r1)时就会过滤sf2,get(r3)就会过滤sf1

ROWCOL:根据KeyValue中的row+qualifier来过滤storefile(会占用存储空间和内存,时间换空间)
举个例子:假设有2个storefile文件sf1和sf2,
sf1包含kv1(r1 cf:q1 v)、kv2(r2 cf:q1 v)
sf2包含kv3(r1 cf:q2 v)、kv4(r2 cf:q2 v)
如果设置了CF属性中的bloomfilter为ROW,无论get(r1,q1)还是get(r1,q2),都会读取sf1+sf2;而如果设置了CF属性中的bloomfilter为ROWCOL,那么get(r1,q1)就会过滤sf2,get(r1,q2)就会过滤sf1

hbase的读写路径

客户端是怎么找到对应的Region的

1.客户端连接zk集群,来获取hbase:meta数据所在的RegionServer
2.去hbase:meta数据所在的RegionServer,根据RowKey(table与其对应的regionID组成)与找到的meta中所属表的StartKey和EndKey对比找到该RowKey所在的RegionServer上
3.做相关的操作

Memory Store(写缓存机制)

1.客户端向hbase集群发起一个写的请求
2.获取hbase:meta对应RS所在机器
3.客户端向对应的RegionServer发起写请求
4.RegionServer发起请求到对应的HRegion
5.HRegion向Store发起写的请求

6.Store向MemoryStore发起写请求
7.如果MemoryStore满了,会flush数据到HFile

6 ->7 的条件是:
Memory Store Flush的单位是:Region
1、当一个Region中所有MemoryStore内存之和大于hbase.hregion.memstore.flush.size(默认大小是:134217728字节(128M))的时候,这个MemoryStore所在的Region中的所有MemoryStore都会写到磁盘
2.当一个HRegionServer中所有的MemoryStore加在一起的大小大于hbase.regionserver.global.memstore.upperLimit默认大小是堆内存的40%,那么这个HRegionServer中的所有的Region中的内存数据都会flush到磁盘中,当所有的内存使用达到hbase.regionserver.global.memstore.lowerLimit的时候就不会flush了
当然你也可以手动flush -> flush 表名

写路径中的WAL

因为很多原因可以导致你的机器挂掉,因此,需要有这个个机制来保证数据的准确性等
在上一个写缓存机制的第5->6之间我们需要写一个HLog,先把数据写到HLog中去,这样就可以防止数据丢失
1.HRegionServer中的LogSyncer的sync方法,其功能就是用于同步缓存在RegionServer上的HLog到HDFS的,这个会占用一定的时间,如果你觉得你的数据不是那么重要的话是可以将其关闭的,默认是开着的
2.HRegionServer中的LogRoller的rollWriter方法,其作用是用户滚动日志的,使得日志文件数量以及文件大小不会太大
3.数据的恢复,recovered.edits(它不需要人工恢复,会自动的恢复)
因此上面的写缓存机制的步骤应该是在第5之前加上一个预写日志的操作

读缓存机制 - BlockCache

这个机制主要是为了提高读的速度而设置的,一个RS只有一个BlockCache,其大小由hfile.block.cache.size(默认是堆内存的40%)来设置,缓存策略:LruBlockCache(on heap(堆内存)) 和 BucketCache (off heap(直接内存,就是系统内存))
1.客户端向hbase集群发起一个读的请求
2.获取hbase:meta对应RS所在机器
3.客户端向对应的RegionServer发起读请求
4.RegionServer发起请求到对应的HRegion
5.HRegion向Store发起读的请求
6.Store向MemoryStore发起读请求(会先到Memory去拿数据,如果有我们需要的数据就直接返回)
7.如果没有的话,就会去BlockCache(缓存机制)中去拿,如果有就直接返回
8.如果没有的话,才会去HFile中去找,然后读到的数据块放在BlockCache中,然后再返回

LruBlockCache

就是java虚拟机中的堆内存
三种缓存过期策略:
1.FIFO -> 按照“先进先出”的原理来淘汰数据
2.LRU(Least recently used, 最近最少使用) -> 根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”,默认就是它
3.LFU(Least frequently used, 最近不常使用) -> 根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”

LruBlockCache中的三种Block priority:
1、Single access priority : 当一个Block第一次从HDFS中加载到内存中就是这个级别
2.Multi access priority : 当一个Block再次被访问的时候就会变成这个级别
3.In-memory access priority : 当一个cf被设置为In Memory的时候,则不管这个cf的block被访问了多少次都不会从内存中淘汰,比如hbase:meta表中的cf
设置In Memory:
HColumnDescriptor.setInMemory(true);
hbase(main):003:0> create ‘t’, {NAME => ‘f’, IN_MEMORY => ‘true’}

HBase默认使用的缓存策略 - 看下监控界面,或者用desc看表的信息,看In Memory是否为true在这里插入图片描述
除了缓存需要读取的block之外,还需要缓存如下的数据:
1.hbase:meta
2.HFile Indexes
3.Keys(rowkeys)
4.Bloom Filters(原数据信息)

BucketCache

就是不属于java虚拟机的,java管不了的内存,就是系统内存
配置BucketCache:
停止Hbase stop-hbase.sh
1、配置hbase-env.sh
export HBASE_HEAPSIZE=512M
export HBASE_OFFHEAPSIZE=512M
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m -XX:MaxDirectMemorySize=800M"
这里的这个MaxDirectMemorySize一定要比HBASE_OFFHEAPSIZE大就可以了

2.配置hbase-site.xml

<property>
#这个值还可以是heap或者file:/disk1/hbase/cache.data(SSD固态硬盘)
	<name>hbase.bucketcache.ioengine</name>
  	<value>offheap</value>
</property>
<property>
  	<name>hfile.block.cache.size</name>
  	#默认是40% 0.4 之所以配置这个是因为一般来说要和上面的LruBlockCache配合用的,所以一个一办咯
  	<value>0.2</value>
</property>
<property>
  	<name>hbase.bucketcache.size</name>
  	<value>512</value>
</property>

3.同步配置
scp hbase-env.sh hbase-site.xml hadoop-jrq@slave1:~/bigdata/hbase-1.2.6/conf/
scp hbase-env.sh hbase-site.xml hadoop-jrq@slave2:~/bigdata/hbase-1.2.6/conf/
4.启动hbase: start-hbase.sh
5.结果
在这里插入图片描述
在这里插入图片描述
L1:用于缓存Index和Bloom这种META block数据
L2:用于缓存DATA Block,由BucketCache来管理
L1和L2联合起来提供服务叫CombinedBlockCache
L1和L2分别存储不同的数据,相互配合使用
堆外内存的使用不受java控制,所以不会产生垃圾,因此把数据大的存在堆外内存,其更加稳定和性能会有所提高的,因此在生产中,我们一般会用这种方式(我目前用的就是这个加上下面的小案例第二种配置)
6.把BucketCache作为二级缓存使用
配置hbase-site.mxl:

<property>
  	<name>hbase.bucketcache.combinedcache</name>
  	<value>false</value>
</property>

同步slave1和slave2配置
这时候LruBlockCache淘汰的block放到BucketCache中,这样的话去读的时候,从LruBlockCache拿不到数据,就会从BucketCache去再找…

一个HBase内存规划的小案例

假如:一个HBase集群中,每一个HRegionServer所在的主机的物理内存为96G
1.这个集群需要承担的业务负载是:30%读、70%写

读少写多,用MemoryStore + LruBlockCache就可以了
HRegionServer的堆内存大小为64G,系统内存的2/3,留1/3给系统使用
LruBlockCache:30% : 19.2G
Memory Store:45% : 28.8G
other:25%

64G在hbase-env.sh里设置
export HBASE_OFFHEAPSIZE=64G 默认是1G

配置hbase-site.mxl

<property>
#这个就是配置Memory Store,最大是45%
    <name>hbase.regionserver.global.memstore.upperLimit</name>
    <value>0.45</value>
</property>
<property>
#最小的Memory Store是40%
    <name>hbase.regionserver.global.memstore.lowerLimit</name>
    <value>0.40</value>
</property>
<property>
#这就是配置LruBlockCache
    <name>hfile.block.cache.size</name>
    <value>0.3</value>
</property>

这个集群需要承担的业务负载是:70%读、30%写
读多写少,用MemoryStore + BucketCache
分配如图所示,各部分用图表示
在这里插入图片描述
A: 越多越好, 系统内存的2/3 -> 96 * 2/3 = 64G
B: 读缓存:写缓存:其他=5:4:1, 所以B的大小为 A * 50% = 32G
B1: 存储元数据信息,所以设置为B * 10% = 3.2G
B2: 存储数据块信息,所以设置为B * 90% = 28.8G
C: A * 40% = 25.6G
D: A - B2 = 35.2G
LRUBlockCache(B1) + MemStore© < 80% * JVM_HEAP(堆内存大小),否则RS无法启动,这是一个规则
(3.2 + 25.6) / 35.2 = 81.8% > 80% (LRUBlockCache(B1) + MemStore©)/D
(3.2 + 25.6) / 40 = 72% < 80% 因为堆内存(D)大小变动了,因此其他的也要跟着变动
所以最终:B2是24G,D是40G,B是26G
配置:

<property>
**#这个就是配置Memory Store,同上**
    <name>hbase.regionserver.global.memstore.upperLimit</name>
    <value>0.60</value>
</property>
<property>
    <name>hbase.regionserver.global.memstore.lowerLimit</name>
    <value>0.55</value>
</property>
**#配置BucketCache**
<property>
    <name>hbase.bucketcache.ioengine</name>
    <value>offheap</value>
</property>
<property>
    <name>hbase.bucketcache.size</name>
    <value>26624</value>
</property>
<property>
    <name>hbase.bucketcache.percentage.in.combinedcache</name>
    <value>0.90</value>#因为LUR还要占10%
</property>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值