《HBase原理与实践》阅读笔记(二)

本博客内容基本整理自《Hbase原理与实践》一书。仅用于个人学习和积累。

1.Hbase客户端

Hbase客户端主要有如下几种形式:

  • 1.HBase提供了面向Java、C/C++、Python等多种语言的客户端。
  • 2.非Java语言的客户端需要先访问ThriftServer,然后通过ThriftServer的Java HBase客户端来请求HBase集群
  • 3.第三方团队实现了其他一些HBase客户端,例如OpenTSDB团队使用的asynchbase和gohbase等
  • 4.HBase也支持Shell交互式客户端。Shell客户端实质是用JRuby(用Java编写的Ruby解释器,方便Ruby脚本跑在JVM虚拟机上)脚本调用官方HBase客户端来实现的。

1.1.定位Meta表

HBase一张表的数据是由多个Region构成,而这些Region是分布在整个集群的RegionServer上的。那么客户端在做任何数据操作时,都要先确定数据在哪个Region上,然后再根据Region的RegionServer信息,去对应的RegionServer上读取数据。而hbase:meta表就是专门用来存放整个集群所有的region信息。
客户端定位Region示意图:
在这里插入图片描述

1.1.1.解决热点Region问题

把hbase:meta表的Region信息缓存在HBase客户端。HBase客户端有一个叫做MetaCache的缓存,在调用HBase API时,客户端会先去MetaCache中找到业务rowkey所在的Region。

1.2.Hbase常见超时参数

  • hbase.rpc.timeout:表示单次RPC请求的超时时间,一旦单次RPC超过该时间,上层将收到TimeoutException。默认为60000ms。
  • hbase.client.retries.number:表示调用API时最多容许发生多少次RPC重试操作。默认为35次。
  • hbase.client.pause:表示连续两次RPC重试之间的休眠时间,默认为100ms。
  • hbase.client.operation.timeout:表示单次API的超时时间,默认值为1200000ms

2.RegionServer核心模块

RegionServer是HBase系统中最核心的组件,主要负责用户数据写入、读取等基础操作。RegionServer组件实际上是一个综合体系,包含多个各司其职的核心模块:HLog、MemStore、HFile以及BlockCache。

2.1.内部结构

一个RegionServer由一个(或多个)HLog、一个BlockCache以及多个Region组成。如下图所示:
在这里插入图片描述

2.1.1.HLog

HBase中系统故障恢复以及主从复制都基于HLog实现。
HBase提供了如下命令查看HLog文件的内容:

~/hbase-current/bin$ ./hbase hlog
usage: WAL <filename...> [-h] [-j] [-p] [-r <arg>] [-s <arg>] [-w <arg>]
  -h,--help                 Output help message
  -j,--json                 Output JSON
  -p,--printvals          Print values
  -r,--region <arg>       Region to filter by. Pass encoded region name; e.g.
                        '9192caead6a5a20acb4454ffbc79fa14'
  -s,--sequence <arg>    Sequence to filter by. Pass sequence number.
  -w,--row <arg>          Row to filter by. Pass row name.

比如,可以使用-j参数以json格式打印HLog内容。
除此之外,还可以使用-r参数指定Region,使用-w参数指定row,更加精准化地打印想要的HLog内容。

2.1.2.MemStore

HBase系统中一张表会被水平切分成多个Region,每个Region负责自己区域的数据读写请求。水平切分意味着每个Region会包含所有的列簇数据,HBase将不同列簇的数据存储在不同的Store中,每个Store由一个MemStore和一系列HFile组成。
主要职责: MemStore作为一个缓存级的存储组件,总是缓存着最近写入的数据。MemStore还要承担业务多线程并发访问的职责。

2.1.3.HFile

MemStore中数据落盘之后会形成一个文件写入HDFS,这个文件称为HFile。
HFile文件主要分为4个部分:Scanned block部分、Non-scanned block部分、Load-on-open部分和Trailer。

  • Scanned Block:这部分主要存储真实的KV数据,包括Data Block、Leaf Index Block和Bloom Block。
  • Non-scanned Block:这部分主要存储Meta Block,这种Block大多数情况下可以不用关心。
  • Load-on-open:主要存储HFile元数据信息,包括索引根节点、布隆过滤器元数据等,在RegionServer打开HFile就会加载到内存,作为查询的入口。
  • Trailer:存储Load-on-open和Scanned Block在HFile文件中的偏移量、文件大小(未压缩)、压缩算法、存储KV个数以及HFile版本等基本信息。Trailer部分的大小是固定的。

HFile文件由各种不同类型的Block(数据块)构成,虽然这些Block的类型不同,但却拥有相同的数据结构。
HBase中定义了8种BlockType,每种BlockType对应的Block都存储不同的内容。
核心BlockType如下表:
在这里插入图片描述
其中,Data Block是HBase中文件读取的最小单元。
HBase提供了简单的工具来查看HFile文件的基本信息,在${HBASE_HOME}/bin目录下执行如下命令:

hadoop@hbase17:~/hbase-current/bin$ ./hbase hfile
usage: HFile [-a] [-b] [-e] [-f <arg> | -r <arg>] [-h] [-k] [-m] [-p]
        [-s] [-v] [-w <arg>]
  -a,--checkfamily            Enable family check
  -b,--printblocks            Print block index meta data
  -e,--printkey                Print keys
  -f,--file <arg>             File to scan. Pass full-path; e.g. hdfs://a:9000/hbase/hbase:meta/12/34
  -h,--printblockheaders    Print block headers for each block.
  -k,--checkrow                Enable row order check; looks for out-of-order keys
  -m,--printmeta              Print meta data of file
  -p,--printkv                 Print key/value pairs
  -r,--region <arg>          Region to scan. Pass region name; e.g. 'hbase:meta,,1'
  -s,--stats                    Print statistics
  -v,--verbose                 Verbose output; emits file and meta data  delimiters
  -w,--seekToRow <arg>       Seek to this row and print all the kvs for this
                                  row only

通常使用该命令中-m参数打印当前文件的元数据。

3.Hbase读写流程

HBase采用LSM树架构,天生适用于写多读少的应用场景。需要说明的是,HBase服务端并没有提供update、delete接口,HBase中对数据的更新、删除操作在服务器端也认为是写入操作,不同的是,更新操作会写入一个最新版本数据,删除操作会写入一条标记为deleted的KV数据。所以HBase中更新、删除操作的流程与写入流程完全一致。

3.1.Hbase写入流程

从整体架构的视角来看,写入流程可以概括为三个阶段。
1)客户端处理阶段:客户端将用户的写入请求进行预处理,并根据集群元数据定位写入数据所在的RegionServer,将请求发送给对应的RegionServer。
2)Region写入阶段:RegionServer接收到写入请求之后将数据解析出来,首先写入WAL,再写入对应Region列簇的MemStore。
3)MemStore Flush阶段:当Region中MemStore容量超过一定阈值,系统会异步执行f lush操作,将内存中的数据写入文件,形成HFile。
Hbase写入流程图:
在这里插入图片描述

3.1.1.少量写和批量写

HBase提供了3种常见的数据写入APIHBase提供了3种常见的数据写入API 。

  • table.put(put):这是最常见的单行数据写入API,在服务端先写WAL,然后写MemStore,一旦MemStore写满就f lush到磁盘上。这种写入方式的特点是,默认每次写入都需要执行一次RPC和磁盘持久化。因此,写入吞吐量受限于磁盘带宽、网络带宽以及f lush的速度。但是,它能保证每次写入操作都持久化到磁盘,不会有任何数据丢失。最重要的是,它能保证put操作的原子性
  • table.put(List<Put> puts):HBase还提供了批量写入的接口,即在客户端缓存put,等凑足了一批put,就将这些数据打包成一次RPC发送到服务端,一次性写WAL,并写MemStore。相比第一种方式,此方法省去了多次往返RPC以及多次刷盘的开销,吞吐量大大提升。不过,这个RPC操作耗时一般都会长一点,因为一次写入了多行数据。另外,如果List内的put分布在多个Region内,则不能保证这一批put的原子性,因为HBase并不提供跨Region的多行事务,换句话说,这些put中,可能有一部分失败,一部分成功,失败的那些put操作会经历若干次重试。
  • bulk load:通过HBase提供的工具直接将待写入数据生成HFile,将这些HFile直接加载到对应的Region下的CF内。在生成HFile时,在HBase服务端没有任何RPC调用,只在load HFile时会调用RPC,这是一种完全离线的快速写入方式。bulk load应该是最快的批量写手段,同时不会对线上的集群产生巨大压力。当然,在load完HFile之后,CF内部会进行Compaction,但是Compaction是异步的且可以限速,所以产生的IO压力是可控的。因此,bulk load对线上集群非常友好

3.1.2.MemStore Flush触发条件

  • MemStore级别限制:当Region中任意一个MemStore的大小达到了上限(hbase.hregion.memstore.flush.size,默认128MB),会触发MemStore刷新。
  • Region级别限制:当Region中所有MemStore的大小总和达到了上限(hbase.hregion. memstore.block.multiplier * hbase.hregion.memstore.flush.size),会触发MemStore刷新。
  • RegionServer级别限制:当RegionServer中MemStore的大小总和超过低水位阈值hbase.regionserver.global.memstore.size.lower.limit*hbase.regionserver.global.memstore. size,RegionServer开始强制执行flush,先flush MemStore最大的Region,再flush次大的,依次执行。如果此时写入吞吐量依然很高,导致总MemStore大小超过高水位阈值hbase.regionserver.global.memstore.size,RegionServer会阻塞更新并强制执行flush,直至总MemStore大小下降到低水位阈值。
  • 当一个RegionServer中HLog数量达到上限(可通过参数hbase.regionserver.maxlogs配置)时,系统会选取最早的HLog对应的一个或多个Region进行flush。
  • HBase定期刷新MemStore :默认周期为1小时,确保MemStore不会长时间没有持久化。为避免所有的MemStore在同一时间都进行flush而导致的问题,定期的flush操作有一定时间的随机延时。
  • 手动执行f lush :用户可以通过shell命令flush 'tablename'或者flush 'regionname'分别对一个表或者一个Region进行f lush。

3.2.Hbase读取流程

和写流程相比,HBase读数据的流程更加复杂。一是因为HBase一次范围查询可能会涉及多个Region、多块缓存甚至多个数据存储文件;二是因为HBase中更新操作以及删除操作的实现都很简单,更新操作并没有更新原有数据,而是使用时间戳属性实现了多版本;删除操作也并没有真正删除原有数据,只是插入了一条标记为"deleted"标签的数据,而真正的数据删除发生在系统异步执行Major Compact的时候
读流程从头到尾可以分为如下4个步骤:

  • Client-Server读取交互逻辑
  • Server端Scan框架体系
  • 过滤淘汰不符合查询条件的HFile
  • 从HFile中读取待查找Key
    其中,过滤手段主要有三种:根据KeyRange过滤,根据TimeRange过滤,根据布隆过滤器进行过滤。

4.总结

今天阅读了第四到第六章,其中第四章介绍了Hbase客户端的相关实现,并介绍了一些客户端到服务端通信的过程中常见的一些异常和常见的超时参数。虽然目前自己并没有接触到这些异常,但是通过这次阅读使得自己再今后遇到类似问题时能够有所反应,不至于两眼抹黑。第五章介绍了Hbase中很重要的一个模块——RegionServer。平时业务中碰到的一些Hbase数据不一致问题就和它密切相关。通过第五章的阅读让我学会了之后如何查看HLog和HFile中的内容,或许对之后问题的定位有帮助。第六章主要介绍了Hbase的读写流程,书中还介绍了Coprocessor的用法。虽然大多数情况下,通过调用HBase提供的读写API或者使用Bulkload功能基本上可以满足日常的业务需求。这里先提一下,之后如果遇到特殊应用场景,可以再去翻出来学习一下。

发布了67 篇原创文章 · 获赞 113 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/TNTZS666/article/details/104169063