导航
- HBase定义
- HBase数据模型
- HBase系统架构
- HBase 写流程
- HBase 读流程
- StoreFile Compaction
- Region Split
HBase定义
HBase是一种分布式、可扩展、支持海量数据列式存储、实时读写的NoSQL数据库
它有如下优点
1)分布式、可扩展、支持海量数据列式存储:HBase 底层数据存储依赖于HDFS系统,HDFS可以通过简单地增加DataNode实现扩展,HBase读写服务节点也一样,可以通过简单的增加RegionServer节点实现计算层的扩展;Hbase 是根据列族来存储数据
2)单表容量巨大:HBase的单表可以支持千亿行、百万列的数据规模,数据容量可以达到TB甚至PB级别。传统的关系型数据库,如 Oracle和MySQL等,如果单表记录条数超过亿行,读写性能都会急剧下降,在HBase中并不会出现这样的问题
3)实时读写:Hbase 适合存储 PB 级别的海量数据,在 PB 级别的数据以及采用廉价 PC 存储的情况下,能在几十到百毫秒内返回查询数据
4)稀疏性:HBase支持大量稀疏存储,即允许大量列值为空,并不占用任何存储空间。这与传统数据库不同,传统数据库对于空值的处理要占用一定的存储空间,这会造成一定程度的存储空间浪费。因此可以使用HBase存储多至上百万列的数据,即使表中存在大量的空值,也不需要任何额外空间
5)多版本:HBase支持多版本特性,即一个 KV 可以同时保留多个版本,用户可以根据需要选择最新版本或者某个历史版本
它有如下缺点
1)Hbase 不支持 join 等复杂操作,但可通过Phoenix组件或者Spark 组件,来实现多表 join 等复杂操作。Phoenix组件主要应用于小规模聚合的 OLTP 场景,Spark 组件应用于大规模聚合的 OLAP 场景
2)HBase原生不支持全局跨行事务,只支持单行事务模型,但同样可以使用Phoenix组件提供的全局事务模型来弥补HBase的这个缺陷
3)HBase本身并没有实现二级索引功能,所以不支持二级索引查找,同样可以使用Phoenix组件来弥补HBase的这个缺陷
HBase数据模型
1)Name Space
命名空间,类似于关系型数据库的database概念,每个命名空间下有多个表。HBase两个自带的命名空间,分别是hbase和default,hbase中存放的是HBase内置的表,default表是用户默认使用的命名空间
2)Table
类似于关系型数据库的表概念。不同的是,HBase定义表时只需要声明列族即可,不需要声明具体的列。这意味着,往HBase写入数据时,字段可以动态、按需指定。因此,和关系型数据库相比,HBase能够轻松应对字段变更的场景
3)Row
HBase表中的每行数据都由一个RowKey(行键)和多个Column(列)组成,数据是按照RowKey的字典顺序存储的,并且查询数据时只能根据RowKey进行检索,所以RowKey的设计十分重要
RowKey(行键)可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在hbase底层,row key保存为字节数组
4)Column
HBase中的每个列都由Column Family(列族)和Column Qualifier(列限定符)进行限定,例如info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义。列族是表的Schema的一部分(而列不是)
5)Time Stamp
用于标识数据的不同版本(version),每条数据写入时,系统会自动为其加上该字段,其值为写入HBase的时间
6)Cell
由{rowkey, column Family:column Qualifier, time Stamp} 唯一确定的单元。cell中的数据全部是字节码形式存储
7)Region&Store&MemStore&StoreFile
当这个表数据量达到一定数量时
,就会分裂,分裂成多个Region
,分裂的方式是以行的方式进行分割
,例如0~100万行为一个Region,100~200万行为一个Region,而每一个Region内,又可以按照列族
进行分割,不同的列族对应不同的Store
,而每一个Store又由一个 MemStore 和0至多个 StoreFile 组成(下边有详细介绍)
HBase系统架构
1)Region Server
Region Server 是所有 Region的管理者,其实现类为HRegionServer,主要作用如下:
- 对数据的操作:get, put, delete
- 对Region的操作:splitRegion、compactRegion
2)Master
Master是所有Region Server的管理者,其实现类为HMaster,主要作用如下:
- 对表的操作:create, delete, alter
- 对RegionServer的操作:分配regions到每个RegionServer,监控每个RegionServer的状态,负载均衡和故障转移
3)Zookeeper
HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作
4)HDFS
HDFS为HBase提供最终的底层数据存储服务,同时为HBase提供高容错的支持
RegionServer 架构
1)StoreFile
保存实际数据的物理文件,StoreFile以Hfile的形式存储在HDFS上。每个Store会有一个或多个StoreFile(HFile),数据在每个StoreFile中都是有序的
2)MemStore
写缓存,由于HFile中的数据要求是有序的,所以数据是先存储在MemStore中,排好序后,待满足刷写时机时才会刷写到HFile,每次刷写都会形成一个新的HFile
3)WAL
由于数据要经MemStore排序后才能刷写到HFile,数据保存在内存中的这段时间会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做Write ahead log 的文件中,然后再写入MemStore中。所以在系统出现故障的时候,数据可以通过这个日志文件重建
4)BlockCache
读缓存,每次查询出的数据会缓存在BlockCache中,方便下次查询
HBase 写流程
1)Client先访问zookeeper,先询问hbase的meta表位于哪个Region Server
2)访问对应的Region Server,获取hbase的meta表,根据写请求的namespace:table/rowkey,首先查询出目标数据应该写入哪个Region Server中的哪个Region中,然后在将该region信息以及meta表的位置信息缓存到客户端的Meta cache中一份,方便下次访问
3)然后与目标Region Server进行通讯,先将数据顺序写入(追加)到WAL,在将数据写入对应的MemStore,数据会在MemStore进行排序
4)Region Server向客户端发送ack应答
5)Region Server待达到MemStore的刷写时机后,将数据刷写到HFile
MemStore 刷写时机
(1)当
某个memstroe的大小达到了hbase.hregion.memstore.flush.size(默认值128M),其所在region的所有memstore都会刷写
;当
memstore的大小达到了hbase.hregion.memstore.flush.size(默认值128M)* hbase.hregion.memstore.block.multiplier(默认值4)时,会阻止继续往该memstore写数据
memstroe的大小若为127.9M时,依旧可以往里面写数据,但是此次写数据写多少都可以吗(2000G行吗)?显然不行,所以需要有上限,即128*4
(2)当region server中memstore的总大小达到java_heapsize* hbase.regionserver.global.memstore.size(默认值0.4)* hbase.regionserver.global.memstore.size.lower.limit(默认值0.95)时,region会按照其所有memstore的大小顺序(由大到小)依次进行刷写,直到region server中所有memstore的总大小减小到java_heapsize* 0.38以下;当region server中memstore的总大小达到java_heapsize* hbase.regionserver.global.memstore.size(默认值0.4)时,会阻止继续往所有的memstore写数据
(3)到达自动刷写的时间,也会触发memstore flush。自动刷新的时间间隔由该属性进行配置hbase.regionserver.optionalcacheflushinterval(默认1小时)
(4)当WAL文件的数量超过hbase.regionserver.max.logs(默认值32),region会按照时间顺序依次进行刷写,直到WAL文件数量减小到hbase.regionserver.max.log以下(该属性2.x后已经废弃
)
HBase 读流程
1)Client先访问zookeeper,先询问hbase的meta表位于哪个Region Server
2)访问对应的Region Server,获取hbase的meta表,根据写请求的namespace:table/rowkey,首先查询出目标数据应该位于哪个Region Server中的哪个Region中,然后在将该region信息以及meta表的位置信息缓存到客户端的Meta cache中一份,方便下次访问
3)然后与目标Region Server建立通信后,分别在MemStore和Store File(HFile)中查询目标数据,并将查到的所有数据进行合并。此处所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete)
4)将合并后的最终结果返回给客户端
StoreFile Compaction
由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction
Compaction分为两种,分别是Minor Compaction
和Major Compaction
。Minor Compaction会将临近的若干个较小的HFile
合并成一个较大的HFile,并清理掉部分过期和删除的数据。Major Compaction会将一个Store下的所有的HFile合并成一个大HFile
,并且会清理掉所有过期和删除的数据
Region Split
默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的Region Server,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的Region Server
Region Split时机:
(1)当1个region中的某个Store下所有StoreFile的总大小超过hbase.hregion.max.filesize (10G),该Region就会进行拆分(0.94版本之前)
(2)当1个region中的某个Store下所有StoreFile的总大小超过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分裂