架构图
HBase体系结构借鉴了BigTable论文,是典型的Master-Slave模型。系统中有一个管理集群的Master节点以及大量实际服务用户读写的RegionServer节点。 除此之外,HBase中所有数据最终都存储在HDFS系统中,这与BigTable实际数据存储在GFS中相对应;系统中还有一个ZooKeeper节点,协助Master对集群进行管理。
- 0.9x.x版本
- 1.4.x及2.x版本
每一个 RegionServer 就只有一个 HLog,而不是一个 Region 有一个 HLog
Client
HBase客户端(Client)提供了Shell命令行接口、原生Java API编程接口、Thrift/REST API编程接口以及MapReduce编程接口。 HBase客户端支持所有常见的DML操作以及DDL操作,即数据的增删改查和表的日常维护等。 其中Thrift/REST API主要用于支持非Java的上层业务需求,MapReduce接口主要用于批量数据导入以及批量数据读取。
- 0.98.x及更低版本
HBase有两张特殊表:
-ROOT-
:记录了.META.
表的Region
信息,-ROOT-
只有一个Region
,无论如何不会分裂
.META.
:记录了用户所有表拆分出来的的Region
映射信息,.META.
可以有多个Regoin
Client
访问用户数据前需要首先访问ZooKeeper
,找到-ROOT-
表的Region
所在的位置,然后访问-ROOT-
表,
接着访问.META.表
,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过client
端会做cache
缓存。
- 1.4.x及更高版本 HBase客户端访问数据行之前,首先需要通过元数据表定位目标数据所在RegionServer,之后才会发送请求到该RegionServer。 同时这些元数据会被缓存在客户端本地,以方便之后的请求访问。如果集群RegionServer发生宕机或者执行了负载均衡等, 从而导致数据分片发生迁移,客户端需要重新请求最新的元数据并缓存在本地。
Zookeeper
主要用于协调管理分布式应用程序。在HBase系统中,ZooKeeper扮演着非常重要的角色。
-
实现Master高可用:通常情况下系统中只有一个Master工作,一旦Active Master由于异常宕机,ZooKeeper会检测到该宕机事件,并通过一定机制选举出新的Master,保证系统正常运转。
-
管理系统核心元数据:比如,管理当前系统中正常工作的RegionServer集合,保存系统元数据表hbase:meta所在的RegionServer地址等。
-
参与RegionServer宕机恢复:ZooKeeper通过心跳可以感知到RegionServer是否宕机,并在宕机后通知Master进行宕机处理。
-
实现分布式表锁:HBase中对一张表进行各种管理操作(比如alter操作)需要先加表锁,防止其他用户对同一张表进行管理操作,造成表状态不一致。 和其他RDBMS表不同,HBase中的表通常都是分布式存储,ZooKeeper可以通过特定机制实现分布式表锁。
Master
Master主要负责HBase系统的各种管理工作:
-
处理用户的各种管理请求,包括建表、修改表、权限操作、切分表、合并数据分片以及Compaction等。
-
管理集群中所有RegionServer,包括RegionServer中Region的负载均衡、RegionServer的宕机恢复以及Region的迁移等。
-
清理过期日志以及文件,Master会每隔一段时间检查HDFS中HLog是否过期、HFile是否已经被删除,并在过期之后将其删除。
HRegionServer
RegionServer主要用来响应用户的IO请求,是HBase中最核心的模块,由WAL(HLog)、BlockCache以及多个Region构成。
-
WAL(HLog):HLog在HBase中有两个核心作用——其一,用于实现数据的高可靠性,HBase数据随机写入时,并非直接写入HFile数据文件,而是先写入缓存,再异步刷新落盘。 为了防止缓存数据丢失,数据写入缓存之前需要首先顺序写入HLog,这样,即使缓存数据丢失,仍然可以通过HLog日志恢复;其二,用于实现HBase集群间主从复制, 通过回放主集群推送过来的HLog日志实现主从复制。
-
BlockCache:HBase系统中的读缓存。客户端从磁盘读取数据之后通常会将数据缓存到系统内存中,后续访问同一行数据可以直接从内存中获取而不需要访问磁盘。 对于带有大量热点读的业务请求来说,缓存机制会带来极大的性能提升。
BlockCache
缓存对象是一系列Block
块,一个Block
默认为64K
,由物理上相邻的多个KV数据组成。BlockCache
同时利用了空间局部性
和时间局部性
原理,
前者表示最近将读取的KV数据很可能与当前读取到的KV数据在地址上是邻近的,缓存单位是Block(块)而不是单个KV就可以实现空间局部性;
后者表示一个KV数据正在被访问,那么近期它还可能再次被访问。当前BlockCache主要有两种实现—LRUBlockCache
和BucketCache
,
前者实现相对简单,而后者在GC优化方面有明显的提升。
- Region:数据表的一个分片,当数据表大小超过一定阈值就会“水平切分”,分裂为两个
Region
。Region
是集群负载均衡的基本单位。 通常一张表的Region
会分布在整个集群的多台RegionServer
上,一个RegionServer
上会管理多个Region
,当然,这些Region一般来自不同的数据表。
一个Region
由一个或者多个Store
构成,Store的个数取决于表中列簇(column family)的个数,多少个列簇就有多少个Store
。
HBase中,每个列簇的数据都集中存放在一起形成一个存储单元Store
,因此建议将具有相同IO特性的数据设置在同一个列簇中。
每个Store由一个MemStore和一个或多个HFile组成。MemStore称为写缓存,用户写入数据时首先会写到MemStore, 当MemStore写满之后(缓存数据超过阈值,默认128M)系统会异步地将数据flush成一个HFile文件。显然,随着数据不断写入, HFile文件会越来越多,当HFile文件数超过一定阈值之后系统将会执行Compact操作,将这些小文件通过一定策略合并成一个或多个大文件。
HRegionServer主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。
HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个 Region,HRegion中由多个HStore组成。 每个HStore对应了Table中的一个Column Family的存储, 可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。
HStore存储是HBase存储的核心了,其中由两部分组成,一部分是MemStore,一部分是StoreFiles。 MemStore是Sorted Memory Buffer,
用户写入的数据首先会放入MemStore,当MemStore满了以后会Flush成一个StoreFile(底层实现是HFile), 当StoreFile文件数量增长到一定阈值,
会触发Compact合并操作,将多个StoreFiles合并成一个StoreFile,合并过程中会进 行版本合并和数据删除,因此可以看出HBase其实只有增加数据,
所有的更新和删除操作都是在后续的compact过程中进行的,这使得用户的写操作只要 进入内存中就可以立即返回,保证了HBase I/O的高性能。
当StoreFiles Compact后,会逐步形成越来越大的StoreFile,当单个StoreFile大小超过一定阈值后,会触发Split操作,同时把当前 Region Split成2个Region,
父Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer 上,使得原先1个Region的压力得以分流到2个Region上。
下图描述了Compaction和Split的过程:
- HLog(预写日志)
在理解了上述
HStore
的基本原理后,还必须了解一下HLog
的功能,因为上述的HStore
在系统正常工作的前提下是没有问题的, 但是在分布式系统环境中,无法避免系统出错或者宕机,因此一旦HRegionServer
意外退出,MemStore
中的内存数据将会丢失, 这就需要引入HLog
了。每个HRegionServer
中都有一个HLog
对象,HLog
是一个实现Write Ahead Log
的类,在每次用户操作写入MemStore
的同时, 也会写一份数据到HLog
文件中(HLog文件格式见后续),HLog
文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据)。 当HRegionServer
意外终止后,HMaster
会通过Zookeeper
感知到,HMaster
首先会处理遗留的HLog
文件,将其中不同Region
的Log
数据进行拆分, 分别放到相应region
的目录下,然后再将失效的region
重新分配,领取到这些region
的HRegionServer
在Load Region
的过程中,会发现有历史HLog
需要处理, 因此会Replay HLog
中的数据到MemStore
中,然后flush
到StoreFiles
,完成数据恢复。
HLog
文件就是一个普通的Hadoop Sequence File
,Sequence File
的value
是key
时HLogKey
对象,其中记录了写入数据的归属信息,除了table
和region
名字外,
还同时包括sequence number
和timestamp
,timestamp
是写入时间,sequence number
的起始值为0,或者是最近一次存入文件系统中的sequence number
。
Sequence File
的value
是HBase
的KeyValue
对象,即对应HFile
中的KeyValue
。
-
HRegion:当表的大小超过预设值的时候,HRegion会自动按行对rowkey对应的数据进行拆分
-
HLog:HLog 是一个实现了WAL(Write Ahead Log)的预写日志类,其内部是一个简单的顺序日志。每个HRegionServer上都有一个HLog,类似于mysql中的binlog。该日志只会追加内容,用于记录操作日志,能用来做灾难恢复(数据回滚到初始状态)。
-
HStore:它是HBase的存储核心,存储的最小单元,由MemStore或0至多个StoreFile组成。
-
MemStore:它是内存缓冲区,用户写入的数据首先会放入MemStore,当MemStore满了以后会Flush成一个StoreFile(底层实现是HFile,是HBase存储数据的文件组织形式),当StoreFile的文件数量增长到一定阈值后,会触发Compact合并操作,将多个StoreFiles合并成一个StoreFile,合并过程中会进行版本合并和数据删除操作。
因此,可以看出HBase其实只有增加数据
,所有的更新和删除操作都是在后续的Compact过程中进行的
,这样使得用户的写操作只要进入内存就可以立即返回,保证了HBaseI/O的高性能。
- 数据flush过程如下:
当memstore数据达到阈值(默认是128M),将数据刷到硬盘,将内存中的数据删除,同时删除Hlog中的历史数据。
并将数据存储到hdfs中。
在hlog中做标记点。
数据Compact合并过程如下:
当数据块达到4块,hmaster将数据块加载到本地,进行合并
当合并的数据超过256M,进行拆分,将拆分后的region分配给不同的hregionserver管理
当hregionser宕机后,将hregionserver上的hlog拆分,然后分配给不同的hregionserver加载,修改habse:meta(HBase的内置表,存储HBase内部的系统信息——Region的分布情况以及每个Region的详细信息)
hlog会同步到hdfs
- HBase 容错
HMaster 容错:通过Zookeeper实现,如果HMaster挂掉,通过Zookeeper的选举机制重新选择一个新的HMaster
HRegionServer容错:RegionServer会定时向Zookeeper发送心跳,如果一段时间内未出现心跳,Master将该RegionServer上的Region重新分配到其他RegionServer上。
Zookeeper容错:zookeeper是为其它分布式框架提供分布式协调服务的,本身并不是单点,一般都是奇数个zk组成的集群,如果某一个挂掉后,zk会通过选举机制重新选择一个leader。
HBase存储格式
HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,主要包括上述提出的两种文件类型:
-
HFile
,HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile -
HLog File
,HBase中WAL(Write Ahead Log)的存储格式,物理上是Hadoop的Sequence File
HFile
首先HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。正如图中所示的,Trailer 中有指针指向其他数据块的起始点。 File Info中记录了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。Data Index和Meta Index块记录了 每个Data块和Meta块的起始点。
Data Block是HBase I/O的基本单元,为了提高效率,HRegionServer中有基于LRU的Block Cache机制。每个Data块的大小可以在创建一个Table的时候通过参数指定, 大号的Block有利于顺序Scan,小号Block利于随机查询。 每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成, Magic内容就是一些随机数字,目的是防止数据损坏。
HFile里面的每个KeyValue对就是一个简单的byte数组。但是这个byte数组里面包含了很多项,并且有固定的结构。我们来看看里面的具体结构:
开始是两个固定长度的数值,分别表示Key的长度和Value的长度。紧接着是Key,开始是固定长度的数值,表示RowKey 的长度,紧接着是RowKey, 然后是固定长度的数值,表示Family的长度,然后是Family,接着是Qualifier,然后是两个固定长度的数 值,表示Time Stamp和Key Type(Put/Delete)。 Value部分没有这么复杂的结构,就是纯粹的二进制数据了。
HLogFile
HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息, 除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。