目录
一、HBase架构
1、Client
2、Zookeeper
3、HMaster(类似NameNode)
4、HregionServer(类似DataNode)
5、HDFS
6、HRegion
7、Store
8、HFile
9、MemStore
10、WAL(Write-Ahead logs)
11、HBase Meta表
二、HBase数据结构
1、RowKey(行键)
2、Column Family(列族)
3、Cell(单元)
4、TimeStamp(时间戳)
5、NameSpace(命名空间)
三、HBase进阶原理
1、写流程
2、读流程
3、MemStore Flush
4、StoreFile Compaction
5、Region Split
从图中可以看出,HBase是由Client、Zookeeper、HMaster、HRegionServer、HDFS等几个组件组成。
下面介绍一下几个组件的相关功能:
Client包含了访问HBase的接口,另外Client还维护了对应的cache来加速HBase的访问,比如cache的.META元数据的信息。
HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。具体工作如下:
master节点的主要职责如下:
HregionServer直接对接用户的读写请求,是真正的“干活”的节点。它的功能概括如下:
HDFS为HBase提供最终的底层数据存储服务,同时为HBase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:
HBase表的分片,HBase表会根据RowKey值被切分成不同的HRegion存储在RegionServer中,每个HRegion会分散在不同的RegionServer中,但一个HRegion是不会拆分到多个RegionServer上的。 HRegion是Hbase中分布式存储和负载均衡的最小单元。
每个HRegion由多个Store构成,每个Store由一个MemStore和0或多个StoreFile组成,每个Store保存一个Columns Family。
这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。HRegion虽然是分布式存储的最小单元,但并不是存储的最小单元。StoreFile是以HFile的形式存储在HDFS的。
HFile的格式参考如下:
HFile分为六个部分:
HFile的Data Block,Meta Block通常采用压缩方式存储,压缩之后可以大大减少网络IO和磁盘IO,随之而来的开销当然是需要花费cpu进行压缩和解压缩。目标HFile的压缩支持两种方式:Gzip,Lzo。
内存存储存当前的数据操作,所以当数据保存在WAL中之后,RegsionServer会在内存中存储键值对。
当对HBase读写数据的时候,数据不是直接写进磁盘,它会在内存中保留一段时间(时间以及数据量阈值可以设定)。但把数据保存在内存中可能有更高的概率引起数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入内存中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。
HBase
有一个叫做Meta
的特殊的目录表,用于保存集群中Regions
的位置信息(Region
列表)。ZooKeeper
存储着Meta
表的位置。
与nosql数据库们一样,RowKey是用来检索记录的主键。访问HBASE table中的行,只有三种方式:
1)通过单个RowKey访问(get)
2)通过RowKey的range(正则)(like)
3)全表扫描(scan)
RowKey行键 (RowKey)可以是任意字符串(最大长度是64KB,实际应用中长度一般为 10-100bytes),在HBASE内部,RowKey保存为字节数组。存储时,数据按照RowKey的字典序(byte order)排序存储。设计RowKey时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)
列族:HBASE表中的每个列,都归属于某个列族。列族是表的schema的一部 分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如 courses:history,courses:math都属于courses 这个列族。
由{rowkey, column Family:columu, version} 唯一确定的单元。cell中的数据是没有类型的,全部是字节码形式存贮。
关键字:无类型、字节码
HBASE 中通过rowkey和columns确定的为一个存贮单元称为cell。每个 cell都保存 着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由HBASE(在数据写入时自动 )赋值,此时时间戳是精确到毫秒 的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell 中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,HBASE提供 了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段 时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。
命名空间的结构:
1) Table:表,所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定,则在default默认的命名空间中。
2) RegionServer group:一个命名空间包含了默认的RegionServer Group。
3) Permission:权限,命名空间能够让我们来定义访问控制列表ACL(Access Control List)。例如,创建表,读取表,删除,更新等等操作。
4) Quota:限额,可以强制一个命名空间可包含的region的数量。
1)Client先访问ZooKeeper,获取hbase:meta表位于哪个RegionServer;
2)访问对应的RegionServer,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问;
3)与目标RegionServer进行通讯;
4)将数据顺序写入(追加)到WAL;
5)将数据写入对应的MemStore,数据会在MemStore进行排序;
6)向客户端发送ack;
7)等达到MemStore的刷写时机后,将数据刷写到HFile。
1)Client先访问ZooKeeper,获取hbase:meta表位于哪个RegionServer;
2)访问对应的RegionServer,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问;
3)查询数据,如果Block Cache没有对应数据,同时读取内存(MemStore)和磁盘(StoreFile)中的数据(并将磁盘的数据缓存到Block Cache,LRU算法),比较时间戳返回对应的数据。
4)如果Block Cache有对应数据,直接比较和MemStore中数据的最大时间戳,返回该数据。
MemStore数据达到阈值,将数据刷到硬盘。将内存中的数据删除,同时删除HLog中的历史数据。
MemStore刷写时机:
1)当某个MemStore的大小达到了hbase.hregion.memstore.flush.size (默认值128M),其所在Region的所有MemStore都会刷写。
2)RegionServer中的MemStore大小超过hbase.regionserver.global.memstore.size(默认大小为堆大小的40%)
3)到达自动刷写的时间也会触发MemStore Flush,自动刷新的时间间隔由该属性进行配置hbase.regionserver.optionalcacheflushinterval (默认1小时)。
由于MemStore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction。
Compaction分为两种,分别是Minor Compaction和Major Compaction。Minor Compaction会将临近的若干个较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据。Major Compaction会将一个Store下的所有的HFile合并成一个大HFile,并且会清理掉过期和删除的数据。
StoreFile Compaction触发时机:
当数据块达到 4 块,Hmaster触发合并操作,Region将数据块加载到本地,进行合并;当合并的数据超过 256M,进行拆分,将拆分后的Region分配给不同的HRegionServer管理(一个表中的Region就会被不同的HRegionServer管理,分布式存储,高可用容灾); 当 HRegionServer宕机后,将 HRegionServer上的HLog拆分,然后分配给不同的HRegionServer加载,修改.META.;
默认情况下,每个Table
起初只有一个Region
,随着数据的不断写入,Region
会自动进行拆分。刚拆分时,两个子Region
都位于当前的Region Server
,但处于负载均衡的考虑,HMaster
有可能会将某个Region
转移给其他的RegionServer
。
Region Split时机:
当1个Region中的某个Store下所有StoreFile的总大小超过hbase.hregion.max.filesize,该Region就会进行拆分(0.94 版本之前)。
当1个Region中的某个Store下所有StoreFile的总大小超过Min(R^2 * "hbase.hregion.memstore.flush.size",hbase.hregion.max.filesize"),该Region就会进行拆分,其中R为当前Region Server中属于该Table的个数(0.94 版本之后)。