一、概述
-
HBase是Apache提供的一套分布式的、可扩展的非关系型数据库
-
HBase能存储billions of rows X millions of columns
-
HBase是Doug仿照Google的Big Table来设计实现的
-
HBase是NOSQL(Not only SQL)数据库,HBase不支持SQL
-
HBase中,数据是采取了列级别的方式来存储,并且数据在存储的时候是以键值对形式存储
-
-
HBase实际上提供了3种安装方式:单机、伪分布式和完全分布式。在单机模式中,HBase不是基于Hadoop存储的而是存储在本地磁盘上
-
HBase适合于存储半结构化、稀疏的数据
-
在HBase中,如果要删除一个表,需要先禁用这个表
-
HBase提供了完整的增删改查的能力
-
HBase是基于HDFS来存储数据,HDFS不允许修改数据,但是HBase提供了"改"的能力 - HBase的修改实际上并不是改变原始数据,而是在文件尾部追加。HBase在写入数据的时候,每一条数据都会附带一个时间戳,HBase在查询的时候,如果不指定,默认找的是最新的时间戳。时间戳称之为是数据的版本,默认每一个数据只打印最新版本
-
如果只通过行键+列名,并不能锁定唯一的一条数据,如果需要锁定唯一的一条数据,需要添加时间戳 - 通过行键+列名+版本锁定唯一的一条数据,称之为是一个cell
-
如果需要保留多个版本的数据,需要在建表的时候就指定保留的版本数
二、基本概念
- rowkey行键:
a. 行键类似于传统关系型数据库中的主键
b. 不同于主键之处在于行键不属于任何列族
c. 在建表的时候不需要指定行键,在添加数据的时候才指定行键
d. 在HBase中,行键会默认进行排序,并且是按照字典序排序 - column family列族/列簇:
a. 类似于传统关系型数据库中的单个表
b. 在HBase中,一个表中至少要包含一个列族,理论上不限制列族的数量,但是实际开发过程中一个表中的列族数量一般不超过3个
c. 列族在定义表的时候就需要指定,表建立好之后列族的个数就不能改动了
d. 每一个列族可以包含0到多个列
e. HBase不强调列,列可以动态的增删,每一个列必须属于某一个列族 - namespace:
a. 类似于关系型数据库中的database
b. 在HBase中,每一个表都属于一个namespace
c. 如果一个表没有指定namespace,那么在default中
三、命令
命令 解释
get ‘person’,‘p1’ 获取person表中行键为p1的值
get ‘person’, ‘p1’, ‘basic’ 获取person表中行键为p1,列族为basic的值
get ‘person’, ‘p1’, ‘basic:name’ 获取person表中行键为p1,列为basic:name的值
create ‘person’, ‘basic’, ‘info’ 创建person表,包含basic和info列族
put ‘person’, ‘p1’, ‘basic:age’, 15 向person表中添加数据,行键为p1,列为basic:age,值为15
scan ‘person’ 扫描person整表
scan ‘person’, {COLUMNS=>[‘info’]} 获取person表中info列族的值
scan ‘person’, {COLUMNS=>[‘basic:name’]} 获取person列族中basic:name列的值
delete ‘person’, ‘p2’, ‘info:addr’ 删除person表中,行键为p2,列为info:addr的值
deleteall ‘person’, ‘p1’ 删除person表中,行键为p1的数据
disable ‘person’ 禁用表
delete ‘person’ 删除表
create ‘person’, {NAME=>‘basic’, VERSIONS=>3}, {NAME=>‘info’, VERSIONS=>4} 创建person表,包含2个列族:basic以及info。其中basic列族保留3个版本的数据,info列族要保留4个版本的数据
get ‘person’, ‘p1’, {COLUMN=>‘basic:name’, VERSIONS=>4} 获取person表中,basic:name列的4个版本数据
create ‘hbasedemo:orders’, ‘basic’ 在hbasedemo名称空间下创建一个orders表
list_namespace_tables ‘hbasedemo’ 列出hbasedemo名称空间下所有的表
drop_namespace ‘hbasedemo’ 要求名称空间为空才能删除
细节
一、HRegion
- 从行键方向上,将表进行切分,会切分出一个或者多个HRegion
- 每一个HRegion都会放在一个HRegionServer上
- 因为行键是排序的,所以同一个表的HRegion之间,数据是不会交叉的
- 切分HRegion的意义:
a. 能够有效的提高HBase的吞吐量
b. 能够进行数据的分布式存储 - 当HRegion达到一定大小(默认是10G)的时候,平均分裂为2个HRegion,其中的一个HRegion会转移到其他节点上
- 每一个HRegion都会包含1到多个HStore,HStore的数量由列族的数量决定。每一个列族对应一个HStore
- 每一个HStore中包含1个memStore(写缓存)以及0到多个StoreFile/HFile
- HRegion虽然是分布式存储的最小单元,但并不是存储的最小单元
- HRegion是存储在DataNode上,由HRegionServer来管理,所以实际开发过程中,将HRegionServer和DataNode部署在相同的节点上
10.
二、Zookeeper的作用
10. 当启动HBase的时候,HBase会在Zookeeper上注册一个/hbase节点
11. HRegionServer会在Zookeeper的/hbase/rs节点下注册一个临时节点,由Zookeeper监控HRegionServer的存活情况。HRegionServer会给Zookeeper发送心跳维系这个临时节点,如果Zookeeper没有收到心跳,这个临时节点也会消失
12. HMaster在启动之后会在Zookeeper下注册节点,其中active HMaster会注册到/hbase/master节点下,backup HMaster会注册到/hbase/backup-masters,注册都是临时节点。如果Zookeeper监控到master节点消失,就会从backup-masters节点中选取一个节点切换为active状态
三、HMaster
13. HMaster在启动之后会在Zookeeper上注册临时节点,其中HMaster的状态分为active和backup状态
14. 通过sh hbase-daemon.sh start master单独启动HMaster
15. HMaster的状态由启动顺序决定:先启动的节点成为active状态,后启动的HMaster自动成为backup状态
16. HMaster不存在单点故障,因为可以选择启动多个HMaster
17. 当启动backup HMaster的时候,active HMaster监测到了这个节点。active HMaster监控Zookeeper上/hbase/backup-masters的变化,如果发现这个节点下多了子节点则表示新添了一个backup HMaster
18. active HMaster和backup HMaster之间要进行热备,所以实际过程中一般HMaster的个数不超过3个
19. HMaster的作用:
a. 管理HRegionServer
b. 管理表结构(DDL - 表的增删 - create/disable/enable/drop)
20. 如果是表中数据进行操作(dml),不经过HMaster
21. HBase的元数据:namespace、table、column family等
22. HBase0.94之前第一次读写数据的流程
23. HBase0.94之后的读写流程:
a. .meta.不再允许切分
b. 客户端会自动缓存.meta.的位置
c. 客户端会自动缓存HRegion的位置。随着HBase集群运行时间的延长,客户端缓存的位置会越来越多,读写效率会越来越高。但是如果这个过程中发生HRegion的转移或者客户端宕机,那么缓存就会失效需要重新建立
四、HRegionServer
24. HRegionServer负责管理HRegion,每一个HRegionServer最多能管理1000个HRegion
25. HRegionServer包含了一个WAL、一个BlockCache以及0个或者多个HRegion
26.
- WAL - Write Ahead Log - HLog
a. 用于记录写操作的
b. 在HRegionServer接收到写操作的时候,先将操作记录到WAL中,记录成功之后再写到memStore中。如果memStore达到指定条件,会冲刷到StoreFile/HFile
c. 意义是保证操作不会丢失 - BlockCache - 读缓存 - 默认是128M
a. 意义是为了提高读取效率
b. BlockCache在缓存的时候,采用了"局部性"原理:
i. 时间局部性:如果一条数据被读取过,那么认为这条数据再次被读取的概率会高于没有被读取过的数据,那么这条数据就会被缓存 - 通俗来说,就是读过的数据就会被缓存
ii. 空间局部性:如果一条数据被读取过,那么认为这条数据相邻的数据被读取的概率会高于其他数据,此时这条数据相邻的数据也会被缓存
c. 采用局部性的目的实际上是为了提高命中率
d. 采取LRU策略:删除最长时间不用的数据
流程
一、写流程
- 客户端发起写请求到Zookeeper,获取到.meta.文件的位置,客户端会缓存这个文件的位置
- 读取.meta.文件,然后获取到要操作的HRegion所在的HRegionServer
- HRegionServer接收到请求之后,会先将请求记录到WAL中。在HBase0.96版本之前,WAL只允许串行写,从0.96开始,允许并行写(NIO的管道机制)
- WAL记录成功之后,然后会将数据写到memStore中。数据在memStore中会进行排序:行键 -> 列族名 -> 列名 -> 时间戳,行键、列族名、列名字典序,时间戳是倒叙
- memStore达到一定条件之后会冲刷到StoreFile/HFile中:
a. memStore到达128M
b. 一个HRegionServer上所有的memStore占用的内存达到物理内存的35%,会将大一些的memStore进行冲刷
c. 默认情况下,WAL达到1G - 单个HFile中的数据是有序的,但是所有的HFile之间是局部有序的
- HFile的格式:
a. DataBlock:存储数据
i. Magic是一个魔数,本质上就是一个随机数,用于校验这个Block是否被更改;KeyValue存储实际数据的位置
ii. 每一个KeyValue对应一条数据
iii. 每一个DataBlock都保持了起始行键和结束行键
iv. 一个DataBlock中有多个KeyValue
v. DataBlock默认是64KB大小。调小DataBlock适合于字段查询,调大DataBlock适合于遍历
vi. DataBlock是HBase中数据存储的基本单位,空间局部性在进行缓存的时候就是以DataBlock为单位缓存 - 即如果这个DataBlock中的某一条数据被读取,那么整个DataBlock就会被缓存
b. MetaBlock:元数据信息,不关注
c. FileInfo:对HFile的描叙信息
d. DataIndex:记录了每一个DataBlock的起始和结束字节位置
e. MetaIndex:记录了每一个MetaBlock的起始和结束字节位置
f. Trailer:固定4个字节,记录了DataIndex以及MetaIndex的起始字节 - 在HFile的高版本中,引入了BloomFilter
二、读流程
- 数据可能存储在BlockCache、memStore以及HFile中
- 读取数据的时候先从BlockCache中读取
- 如果BlockCache中没有,再试图从memStore中读取
- 如果memStore中没有,那么从HFile读取数据,根据行键的范围以及布隆过滤器来筛选,筛选掉没有指定数据的HFile,剩余的HFile中不代表有这个数据
三、合并机制
- minor compaction:将相邻的几个小的HFile合并成一个大的HFile
- major compaction:将这个HStore中所有的HFile合并成一个
- 在默认情况下,HBase使用的是minor compaction
- 在合并过程中,数据会进行整体的排序,会舍弃掉一部分数据:被删除的数据、超过版本的数据