注意:首先声明一点的是Hbase是一个读数据比写数据复杂(慢)的框架,所以先来看下写数据流程(以下为Hbase1.3.1版本)

           另外:读写数据均与master无关

Hbase写数据流程

 

  1. Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server(保存在了zookeeper的/hbase/meta-region-server中)。
  2. 访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标表位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。 
  3. 与table所在的 Region Server 进行通讯。
  4. 将数据顺序写入(追加)到 WAL(预写入日志)以便在服务器没有flush到storefile时宕机通过wal进行数据重建。
  5. 将数据写入对应的 MemStore,数据会在 MemStore 进行排序。
  6. 向客户端发送 ack。
  7. 等达到 MemStore 的刷写时机后,将数据刷写到 StoreFile。

        如果是以前0.9x版本的时候,hbase还维护了一个叫做-ROOT-的表,用来存储meta的位置,然后meta表中存储实际表的位置。基于考虑到将来由于meta表过大而进行split,也会形成多个Region,然而在zookeeper中就不能用一条数据存储多个Region形成的meta表的信息。经过长期生产上的测试,发现meta表一般不会由于数据量大而进行split,假如meta表的数据量确实很大了,在做校验进行split时,如果是meta表,就不进行split,所以meta表就会一直在一个Region上,最终舍弃了-ROOT-表。

解读步骤4:(具体源码中是这样的)在HRegion类中

  1. 上锁,读写分离(java.util.concurrent.locks.Lock)
  2. 传入数据添加一个时间戳
  3. 内存构建WAL
  4. 向WAL中写日志,并不同步到磁盘
  5. 数据写入memstore
  6. 释放锁
  7. 同步wal
  8. 如果同步wal失败(指的是数据在wal在写到hdfs时失败),事务回滚,从内存中将数据remove

 

Hbase读数据流程

Block Cache:读缓存(如果是从StoreFile里面读取的数据,不是直接返回给客户端,而是先写入BlockCache,再返回给客户端。)

作用是:读数据是会扫描磁盘的,本身很慢。所以用一个读缓存来加速查询。当读缓存中的数据量很大的时候会根据LRU算法删除一些数据。

LRU:最近最少使用

  1. Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server。
  2. 访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
  3. 与目标 Region Server 进行通讯。
  4. 分别在 Block Cache(读缓存),MemStore 和 Store File中查询目标数据,并将查到的所有数据进行合并(marge)。此处所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete),然后返回时间戳大的一条数据。
  5. 将从文件中查询到的数据块缓存到Block Cache。
  6. 将合并后的最终结果返回给客户端。

 

问题:

为什么不直接先读写缓存的数据然后直接返回?

        举例:先写一条数据到table1里面,不加时间戳,系统默认。并手动将数据flush到hdfs

                   put table1  1001 ‘info:name’ zhangsan

                   再添加一条比上一条数据时间戳小的数据

                   put table1 1001 'info:name' lisi 1503268558890

                   此时按理来说是不是应该返回 zhangsan?

                   如果读数据的时候不读storefile,只读写缓存。那么读出来的lisi就是错误的数据。

 

为什么读了读缓存还要再读storefile和写缓存?

              首先,一个表上面的数据是当memstore达到一定大小或者一定时间默认flush到hdfs上面的(或者手动flush)形成一个一个的文件。

               此时去table1上面读取一条数据,并将数据缓存到BlockCache中,和memStore中的marge后返回。此时的BlockCache中有了当前时间StoreFile中的数据,如果没有新添加,不用读取StoreFile。

               此时,再添加一条数据,并flush到StoreFile中,形成一个文件。

               那么,接下来再读取数据的时候,还会去磁盘扫描BlockCache没有扫描过的新文件,并加载到blockcache中,再和memstore中的数据进行marge返回。

 

综上:hbase是一个读比写复杂的一个框架。

              

        

 

posted on 2020-04-28 17:01  -星星点灯丶  阅读(239)  评论(0编辑  收藏  举报