HBase介绍安装与操作

介绍

  • HBase是Apache Hadoop的数据库,能够对大型数据提供随机、实时的读写访问,是Google的BigTable的开源实现。
  • HBase的目标是存储并处理大型的数据,更具体地说仅用普通的硬件配置,能够处理成千上万的行和列所组成的大型数据库。
  • HBase是一个开源的、分布式的、多版本的、面向列的存储模型。可以直接使用本地文件系统,也可使用Hadoop的HDFS文件存储系统。

为了提高数据的可靠性和系统的健壮性,并且发挥HBase处理大型数据的能力,还是使用HDFS作为文件存储系统更佳。

另外,HBase存储的是松散型数据,具体来说,HBase存储的数据介于映射(key/value)和关系型数据之间。如下图所示,HBase存储的数据从逻辑上看就是一张很大的表,并且它的数据列可以根据需要动态增加。每一个cell中的数据又可以有多个版本(通过时间戳来区别),从下图来看,HBase还具有 “ 向下提供存储,向上提供运算 “ 的特点。

逻辑结构

逻辑上,HBase的数据模型和关系型数据库类似,有表,有行列。但是从底层物理存储结构k-v来看,它更像一个多维度map。

20200423162536

物理存储结构

20200423162547

数据模型
Name Space

命名空间,类似于关系型数据库的 DatabBase 概念,每个命名空间下有多个表。HBase有两个自带的命名空间,分别是 hbase 和 default,hbase 中存放的是 HBase 内置的表,default 表是用户默认使用的命名空间。

Region

类似于关系型数据库的表概念。不同的是,HBase 定义表时只需要声明列族即可,不需要声明具体的列。往 HBase 写入数据时,字段可以动态、按需指定。因此,和关系型数据库相比,HBase 能够轻松应对字段变更的场景。

Row

HBase表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索。

Column

HBase 中的每个列都由 Column Family(列族)和 Column Qualifier(列限定符)进行限定,例如 info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义。

Time Stamp

用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入 HBase 的时间。

Cell

由{rowkey, column Family:column Qualifier, time Stamp} 唯一确定的单元。cell 中的数据是没有类型的,全部是字节码形式存贮。

HBase体系架构

HBase的服务器体系结构遵从简单的主从服务器架构,它由HRegion Server群和HBase Master服务器构成。HBase Master负责管理所有的HRegion Server,而HBase中的所有RegionServer都是通过ZooKeeper来协调,并处理HBase服务器运行期间可能遇到的错误。

HBase Master Server本身并不存储HBase中的任何数据,HBase逻辑上的表可能会被划分成多个Region,然后存储到HRegion Server群中。HBase Master Server中存储的是从数据到HRegion Server的映射。HBase体系结构如下图所示:

20200423162558

Client

HBase Client使用HBase的RPC机制与HMaster和HRegionServer进行通信,对于管理类操作,Client与HMaster进行RPC;对于数据读写类操作,Client与HRegionServer进行RPC。

Zookeeper

Zookeeper Quorum中除了存储了ROOT表的地址和HMaster的地址,HRegionServer也会把自己以Ephemeral方式注册到 Zookeeper中,使得HMaster可以随时感知到各个HRegionServer的健康状态。此外,Zookeeper也避免了HMaster的单点问题。

HMaster
  • 管理用户对表的操作:create, delete, alter;
  • 管理HRegion Server的负载均衡,调整Region分布;
  • 在Region Split后,负责新Region的分配;
  • 在HRegion Server停机后,负责失效HRegion Server 上的Regions迁移。
    HDFS
    HDFS 为 HBase 提供最终的底层数据存储服务,同时为 HBase 提供高可用的支持。
    Region
    20200423162607

当表的大小超过设置值的时候,HBase会自动地将表划分为不同的区域,每个区域包含所有行的一个子集。对用户来说,每个表是一堆数据的集合,靠主键来区分。从物理上来说,一张表被拆分成了多块,每一块就是一个Region。一个Region会保存一个表里面某段连续的数据,从开始主键到结束主键,一张完整的表格是保存在多个Region上面。

HRegionServer

Region 的管理者,主要作用:对于数据的操作:get, put, delete;对于 Region 的操作:splitRegion、compactRegion。

20200423162617

  • 所有的数据库数据一般是保存在Hadoop HDFS分布式文件系统上面,用户通过一系列HRegion Server获取这些数据,一台机器上面一般只运行一个HRegion Server,且每一个区段的HRegion也只会被一个HRegion Server维护。
  • HRegion Server主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。
  • HRegion Server内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,Region中由多个Store组成。每个Store对应了Table中的一个Column Family的存储,可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。
    HStore​(StoreFile)
  • HBase存储的核心。由MemStore和StoreFile组成。。
  • MemStore是Sorted Memory Buffer

Client写入 -> 存入MemStore,一直到MemStore满 -> Flush成一个StoreFile,直至增长到一定阈值 -> 触发Compact合并操作 -> 多个StoreFile合并成一个StoreFile,同时进行版本合并和数据删除 -> 当StoreFiles Compact后,逐步形成越来越大的StoreFile -> 单个StoreFile大小超过一定阈值后,触发Split操作,把当前Region Split成2个Region,Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer上,使得原先1个Region的压力得以分流到2个Region上。

20200423162625

所以,HBase只是增加数据,有所得更新和删除操作,都是在Compact阶段做的,所以,用户写操作只需要进入到内存即可立即返回,从而保证I/O高性能。

  • HFile是底层的实现。
    MemStore
    写缓存,由于 HFile 中的数据要求是有序的,所以数据是先存储在 MemStore 中,排好序后,等到达刷写时机才会刷写到 HFile,每次刷写都会形成一个新的 HFile。
    Hlog
    在分布式系统环境中,无法避免系统出错或者宕机,因此一旦HRegion Server意外退出,MemStore中的内存数据将会丢失,这就需要引入HLog了。每个HRegion Server中都有一个HLog对象。

每个HRegionServer中都会有一个HLog对象,HLog是一个实现Write Ahead Log的类,每次用户操作写入Memstore的同时,也会写一份数据到HLog文件,HLog文件定期会滚动出新,并删除旧的文件(已持久化到StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知,HMaster首先处理遗留的HLog文件,将不同region的log数据拆分,分别放到相应region目录下,然后再将失效的region重新分配,领取到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

Hbase的存储格式

HBase中的所有数据文件都存储在Hadoop HDFS文件系统上为例,主要包括上述提出的两种文件类型:

1
2
HFile, HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile。
HLog File,HBase中WAL(Write Ahead Log) 的存储格式,物理上是Hadoop的Sequence File。
  • Hbase的存储格式(HFile)*

20200423162635

1
2
3
4
5
6
7
8
9
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数组里面包含了很多项,并且有固定的结构。

20200423162645

1
2
3
4
5
KeyLength和ValueLength:两个固定的长度,分别代表Key和Value的长度
Key部分:Row Length是固定长度的数值,表示RowKey的长度,Row 就是RowKey
Column Family Length是固定长度的数值,表示Family的长度
接着就是Column Family,再接着是Qualifier,然后是两个固定长度的数值,表示Time Stamp和Key Type(Put/Delete)
Value部分没有这么复杂的结构,就是纯粹的二进制数据
  • Hbase的存储格式(HLog File)*

20200423162657

  HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。

  HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue

ROOT表和META表

用户表的Regions元数据被存储在.META.表中,随着Region的增多,.META.表中的数据也会增大,并分裂成多个Regions。为了定位.META.表中各个Regions的位置,把.META.表中所有Regions的元数据保存在-ROOT-表中,最后由ZooKeeper记录-ROOT-表的位置信息。所有客户端访问用户数据前,需要首先访问ZooKeeper获得-ROOT-的位置,然后访问-ROOT-表获得.META.表的位置,最后根据.META.表中的信息确定用户数据存放的位置,如下图所示。

20200423162706

ROOT 表永远不会被分割,它只有一个Region,这样可以保证最多需要三次跳转就可以定位任意一个Region。为了加快访问速度,.META.表的Regions全部保存在内存中。客户端会将查询过的位置信息缓存起来,且缓存不会主动失效。如果客户端根据缓存信息还访问不到数据,则询问只有相关.META.表的Region服务器,试图获取数据的位置,如果还是失败,则询问-ROOT-表相关的.META.表在哪里。最后,如果前面的信息全部失效,则通过ZooKeeper重新定位Region的信息。所以如果客户端上的缓存全部是失效,则需要进行6次网络来回,才能定位到正确的Region。

20200423162716

MapReduce On HBase

在HBase系统上运行批处理运算,最方便和实用的模型依然是MapReduce,如下图:

20200423162725

HBase Table和Region的关系,比较类似HDFS File和Block的关系,HBase提供了配套的TableInputFormat和TableOutputFormat API,可以方便的将HBase Table作为Hadoop MapReduce的Source和Sink,对于MapReduce Job应用开发人员来说,基本不需要关注HBase系统自身的细节。

写流程

20200423162734

1
2
3
4
5
6
7
1)Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server。 
2)访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
3)与目标 Region Server 进行通讯;
4)将数据顺序写入(追加)到 WAL;
5)将数据写入对应的 MemStore,数据会在 MemStore 进行排序;
6)向客户端发送 ack;
7)等达到 MemStore 的刷写时机后,将数据刷写到 HFile。
MemStore Flush

20200423162743

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 写数据。

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 的总大小减小到上述值以下。 当 region server 中 memstore 的总大小达到java_heapsize✖hbase.regionserver.global.memstore.size(默认值 0.4)时,会阻止继续往所有的 memstore 写数据。

  1. 到达自动刷写的时间,也会触发 memstore flush。自动刷新的时间间隔由该属性进行配置 hbase.regionserver.optionalcacheflushinterval(默认 1 小时)。

4.当 WAL 文件的数量超过 hbase.regionserver.max.logs,region 会按照时间顺序依次进行刷写,直到 WAL 文件数量减小到 hbase.regionserver.max.log 以下(该属性名已经废弃,现无需手动设置,最大值为 32)。

读流程

20200423162755

1
2
3
4
5
1)Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server。
2)访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
3)与目标 Region Server 进行通讯;
4)分别在 Block Cache(读缓存),MemStore 和 Store File(HFile)中查询目标数据,并将查到的所有数据进行合并。此处所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete)。
5) 将从文件中查询到的数据块(Block,HFile 数据存储单元,默认大小为 64KB)缓存到Block Cache。 6)将合并后的最终结果返回给客户端。
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,并且会清理掉过期和删除的数据

20200423162804

Region Split

默认情况下,每个 Table 起初只有一个 Region,随着数据的不断写入,Region 会自动进行拆分。刚拆分时,两个子 Region 都位于当前的 Region Server,但处于负载均衡的考虑,HMaster 有可能会将某个 Region 转移给其他的 Region Server。

Region Split 时机:

1
2
1.当1个region中的某个Store下所有StoreFile的总大小超过hbase.hregion.max.filesize, 该 Region 就会进行拆分(0.94 版本之前)。
2. 当 1 个 region 中 的 某 个 Store 下所有 StoreFile 的 总 大 小 超 过 Min(R^2 * "hbase.hregion.memstore.flush.size",hbase.hregion.max.filesize"),该 Region 就会进行拆分,其中 R 为当前 Region Server 中属于该 Table 的个数(0.94 版本之后)。

20200423162817

安装

1、docker安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
docker run -d -h docker-hbase \
-p 2181:2181 \
-p 8081:8080 \
-p 8085:8085 \
-p 9090:9090 \
-p 9000:9000 \
-p 9095:9095 \
-p 16000:16000 \
-p 16010:16010 \
-p 16201:16201 \
-p 16301:16301 \
-p 16020:16020\
--name hbase \
harisekhon/hbase

-d 表示后台运行
-h 该容器的host为docker-hbase
-p 宿主机端口:容器端口
--name 该容器的名字

启动成功,访问web界面。

20200423162835

进入容器可以看到hbase正常

1
2
3
4
5
6
7
8
[root@VM_0_3_centos ~]# docker exec -it 6a /bin/bash
bash-4.4# hbase shell
2020-01-08 10:13:42,496 WARN [main] util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
HBase Shell
Use "help" to get list of supported commands.
Use "exit" to quit this interactive shell.
For Reference, please visit: http://hbase.apache.org/2.0/book.html#shell
Version 2.1.3, rda5ec9e4c06c537213883cca8f3cc9a7c19daf67, Mon Feb 11 15:45:33 CST 2019

2、集群搭建

3、常用操作命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
查看集群状态status

查看hbase版本version

查看所有表list

创建表 create 't1','[Column Family 1]','[Column Family 2]'

例如创建一个菜谱表,调味料为一个列族(类),食材则为另一个列族(类),脚本为create 'cookbook','seasoning','ngredients'

查看表的结构describe 't1'
删除表
disable 't1' 之后 drop 't1'
检查表是否存在exists 't1'
获取表中所有数据scan 't1'
-获取表中前10行数据scan 't1',{LIMIT=>10}
获取指定column(ad:pv)的前10行数据scan 't1',{COLUMNS=>['ad:pv'],LIMIT=>10}
加Filter:如过滤rowkey以“2015”开头的前10行数据 scan 't1',{FILTER=>"PrefixFilter('2015')",LIMIT=>10}
查询rowkey=001下所有的数据get 't1','001'
查询rowkey=001下family=ad,column=pvget 't1','001','ad:pv' 或者 get 't1','001',{COLUMN=>'ad:pv'}
添加数据put <table>,<rowkey>,<family:column>,<value>,<timestamp>
例如:向’t1’表中添加rowkey=002,family=ad,column=pv,value=1000,时间戳默认
put 't1','002','ad:pv','1000'

删除rowkey=002的所有数据deleteall 't1','002'
删除rowkey=002中ad:pv数据delete 't1','002','ad:pv'
清空表truncate 't1'
统计行数count 't1'
查询表t1中的行数,每100条显示一次count 't1',{INTERVAL=>100}

附录:Hbase默认端口

20200423162851