Hbase读写流程

Hbase读写数据流程

regionserver

HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个HStore组成,每个HStore对应了Table中的一个Column Family的存储,

可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效

HStore存储由两部分组成,一部分是MemStore(内存),一部分是StoreFiles(磁盘)

容错与恢复

每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中,HLog文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据)

 

WAL就像日志中心一样,它被同一个region server中的所有region共享。
当客户端启动一个操作来修改数据,该操作便会被封装成一个KeyValue对象实例中,并通过RPC调用发送出去。
这些调用成批的发送给含有匹配region的HRegionServer。一旦KeyValue到达,它们会被发送到管理相应行的HRegion对象实例。数据便被写入到WAL,然后放入到实际拥有记录的存储文件的MemStore中。
最后当memstore达到一定的大小或者经历一个特定时间之后,数据就会异步地连续写入到文件系统中。
在写入的过程中,数据以一种不稳定的状态存放在内容中,即使在服务器完全崩溃的情况下,WAL也能够保证数据不丢失,因为实际的日志存储在HDFS上。其他服务器可以打开日志然后回放这些修改。

当HRegionServer意外终止后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应region的目录下,然后再将失效的region重新分配,领取到这些region的HRegionServer在LoadRegion的过程中,会发现有历史HLog需要处理,因此会ReplayHLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复

每个Region Server维护一个Hlog,而不是每个Region一个。

这样做的目的是不断追加单个文件相对于同时写多个文件而言,可以减少磁盘寻址次数,因此可以提高对table的写性能。

带来的麻烦是,如果一台Region Server下线,为了恢复其上的Region,需要将Region Server上的log进行拆分,然后分发到其它Region Server上进行恢复。

 

1 客户端寻找HRegionServer,及缓存位置信息

 

从这个过程中,我们发现客户会缓存这些位置信息,然而第二步它只是缓存当前RowKey对应的HRegion的位置,因而如果下一个要查的RowKey不在同一个HRegion中,则需要继续查询hbase:meta所在的HRegion,然而随着时间的推移,客户端缓存的位置信息越来越多,以至于不需要再次查找hbase:meta Table的信息,除非某个HRegion因为宕机或Split被移动,此时需要重新查询并且更新缓存。

2 写数据流程

1)通过2.3.1 找到该写数据最终需要去的HRegionServer;

2)然后客户端将写请求发送给相应的HRegionServer,在HRegionServer中它首先会将该写操作写入WAL(Hlog)日志文件中(Flush到磁盘中)。

3)写完WAL日志文件后,HRegionServer根据Put中的TableName和RowKey,startkey、endkey找到对应的HRegion,并根据Column Family找到对应的HStore,并将Put写入到该HStore的MemStore中。此时写成功,并返回通知客户端。

 

写入MemStore后的操作:

存入MemStore,一直到MemStore满 

Flush成一个StoreFile,直至增长到一定阈值

→ 触发Compact合并操作 -> 多个StoreFile合并成一个StoreFile,同时进行版本合并和数据删除

→ 当StoreFiles Compact后,逐步形成越来越大的StoreFile

→单个StoreFile大小超过一定阈值(Region split 阈值)后,触发Split操作,把当前Region Split成2个Region,Region会下线,新Split出的2个子Region会被HMaster分配到相应的HRegionServer上,使得原先1个Region的压力得以分流到2个Region上;

 

什么时候执行MemStore Flush?

1)当一个MemStore的大小超过了hbase.hregion.memstore.flush.size的大小,此时当前的HRegion中所有的MemStore会Flush到HDFS中,不阻塞写操作。(Region级别的flush)

2)当全局MemStore的大小超过了hbase.regionserver.global.memstore.upperLimit(默认0.4,memstores所占最大堆空间比例)的大小,此时当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,阻塞写操作。(RS级别的flush)

3)当一个Region的MemStore总量达到hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size(默认2*128M=256M)时,会阻塞这个region的写操作,并强制刷写到HDFS。

触发这个刷新只会发生在MemStore即将写满128M时put了一个巨大的记录的情况,这时会阻塞写操作,强制刷新成功才能继续写入。(Region级别的flush)

4)当前HRegionServer中HLog的大小超过阈值,当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中。(RS级别的flush)

 

3 读数据流程

1)通过2.3.1 找到要读的数据的HRegionServer。

2)根据读取的TableName和RowKey的startkey 、 endkey 找到对应的HRegion。

4)每个regionserver只有一个blockcache(读缓存),读取数据时,先到memestore上读数据,找不到再到blockcahce上找数据,再查不到则到磁盘(storefile)查找,并把读入的数据同时放入blockcache。

 

4 Region拆分策略

Region概念

一个Table由一个或多个Region组成

一个Region由一个或者多个Store组成,每个store保存一个columns family;

一个Strore又由一个memStore和0至多个StoreFile 组成。memStore存储在内存中, StoreFile存储在HDFS上。

 

Region大小考量的因素

1)机器个数多,Region个数少,浪费机器,region数目太少就会妨碍可扩展性,降低并行能力,导致压力不够分散;

2)region小,数目太多就会造成性能下降;

 

Region拆分策略

HRegionServer拆分region的步骤是,先将该region下线,然后拆分,将其子region加入到hbase:meta表中,再将他们加入到原本的HRegionServer中,最后汇报Master。

 

split前

hbase:meta:   region_p

split中

region_p  ---> region1

                       region2

在 region_p  对应的hdfs目录下生成.splits 目录, 里面创建 两个子region的引用文件

tablename/region_p_md5/.splits/region1 引用文件

                                                   /region2 引用文件

在表目录下创建子region对应的hdfs目录, 把引用文件拷贝到 指定region目录下

tablename/region1_md5/region1 引用文件

                 /2region_md5/region2 引用文件

split后

把子region往hbase:meta表里写

hbase:meta

region_p

region1

region2

两个子region从父region获取数据,当数据获取完,删除相应的引用文件

汇报hmaster

可以通过设置RegionSplitPolicy的实现类来指定拆分策略,RegionSplitPolicy类的实现类有:

 

ConstantSizeRegionSplitPolicy
IncreasingToUpperBoundRegionSplitPolicy
DelimitedKeyPrefixRegionSplitPolicy
KeyPrefixRegionSplitPolicy

其中:

ConstantSizeRegionSplitPolicy

仅当region大小超过常量值(hbase.hregion.max.filesize大小,默认为10G)时,才进行拆分。

 

IncreasingToUpperBoundRegionSplitPolicy

默认region split策略。即当同一table在同一regionserver上的region数量在[0,100)之间时按照如下的计算公式算,否则按照上一策略计算:

Min (R^3* "hbase.hregion.memstore.flush.size"*2, "hbase.hregion.max.filesize")

        R为同一个table中在同一个regionserver中region的个数,

        hbase.hregion.memstore.flush.size默认为128M,

        hbase.hregion.max.filesize默认为10G。

第一次分裂:    1*1*1*128*2 = 256 --> 1 --> 2

第二次分裂:  2*2*2*128*2 = 2048 --> 2 --> 4

第三次分裂 : 4 * 4 * 4 * 128 * 2

一个表的region 越分越多 --> hmaster --> 平衡 --> RS --> region 移动(慢)

预分 region 表 数据 --> 够大 -- 分region

表 --> 分出region --> rowkey(范围识别) --> hive的分区 先分区 再存储 数据

 

 

DelimitedKeyPrefixRegionSplitPolicy

保证以分隔符前面的前缀为splitPoint,保证相同RowKey前缀的数据在一个Region中。如果定义rowkey时,采用'_'作为字段分隔符(如:userid_eventid),则采用该策略拆分之后,能够确保具有相同userid的记录隶属于同一Region。

假设分割字段是 “_”

userid_eventid     -->    userid

userid_aaaid

username_aaa    --->   username

username_bb

 

KeyPrefixRegionSplitPolicy                    

保证具有相同前缀的row在一个region中(要求设计中前缀具有同样长度)。指定rowkey前缀位数划分region,通过读取table的prefix_split_key_policy.prefix_length属性,该属性为数字类型,表示前缀长度,在进行split时,按此长度对splitPoint进行截取。

此种策略比较适合固定前缀的rowkey。当table中没有设置该属性,或其属性不为Integer类型时,指定此策略效果等同与使用IncreasingToUpperBoundRegionSplitPolicy。

假设 prefix_split_key_policy.prefix_length=9

userid001_aaa      -->    userid001

userid001_bbb

userid002_aaa      -->    userid002

userid002_bbb

 

 

配置拆分策略

hbase配置文件中定义全局的拆分策略,设置hbase.regionserver.region.split.policy;也可以在创建和修改表时候指定。

如果想关闭自动拆分改为手动拆分,建议同时修改hbase.hregion.max.filesize和hbase.regionserver.region.split.policy值。

如果关闭自动拆分策略需要把 hbase.hregion.max.filesize 设置非常大,再采用手动。

Hbase读写流程Hbase读写流程 爱吃芝麻 发布了107 篇原创文章 · 获赞 0 · 访问量 1240 私信 关注
上一篇:Hbase架构原理解析


下一篇:吴裕雄--天生自然HADOOP操作实验学习笔记:hbase的shell应用v2.0