Hbase读写流程简要分析
Hbase基本概念:
Hbase读流程:
- 首选,客户端访问zookeeper获取meta表(主要记录表的元信息)所在的region,然后从meta中获取想要操作的region位置,并将meta缓存在客户端,用于后续的操作(当一个RegionServer宕机后,客户端需要重新获取meta信息进行缓存);
- 向对应的RegionServer建了连接并发起读取数据请求;
- 此时,RegionServer会先到MemStore中查数据,如果查不到就会到BlockCache中查,再查不到就会访问磁盘中HFile读取数据;
Scanner在server结构:
- 请求RegionServer构建RegionScanner;
- 一个RegionScanner管理一堆ColumnFamily,构造StoreScanner,一个StoreScanner对应了这个store上的memstore和Hfile;
- StoreScanner管理一堆HFile,构造HFileScanner,这个是实际读取数据的地方(获取数据的HFile是不能处于compaction状态,正在处于compaction的HFile是无法检索的);
scanner.next的关键步骤:
- Scan是一行一行获取的,获取完一行之后再获取下一行;
- 一般查找的顺序是先memstore,然后blockcache,最后到HFile;
- 每次拿一次数据都要判断下是否有stopRow,如果有可以停在搜索返回;
- 最终返回的List<Cell>results要封装成Result[]格式返回
Hbase写流程:
- 客户端想RegionServer发送写入数据请求;
- RegionServer先将数据写入HLog,即WAL,再讲数据写入MemStore;
- 当MemStore中的数据达到阈值的时候,会将数据Flush到硬盘中,并同时清空内存和HLog中的历史数据;
- 将硬盘中数据通过HFile来序列化,再讲数据传输到HDFS进行存储。并对HLog进行一次标记;
- 当HFile数量到达一定值的时候,会进行compact操作,合并成一个大的HFile;
- 如果一个region大小超过阈值时,会进行split操作,并将拆分后的region重新分配的不同的RegionServer进行管理;
- 写入流程中涉及到MVCC多版本协议控制协议,主要是hbase解决读写一致性的解决方案。MVCC变量是region级别的,每个region之间的mvcc是相互独立的。写如过程中的MVCC的作用:
Hbase每次Put都会指定一个唯一ID,该ID是Region级递增的。每个Region得MVCC维护两个point:
- readpoint指向已经写入完成的ID;
- writepoint指向正在写入的ID
没有数据写入的时候,二者的位置是一样的,当有数据写入的时候,readpoint要比writepoint小,只有readpoint之前的数据能够读取到(只要成功写入HLog和Memstore的数据能够读取到,无序写入HFile中)
- Nonce机制,在网络不稳定的情况下,当客户端发送rpc请求给regionserver服务器的时候,如果服务器处理时间过长导致超时,会出现服务器处理完毕,而无法及时通知客户端,导致客户端重新发送写入请求,即多次发送append,会造成数据多次添加。为了防止类似的现象,Hbase引入了Nonce机制,ServerNonceManager负责管理该RegionServer的nonce。
客户端每次申请以及重复申请会使用同一个nonce,发送到服务端之后,服务端会判断该nonce是否存在,如果不存在则可以放心执行,否则会根据当前的nonce进行相应的回调处理:
- 如果nonce处于WAIT状态,表示该nonce所对应的操作正在执行中,需要等待其执行结束,根据其执行结果进行下一步操作;
- 如果nonce处于PROCEED状态,则表明该nonce所对应的操作已经执行过了,只不过是已失败告终,可以重新执行;
- 如果noce处于DONT_PROCEED状态,无需做处理。因此,当nonce进入DONT_PROCEED状态以后,所有通过它来执行的操作都会被忽视掉,从而防止操作冗余的发生。
Hbase底层存储结构:
所有数据一般都保存在hadoop分布式系统上,用户通过访问region服务获取数据,一个物理节点一般只能运行一个region服务器,主要组成部分为:HLog(WAL)和多个region;一个HStore包含:一个MemStore和多个HFile
Hbase底层存储的架构图
Hbase的数据最终是以HFile的形式存储在HDFS中的,HBase中HFile有着对应格式。一次memstore的flush会产生一个HFile,一次Compact会导致多个HFile合并成一个。Hbase提供的读/写HFile的reader和writer工厂类,可以直接从HFile文件读取数据,从而绕过Hbase提供Scan、Get、Put等api
一个HFile内容是由一个个block组成的,按照block类型可分为:
1. datablock存放的key-value数据,一般一个datablock大小默认为64kb;
2. data index block,其中存放的是datablock的index,索引可以是多级索引,中间索引,叶子索引一般分布在HFile文件当中;
3. bloom filter block,保持了bloom过滤的值;
4. meta data block,meta data block有多个,且连续分布;
5. meta data index 顾名思义
6. file-info block,其中记录了关于文件的一些信息:HFile中最大的key,平均Key长度,HFile创建时间戳,data block使用的编码方式等;
7. trailer block,每个HFile文件都会有的,对于不同版本的HFile的trailer长度可能不一样,但是同一版本的所有的HFile trailer的长度都是一样长的
HFile读写,都可以通过org.apache.hadoop.hbase.io.hfile.HFile这类类提供的一些静态方法来实现
Hbase宕机处理:
- Zookeeper会监控RegionServer的上下线情况,当ZK发现某个RegionServer宕机之后,会通知HMaster;
- 该RegionServer会停止对外提供服务,即该Region服务器下的region对外都无法访问;
- HMaster会将该RegionServer所负责的region转移到其他RegionServer上,并且会对RegionServer上存在MemStore中未持久化到硬盘的数据进行恢复;
- 这个恢复操作工作由读取WAL文件完成:
- 宕机发生时,读取该RegionServer所对应的路径下的WAL文件,然后根据不同的region切分成不同的recover.edits;
- 当region被分配到其他RegionServer时,RegionServer读取region时会进行是否存在recover.edits,如果有则进行恢复。