一、HBase概述
1. 逻辑结构
(1) 表结构
术语 | 解释 |
row key | 行键,类似于关系型数据库中的主键,具有唯一性;HBase通过行键找数据的速度最快,行键会按照字典序进行排序。 |
column family | 列族,HBase中的任何一张表必须定义列族,列族内可以定义任意列。 |
column | 列,定义列之前,必须要定义出列族;和关系型数据库不同,每一行数据的列可以不同:例如一行数据有3列,另一行数据有2列;并且这两行数据的列名也可以不同。 |
(2) Region
HBase会将表中的数据划分为多个区域(Region),交由集群中的服务器负责管理。
(3) Store
在每一个Region中,会根据列族继续进行划分,每一个列族会被划分为一个Store。
2. 物理存储结构
逻辑结构中的每个Store是某一个列族中的所有数据的集合,这个数据集合在物理层面上使用了一个或者多个HFile格式的文件进行存储,HFile文件存储的内容为(以一行数据进行说明):
名称 | 解释 |
row key | 行键,代表对哪一条数据进行操作,行键唯一确定一条表中数据 |
column famliy name | 列族名,表示操作的是哪一个列族 |
column name | 列名,表示操作的是指定列族中的哪一个列名 |
timestamp | 进行该操作的时间戳,标识数据的版本,时间戳越大,表示该条操作越新,HBase会读取最新的操作 |
type | 操作的类型(修改、添加、删除) |
value | 修改或者添加操作所对应的值 |
HFile中的数据会被组织为一个一个的小块(Block)进行存储。
3. 数据模型
术语 | 解释 |
namespace | 命名空间,类似于关系数据库中的database;HBase自带了两个namespace,分别是:hbase、default,hbase中存放了元数据,default是提供给用户使用的默认数据库。 |
table | 表 |
cell | 单元,HFile中的每行数据都是一个单元 |
二、HBase原理
1. 架构
(1) 集群架构
名称 | 解释 |
HMaster | 负责管理HBase集群中的RegionServer,指定哪些RegionServer负责维护哪些Region以及监控RegionServer的状态,当发现某一台RegionServer挂掉之后,会将其维护的Region交由其他几台RegionServer维护。 |
RegionServer | 负责维护分配给自己的Region:当某一个Region中的数据量太大时分裂(Region Split)、合并某一个Region中的HFile并且物理性的删除一些过期数据(Region Compaction)、接受客户端请求,提供或者修改或者删除数据。 |
Zookeeper | 内部存储HBase的一些信息,比较重要的是存储了HBase中元数据的Region位置,元数据中记录了所有数据的Region位置。 |
(2) RegionServer架构
名称 | 解释 |
memstore | 写缓存,HBase不会立刻将数据写入HFile中,而是会先将其写入memstore中,当memstore满足阈值条件时,会将其中的数据刷写到HFile中 |
WAL | 由于数据要经MemStore后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会写入预写日志中,然后再写入MemStore中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。 |
Block Cache | 读缓存,读取HFile后,会将其中读取的部分块(Block)放入该缓存中,以加快下一次再次读取该数据的读取速度。但是该缓存也不会无限膨胀,会根据算法将最近不常读取的块从缓存中清除掉。 |
2. 写流程
3. MemStore Flush
刷写时机:
(1)当一个Region中某个Store中的memstore中的数据达到阈值(配置项:hbase.hregion.memstore.flush.size,默认128M)时,那么该Region中的所有Store中的memstore会将数据刷写到HFile中;
当memstore中数据大小达到了:hbase.hregion.memstore.flush.size(默认值128M)* hbase.hregion.memstore.block.multiplier(默认值4),会阻止继续往该memstore中写入数据。
(2)当一个RegionServer中所有memstore中数据大小达到:java_heapsize * hbase.regionserver.global.memstore.size(默认值0.4) * hbase.regionserver.global.memstore.size.lower.limit(默认值0.95),RegionServer会按照memstore中数据从大到小的顺序,依次刷写到HFile中;直到RegionServer中所有memstore中数据低于设定值;
当RegionServer中所有的memstore中数据大小达到:java_heapsize * hbase.regionserver.global.memstore.size(默认值0.4),会阻止继续往该RegionServer中所有的memstore中写入数据。
(3) 当达到自动刷写时间(配置项:hbase.regionserver.optionalcacheflushinterval,默认1小时),memstore会向HFile中写数据。
4. 读流程
HBase在查找数据的时候使用了优化手段:根据时间戳过滤、根据row key过滤、根据布隆过滤器过滤。
5. StoreFile Compaction(合并Store中的HFile以及清理过期数据)
(1) Minor Compaction:合并相邻较小的HFile并进行部分的物理清理,每次memstore flush后都有可能发生;
(2) Major Compaction:Store下的所有HFile进行合并,进行全部的物理清理,周期性发生;
6. Region Split(Region过大后,进行切分,交由不同RegionServer维护)
Region Split时机:
(1) 当1个Region中的某个Store下所有HFile的总大小超过hbase.hregion.max.filesize,该Region就会进行拆分(0.94版本之前)。
(2)当1个Region中的某个Store下所有HFile的总大小超过Min(initialSize*R^3 ,hbase.hregion.max.filesize"),该Region就会进行拆分。其中initialSize的默认值为2*hbase.hregion.memstore.flush.size,R为当前Region Server中属于该Table的Region个数(0.94版本之后)。
具体的切分策略为:
第一次split:1^3 * 256 = 256MB
第二次split:2^3 * 256 = 2048MB
第三次split:3^3 * 256 = 6912MB
第四次split:4^3 * 256 = 16384MB > 10GB,因此取较小的值10GB
后面每次split的size都是10GB了。
(3) Hbase 2.0引入了新的split策略:如果当前RegionServer上该表只有一个Region,超过2 * hbase.hregion.memstore.flush.size后进行分裂,否则按照超过hbase.hregion.max.filesize后进行分裂。
注意:HFile、WAL这些文件都存储在hdfs上,目的是为了多副本保证数据可靠。