前言
近期采用kylin+superset方案解决公司多维自助查询分析的问题,大家都知道kylin将预计算的结果写入HBase中以加快多维数据的查询速度,所以不可避免需要对HBase进行各种调优,调优过程中带着学习的目的深入研究了HBase的相关机制,想到以前非常喜欢台湾侯捷先生的名著《深入浅出MFC》以及李维先生的《Inside VCL》,所以把这系列取名深入浅出,当然这里主要是想记录过程,非常粗糙,权做抛砖引吧。
言归正传,先讲原理:
一、HBase原理解析
1、HBase的架构设计及基本的数据结构
1.1服务器节点架构
图1.1.1 HBase节点架构1.1.1 Client
包含访问HBase的接口,维护着一些Cache来加快对HBase的访问,比如缓存regione的位置信息等;
1.1.2 Zookeeper
保证任何时候,集群中只有一个master;存贮所有Region的寻址入口Root Region的位置;实时监控Region Server的状态,将Region server的上线和下线信息实时通知给Master;存储Hbase的schema,包括有哪些table,每个table有哪些column family;
1.1.3 Master
主要负责Region的分配与重分配;RegionServer的负载均衡;处理Schema更新(新建表、修改表结构等)的请求等;不参与HBase的读写数据过程;
图1.1.3.1 HBase Master&RegionServer1.1.4 RegionServer
一个RegionServer对应一个节点,Regionserver是调度者,维护多个Region,处理对这些Region的IO,负责切分在运行过程中变得过大的Region,一个Region只能属于一个Regionserver,Regionserver可以自动调整Region所在的服务器;底层数据是持久化在HDFS上的;
1.1.5 Client
访问hbase上数据的过程并不需要master参与(寻址访问zookeeper和region server,数据读写访问regione server),master仅仅维护者table和region的元数据信息,负载很低;
1.2数据结构模型
1.2.1整体结构
数据结构层面整体是这样的:
图1.2.1.1 HBase数据结构(V1)1.2.2 Region与HFile
一个Table表会被横向分成多个Region,一个Region只属于一个RegionServer,一个RegionServe管理多个Region,Region逻辑结构如下;
图1.2.2.1 Region的逻辑结构每个Region是一个rowkey段内的行记录集合,在逻辑上对应多个Store,一个Store在逻辑上对应一个MemStore和多个StoreFile,StoreFile对应物理存储文件HFile。
写入Hbase的数据可能是随机的,如果直接写入磁盘文件可能会系性能低下,因此,引入MemStore内存结构来存储来自客户端的写入或更新操作,因为是存储在内存,所以直接在 MemStore 里面进行随机写是非常高效的。同时,存储在 MemStore 里面的数据也是按照 RowKey 进行排序的,MemStore的数据会在满足一定参数阈值的时候触发 Flush 操作,存储在 MemStore 里面的数据就直接写到一个 HFile 里面,这样就解决了随机写性能低下的问题。
图1.2.2.2 Memstore&StoreFile&Hfile的关系1.2.3 StoreFile的结构
StoreFile具体分为几部分(见下图):
图1.2.3.1 HFile中各段的指向(V1)比较重要的是Trailer这个段,其结构见下图:
图1.2.3.2 Trailer具体结构(V1)Trailer这一段长度是固定的,保存了每一段的偏移量。读取一个HFile时,会首先读取Trailer,Trailer保存了每个段的起始位置(段的Magic Number用来做安全check),然后,Data Index会被读取到内存中,这样,当检索某个key时,不需要扫描整个HFile,而只需从内存中找到key所在的block,通过一次磁盘io将整个 block读取到内存中,再找到需要的key。
1.2.4 HLog
由于MemStore 是存储在内存的,所以如果对应的 RegionServer 突然挂掉了,那么没有 Flush 的数据就被丢失了,为了解决这个问题,HBase 引入了 HLog(WAL)(write-ahead-log)机制,所有的更新在写入 MemStore 之前先写到 HLog(WAL) 里面,HLog(WAL)是直接存储在 HDFS 上的,但写入时是顺序写,也就是直接Append到文件的后面,因此写入性能非常高,通过这种机制,即使对应的 RegionServer 挂了,但是由于 HLog(WAL)的存在,数据还是可以恢复。
HLog又叫WAL log(Write ahead log),类似mysql中的binlog,用来做灾难恢复。HLog记录数据的所有变更,一旦数据修改,就可以从HLog中进行恢复。每个Region Server维护一个HLog,而不是每个Region一个,这样不同region(来自不同table)的日志会混在一起,这样做的目的是不断追加单个文件,相对于同时写多个文件而言,可以减少磁盘寻址次数,从而提高对table的写性能。带来的问题是,如果一台region server下线,为了恢复其上的region,需要将region server上的log进行拆分,然后分发到其它region server上进行恢复。
WAL 文件里面的数据组织形式和 HFile 里面的是完全不一样的。WAL 文件里面包含一系列的修改,每条修改代表单个 put 或 delete。这些编辑数据包含当前修改是对应哪个 Region 的。编辑数据是按照时间编写的,因此所有的修改都是以追加的形式写到 WAL 文件的末尾。由于 WAL 里面的数据是按照修改时间编写的,所以写 WAL 文件不会发生随机写,这样可以大大提高写 WAL 的操作。
当 WAL 文件越来越大,这个文件最终是会被关闭的,然后再创建一个新的 active WAL 文件用于存储后面的更新。这个操作称为 rolling WAL 文件。一旦 WAL 文件发生了 Rolled,这个文件就不会再发生修改。
默认情况下,WAL 文件的大小达到了 HDFS 块大小的 50%(HBase 2.0.0 之前是 95%,详见 HBASE-19148),这个 WAL 文件就会发生 roll 操作。 我们可以通过 hbase.regionserver.logroll.multiplier 参数控制达到块大小的多少百分比就发生 roll。我们也可以通过 hbase.regionserver.hlog.blocksize 参数来控制块大小(注意,这个块大小不是 HDFS 的块大小)。除了文件大小能触发 rolling,HBase 也会定时去 Rolling WAL 文件,这个时间是通过 hbase.regionserver.logroll.period 参数实现的,默认是一小时。这两个策略满足一个就可以出发 WAL 的 Rolling 操作。
WAL 文件的大小对于 HBase 恢复是有影响的,因为 HBase 在使用 WAL 文件恢复数据的时候,对应的 Region 是无法提供服务的,所以尽量保持少一些的 WAL 文件。
一个 RegionServer 会包含多个 Region 的,HBase 并不为每个 Region 使用一个 WAL,而是整个 RegionServer 里面的 Regions 共用一个 WAL 日志。同时,只有一个 WAL 文件处于 active 状态。
WAL 在 HDFS 上的目录命名格式如下:
/hbase/WALs/,,
/hbase/WALs/192.168.1.103,16020,1542292581331
WAL 文件名称命名格式如下:
/hbase/WALs/,,/%2C%2C.
/hbase/WALs/192.168.1.103,16020,1542292581331/192.168.1.103%2C16021%2C1547646103879.1547646379202
1.2.5 HFile V1的问题
HFile V1的问题主要是:Region Open的时候,需要加载所有的Data Block Index数据,另外,第一次读取时需要加载所有的Bloom Filter数据到内存中。一个HFile中的Bloom Filter的数据大小可达百MB级别,一个RegionServer启动时可能需要加载数GB的Data Block Index数据。这在一个大数据量的集群中,几乎无法忍受。(测算Data Block index到底有多大,具体测算可见附录)。
1.2.6 HFile V2的一些说明
HFile V2.0之后有了一些变化,主要变化如下两图:
图1.2.6.1 HFile V2结构图1.2.6.2 HFile V2中各段的指向 HFile V2设计的初衷是期望显著降低RegionServer启动时加载HFile的时延,更希望解决一次全量加载数百MB级别的BloomFilter数据带来的时延过大的问题。由上面图可以看到主要采用了对索引进行了分层处理以解决索引数据过大的问题。
好,到此位置讲清楚了HBase的基本组织架构和数据结构,下一章我们详细讲讲HBase的读写流程,敬请关注探讨,如果觉得有用,别忘了关注点赞哦!