HBase的原理剖析

先上一张图,看了很多别人传的系统架构图,都是直接照搬其他人的,有错误也不知道,简直是误人子弟!
在里插入图片描述其中在每个HRegionServer上只有一个HLog,而不是在每个HRegion上都有一个HLog,这样容易造成其他人在理解上的偏差。

client的职责:

第 1 步:Client 请求 ZooKeeper 获取.META.所在的 RegionServer 的地址。
		.META.:记录了用户所有表拆分出来的的 Region 映射信息,.META.可以有多个 Regoin
第 2 步:Client 请求.META.所在的 RegionServer 获取访问数据所在的 RegionServer 地址,Client
		会将.META.的相关信息 cache 下来,以便下一次快速访问。
第 3 步:Client 请求数据所在的 RegionServer,获取所需要的数据

在这里会有一个问题,那就是 Client 会缓存.META.的数据,用来加快访问,既然有缓存,那它什么时候更新?
如果.META.更新了,比如 Region1不在RerverServer2上了,被转移到了RerverServer3上。Client 的缓存没有更新会有什么情况呢?

其实,Client 的元数据缓存不更新,当.META.的数据发生更新。如上面的例子,由于 Region1的位置发生了变化,Client 再次根据缓存去访问的时候,会出现错误,
当出现异常达到重试次数后就会去.META.所在的 RegionServer 获取最新的数据,如果.META.所在的 RegionServer也变了,Client 就会去 ZooKeeper 上获取.META.所在的 RegionServer 的最新地址

其实这也是region的一种寻址方式!!!(client要对某一行数据做读写的过程)

ZooKeeper的职责:

1、ZooKeeper为HBase提供 Failover 机制,选举 Master,避免单点 Master 单点故障问题
2、存储所有 Region 的寻址入口:.META.表在哪台服务器上,.META.这张表的位置信息
3、实时监控 RegionServer 的状态,将 RegionServer 的上线和下线信息实时通知给 Master
4、存储HBase的Schema,包括有哪些Table,每个Table有哪些Column Family

Master的职责:

1、为 RegionServer 分配 Region
2、负责 RegionServer 的负载均衡
3、发现失效的 RegionServer 并重新分配其上的 Region
4、HDFS 上的垃圾文件(HBase)回收
5、处理 Schema 更新请求(表的创建,删除,修改,列簇的增加等等)

RegionServer的职责:

1、RegionServer 维护 Master 分配给它的 Region,处理对这些 Region 的 IO 请求
2、负责和底层的文件系统 HDFS 的交互,存储数据到 HDFS
3、负责 Store 中的 HFile 的合并工作
4、RegionServer 负责 Split 在运行过程中变得过大的 Region,负责 Compact 操作

以上可以看到,client 访问 HBase 上数据的过程并不需要 Master 参与(寻址访问 ZooKeeper 和
RegioneServer,数据读写访问 RegioneServer),Master 仅仅维护Table 和 Region 的元数据
信息,负载很低。
.META. 存的是所有的 Region 的位置信息,那么 RegioneServer 当中 Region 在进行分裂之后
的新产生的 Region,是由 Master 来决定发到哪个 RegioneServer,这就意味着,只有 Master
知道 new Region 的位置信息,所以,由 Master 来管理.META.这个表当中的数据的 CRUD
所以结合以上两点表明:

在没有 Region 分裂的情况,Master 宕机一段时间是可以忍受的。

物理架构

1、Table 中的所有行都按照 RowKey 的字典序排列。
2、Table 在行的方向上分割为多个 HRegion。
3、HRegion 按大小分割的(默认 10G),每个表一开始只有一个 HRegion,随着数据不断插入表,HRegion 不断增大,当增大到一个阀值的时候,HRegion 就会等分会两个新的 HRegion。 当表中的行不断增多,就会有越来越多的 HRegion。 
4、HRegion 是 Hbase 中分布式存储和负载均衡的最小单元。最小单元就表示不同的 HRegion可以分布在不同的 HRegionServer 上。但一个 HRegion 是不会拆分到多个 server 上的(也就是没有hdfs中block的副本功能)。
5、HRegion 虽然是负载均衡的最小单元,但并不是物理存储的最小单元。事实上,HRegion由一个或者多个 Store 组成,每个 Store 保存一个 Column Family。每个 Strore 又由一个MemStore 和 0 至多个 StoreFile 组成
   写操作先写入memstore中,当memstore达到一定的阈值时,HRegionServer会启动flushcache进程写入到storefile中,每次写入形成单独的一个hfile,
   当storefile达到一定的阈值时,会把当前的region分裂成两个region,并由master把新分裂出来的region分配到相应的HRegionServer服务器上,实现负载均衡。
   客户端在检索数据时,先在memstore中查找,没有再到storefile中查找。
6、每个 Region Server 维护一个 HLog,而不是每个 Region 一个。这样不同 region(来自不同 table)的日志会混在一起,这样做的目的是不断追加单个文件相对于同时写多个文件而言,可以减少磁盘寻址次数,因此可以提高对 table 的写性能。
   带来的麻烦是,如果一台 region server下线,为了恢复其上的 Region,需要将 RegionServer 上的 log 进行拆分,然后分发到其它RegionServer 上进行恢复

读写过程:

读请求过程:
<1>、client通过ZK找到.META.表所在的HRegionServer,client通过.META.表所在的HRegionServer找到所需数据的HRegionServer
<2>、然后到数据所在的HRegionServer上获取相关数据
<3>、HRegionServer 定位到目标数据所在的 Region,发出查询请求
<4>、Region 先在 Memstore 中查找,命中则返回
<5>、如果在 Memstore 中找不到,则在 Storefile 中扫描
	为了能快速的判断要查询的数据在不在这个 StoreFile 中,应用了 BloomFilter

BloomFilter,布隆过滤器:迅速判断一个元素是不是在一个庞大的集合内,但是他有一个弱点:它有一定的误判率
误判率:原本不存在与该集合的元素,布隆过滤器有可能会判断说它存在,但是,如果布隆过滤器,判断说某一个元素不存在该集合,那么该元素就一定不在该集合内

写请求过程:
<1>、Client 先根据 RowKey 找到对应的 Region 所在的 RegionServer
<2>、Client 向 RegionServer 提交写请求
<3>、RegionServer 找到目标 Region
<4>、Region 检查数据是否与 Schema 一致
<5>、如果客户端没有指定版本,则获取当前系统时间作为数据版本
<6>、将更新写入 WAL Log
<7>、将更新写入 Memstore
<8>、判断 Memstore 的是否需要 flush 为 StoreFile 文件
Hbase 在做数据插入操作时,首先要找到 RowKey 所对应的的 Region,怎么找到的?其实这个简单,因为.META.表存储了每张表每个 Region 的起始 RowKey 了。

在实际生产中注意:在做海量数据的插入操作,应该避免出现递增 rowkey 的 put 操作,
如果 put 操作的所有 RowKey 都是递增的,那么试想,当插入一部分数据的时候刚好进行分裂,那么之后的所有数据都开始往分裂后的第二个 Region 插入,就造成了数据热点现象

数据在更新时首先写入 HLog(WAL Log),再写入内存(MemStore)中,MemStore 中的数据是排
序的
,当 MemStore 累计到一定阈值(默认是 128M)时,就会创建一个新的 MemStore,并且
将老的 MemStore 添加到 flush 队列,由单独的线程 flush 到磁盘上,成为一个 StoreFile。于
此同时,系统会在 ZooKeeper 中记录一个 redo point,表示这个时刻之前的变更已经持久化
了。当系统出现意外时,可能导致内存(MemStore)中的数据丢失,此时使用 HLog(WAL Log)
来恢复 checkpoint 之后的数据。

Memstore 执行刷盘操作的的触发条件:

<1>、全局内存控制:当所有 memstore 占整个 heap 的最大比例的时候,会触发刷盘的操作。
	这个参数是hbase.regionserver.global.memstore.upperLimit,默认为整个heap内存的40%。
	这个全局的参数是控制内存整体的使用情况,但这并不意味着全局内存触发的刷盘操作会将所有的MemStore都进 行输盘,而是通过另外一个参数hbase.regionserver.global.memstore.lowerLimit 来控制,默认是整个 heap 内存的 35%。
	当flush 到所有 memstore 占整个 heap 内存的比率为 35%的时候,就停止刷盘。这么做主要是为了减少刷盘对业务带来的影响,实现平滑系统负载的目的。
<2>、当 MemStore 的大小达到 hbase.hregion.memstore.flush.size 大小的时候会触发刷盘,默认 128M 大小。
<3>、前面说到 HLog 为了保证 HBase 数据的一致性,那么如果 HLog 太多的话,会导致故障恢复的时间太长,因此 HBase 会对 HLog 的最大个数做限制。
	当达到 Hlog 的最大个数的时候,会强制刷盘。这个参数是 hase.regionserver.max.logs,默认是 32 个。
	HLog默认是在HRegionServer上一小时形成一个新的HLog,在memstore的数据flush到storefile后,也会把之前的的HLog删除,其实也就是尽量保证最新的HLog保留的是memstore中的log,已经flush的数据的log会在后面进行删除。
<4>、可以通过 HBase Shell 或者 Java API 手工触发 flush 的操作。

HBase 的三种默认的 Split 策略:

1、ConstantSizeRegionSplitPolicy
2、IncreasingToUpperBoundRegionSplitPolicy
3、SteppingSplitPolicy

StoreFile 是只读的,一旦创建后就不可以再修改。因此 HBase 的更新/修改其实是不断追加
的操作
。当一个 Store 中的 StoreFile 达到一定的阈值后,就会进行一次合并(minor_compact,
major_compact),将对同一个 key 的修改合并到一起,形成一个大的 StoreFile,当 StoreFile
的大小达到一定阈值后,又会对 StoreFile 进行 split,等分为两个 StoreFile。由于对表的更
新是不断追加的,compact 时,需要访问 Store 中全部的 StoreFile 和 MemStore,将他们按
rowkey 进行合并,由于 StoreFile 和 MemStore 都是经过排序的,并且 StoreFile 带有内存中
索引,合并的过程还是比较快。

Minor_Compact 和 Major_Compact 的区别:

<1>、Minor 操作只用来做部分文件的合并操作以及包括 minVersion=0 并且设置 ttl 的过期版本清理,不做任何删除数据、多版本数据的清理工作。
<2>、Major 操作是对 Region 下的 HStore 下的所有 StoreFile 执行合并操作,最终的结果是整理合并出一个文件。

HBase 只是增加数据,所有的更新和删除操作,都是在 Compact 阶段做的,所以用户写操作只需要进入到内存即可立即返回,从而保证 I/O 高性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值