0%

HBase快速上手

HBase头图

HBase 是一个开源的非关系型分布式数据库(NoSQL),它使用 Java 语言实现了 Google 的 BigTable,运行于 HDFS 文件系统之上,为 Hadoop 提供类似于 BigTable 规模的服务,可以对稀疏文件提供极高的容错率。


概述

就像 HDFS 和 MapReduce 是 Google 的 GFS 和 MapReduce 的实现,HBase 是 Google BigTable 的开源 Java 版本,它建立在 HDFS 之上,提供高可靠性、高性能、列存储、可伸缩、实时读写 NoSQL 的非关系型数据库系统。HBase 介于 NoSQL 和 RDBMS 之间,仅能通过行键(row key)和行键的 range 来检索数据,仅支持单行事务(可通过 Hive 来实现多表 join 等复杂操作),主要用来存储结构化和半结构化的松散数据。

HBase 中的表一般有这样的特点:

  • 大:一个表可以有上十亿行,上百万列;
  • 面向列:面向列(族)的存储和权限控制,列(族)独立检索;
  • 稀疏:对于为空(null)的列,并不占用存储空间,因此表可以设计的非常稀疏。

HBase表的组成

表模型

HBase表模型

Table:表,由多个行组成,表名作为路径的一部分存储在文件系统中
ROW:行,由多个列族组成,为逻辑上的行
RowKey:行键,每一行根据 RowKey 进行字典排序,因此行键的设计非常重要
Column Family:列族/列簇,由一个或多个列组成,在磁盘上是按列族存储数据的,因此在创建表的时候就必须指定列族
Column:列,由列族加上列的标识组成,一般是列簇:列标识,可以动态定义,创建表的时候无需指定列标识
Column Qualifier:列标识,用来具体描述每一列
Timestamp:时间戳,用来记录 HBase 数据的版本,每次生成或修改数据时都保存一个时间戳
Cell:单元,用来保存具体的数据,不记录原本的数据类型,全部以byte[]类型存储,因此使用时需要显示转换为原来的类型,由{row key, column( =<family> + <label>), version}进行唯一标识

HBase 表中最基本的单位是列(column),若干列形成一行(row),并由唯一的行键(row key)来确定存储;一个表中有若干行,这些行按照行键的字典排序进行存储;HBase 中存储的数据可以保留多个版本,原因是每一个单元格(cell)中存储了不同的值。

列族

若干列构成一个列族(column family),这不仅有助于构建数据的语义边界,还有助于给它们设置某些特性(比如压缩),或者指示存储在内存中。一个列族的所有列存储在同一个底层的文件中,这个文件叫作 HFile。列族需要在创建表时定义好,并且不能修改得太频繁,由于当前实现上的缺陷导致列族数量也不能太多(几十个或更少)。列族的名称必须由可打印字符组成。

列限定符

列的常见引用格式为 family:qualifierfamily 为列族,qualifier 为列(限定符)。列名可以是任意字节数组,并且数量没有限制(可以有数百万个列),列值也没有类型和长度的限制。

单元格

https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/Cell.html

由行键、列族、列限定符、数据和时间戳组合起来叫做一个单元格( Cell)。这里的行键、列族、列修饰符和时间戳其实可以看作是定位属性(类似坐标),最终确定了一个数据。下图中的一行相等于Hbase中的一个单元格:

时间戳

每一列的值或单元格的值

架构

HBase基础架构

HMaster 为主节点,HRegionServer 为从节点。HBase 强依赖于 Zookeeper 和 Hadoop,启动 HBase 之前一定要确保 Zookeeper 和 Hadoop 启动成功并正常运行。

HMaster

  • 为 HRegionServer 分配 Region
  • 负责 HRegionServer 的负载均衡
  • 处理 HRegionServer 故障转移,重新分配其中的 Region
  • 处理 Region 的分配或移除
  • 处理元数据的变更
  • 回收 HDFS 上的垃圾文件
  • 通过 Zookeeper 发布自己的位置给 Client

HRegionServer

  • 负责存储 HBase 的实际数据
  • 维护 HMaster 分配给它的 Region
  • 维护 HLog
  • 存储到 HDFS
  • 切分过大的 HFile

Hlog:HBase 读写数据的时候,数据会在内存中保留,满足条件(如 128 MB 或 1 小时等)后再写进磁盘生成 HFile 文件。为了避免数据在内存中丢失,HBase 使用 WAL 机制(Write-Ahead logfile),在数据写入到内存之前先生成日志文件,这样在系统出现故障的时候,可以通过日志文件重建数据,避免数据丢失。

Region一个 Region 对应一张 HBase 表(或表的分片),数据在磁盘上以 HFile 文件进行存储。单个 HFile 文件如果过大(10 GB),会被 HRegionServer 切分为两个,相应的 Region 也会被切分成两个 Region 分片。一个 HRegionServer 中可以有多个不同的 Region。

Store一个 Store 对应 HBase 表中的一个列族(Column Family)。因为一张表可以有多个列族,所以一个 Region 中可以有多个 Store。Store 又分为两部分:

  • MemoryStore:内存存储,用来保存当前的数据操作,默认大小为 128 MB。在记录 Hlog 日志之后,数据便写入 MemoryStore。
  • StoreFile:文件存储,每当 MemoryStore 存储的数据达到阈值(如 128 MB 或 1 小时等)便写入到磁盘,生成一个 StoreFile(HFile 文件)。大量的 HFile 小文件会通过 Compact 机制合并成一个 HFile 大文件,再写入 HDFS。

HDFS

负责存储 HFile 文件,单个 HFile 文件达到 10 GB 后会被一分为二。

Zookeeper

  • 保证任何时候,集群中只有一个 HMaster 处于 Active
  • 存储所有 Region 的寻址入口
  • 实时监控 HRegionServer 的状态,将上下线信息实时通知给 HMaster
  • 存储 HBase 的 schema,包括表和表中的列族

Client

包含访问 HBase 的接口,Client 维护着一些 cache 来加快对 HBase 的访问,如 Regione 的位置信息

安装

HBase强依赖 Zookeeper和 Hadoop,安装 HBase 之前一定要保证 Zookeeper 和 Hadoop 启动成功并正常运行。

下载安装

CDH版本的软件包地址: http://archive.cloudera.com/cdh5/cdh/5/

HBase的下载地址: http://archive.cloudera.com/cdh5/cdh/5/hbase-1.2.0-cdh5.14.0.tar.gz

安装 HBase:

1
tar -zxvf /export/softwares/hbase-1.2.0-cdh5.14.0.tar.gz -C /export/servers/

修改配置文件

  1. node01 修改文件hbase-env.sh
/export/servers/hbase-1.2.0-cdh5.14.0/conf/hbase-env.sh
1
2
3
4
5
# export JAVA_HOME=/usr/java/jdk1.6.0/
+ export JAVA_HOME=/usr/java/jdk1.8.0_211/

# export HBASE_MANAGES_ZK=true
+ export HBASE_MANAGES_ZK=false
  1. node01 修改配置文件hbase-site.xml

注:0.98之前版本没有.port配置,默认端口为60000

/export/servers/hbase-1.2.0-cdh5.14.0/conf/hbase-site.xml
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
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://node01:8020/hbase</value>
</property>

<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>

<property>
<name>hbase.master.port</name>
<value>16000</value>
</property>

<property>
<name>hbase.zookeeper.quorum</name>
<value>node01:2181,node02:2181,node03:2181</value>
</property>

<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/export/servers/zookeeper-3.4.5-cdh5.14.0/zkdatas</value>
</property>
</configuration>
  1. node01 修改配置文件regionservers
/export/servers/hbase-1.2.0-cdh5.14.0/conf/regionservers
1
2
3
4
- localhost
+ node01
+ node02
+ node03
  1. node01 创建back-masters文件,实现HMaster高可用:
/export/servers/hbase-1.2.0-cdh5.14.0/conf/
1
2
# vim backup-masters
node02

分发

分发 node01 上的 HBase 到其他节点:

/export/servers/
1
2
scp -r hbase-1.2.0-cdh5.14.0/ node02:$PWD
scp -r hbase-1.2.0-cdh5.14.0/ node03:$PWD

创建软链接

因为 HBase 需要读取 Hadoop 的 core-site.xml 以及 hdfs-site.xml 中的配置文件信息,所以我们三台机器都要执行以下命令创建软链接:

1
2
ln -s /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop/core-site.xml /export/servers/hbase-1.2.0-cdh5.14.0/conf/core-site.xml
ln -s /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop/hdfs-site.xml /export/servers/hbase-1.2.0-cdh5.14.0/conf/hdfs-site.xml

添加环境变量

三台机器都要执行以下命令添加HBASE_HOME的环境变量:

1
2
3
# vim /etc/profile
export HBASE_HOME=/export/servers/hbase-1.2.0-cdh5.14.0
export PATH=:$HBASE_HOME/bin:$PATH

启动

启动集群

node01 执行以下命令进行启动 HBase 集群:

/export/servers/hbase-1.2.0-cdh5.14.0/
1
bin/start-hbase.sh

启动HBase

注:HBase启动的时候会产生警告,这是因为JDK版本导致的,如果服务器使用的是 JDK8 就会产生这样的警告,不影响正常运行。可以通过注释掉所有机器中 hbase-env.sh 文件中的 HBASE_MASTER_OPTSHBASE_REGIONSERVER_OPTS 两个配置来解决这个问题。

启动单个节点

也可以执行以下命令单节点进行启动:

/export/servers/hbase-1.2.0-cdh5.14.0/
1
2
3
4
5
# 启动HMaster
# bin/hbase-daemon.sh start master

# 启动HRegionServer
# bin/hbase-daemon.sh start regionserver

为了解决 HMaster 单点故障问题,可以在 node02 上启动 HMaster 节点的进程,以实现 HMaster 的高可用。

访问监控页面

浏览器页面访问:http://node01:60010/master-status

HBase页面访问

Shell

HBase 的常用 shell 操作。

进入客户端

1
2
3
4
5
# /export/servers/hbase-1.2.0-cdh5.14.0/bin/hbase shell
hbase(main):001:0>

#查看帮助
hbase(main):001:0> help

表模型

HBase表模型

Table:表,由多个行组成,表名作为路径的一部分存储在文件系统中
ROW:行,由多个列族组成,为逻辑上的行
RowKey:行键,每一行根据 RowKey 进行字典排序,因此行键的设计非常重要
Column Family:列族/列簇,由一个或多个列组成,在磁盘上是按列族存储数据的,因此在创建表的时候就必须指定列族
Column:列,由列族加上列的标识组成,一般是列簇:列标识,可以动态定义,创建表的时候无需指定列标识
Column Qualifier:列标识,用来具体描述每一列
Timestamp:时间戳,用来记录 HBase 数据的版本,每次生成或修改数据时都保存一个时间戳
Cell:单元,用来保存具体的数据,不记录原本的数据类型,全部以byte[]类型存储,因此使用时需要显示转换为原来的类型,由{row key, column( =<family> + <label>), version}进行唯一标识

查看与创建表

查看数据库中有哪些表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- list
hbase(main):001:0> list
TABLE
testdb
-- 查看表结构
hbase(main):003:0> desc 'testdb'
Table testdb is ENABLED
testdb
COLUMN FAMILIES DESCRIPTION
{NAME => 'c', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_D
ATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER =>
'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMP
RESSION => 'SNAPPY', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
{NAME => 'd', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_D
ATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER =>
'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMP
RESSION => 'SNAPPY', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
{NAME => 'm', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_D
ATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER =>
'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMP
RESSION => 'SNAPPY', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
3 row(s)
Took 0.1930 seconds

创建表,同时创建列族:

1
2
3
4
5
--创建user表,包含info、data两个列族
create 'user', 'info', 'data'

--在创建user表时指定info列族中的数据保存3个版本
create 'user', {NAME => 'info', VERSIONS => '3'},{NAME => 'data'}

添加数据

添加/更新数据到指定表中的指定列族中,同时创建列、RowKey 和值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 向user表中插入信息,row key为rk0001,列族info中添加name列标示符,值为zhangsan
put 'user', 'rk0001', 'info:name', 'zhangsan'

-- 向user表中插入信息,row key为rk0001,列族info中添加gender列标示符,值为female
put 'user', 'rk0001', 'info:gender', 'female'

-- 向user表中插入信息,row key为rk0001,列族info中添加age列标示符,值为20
put 'user', 'rk0001', 'info:age', 20

-- 向user表中插入信息,row key为rk0001,列族data中添加pic列标示符,值为picture
put 'user', 'rk0001', 'data:pic', 'picture'

-- 继续插入一批数据
put 'user', 'rk0002', 'info:name', 'fanbingbing'
put 'user', 'rk0002', 'info:gender', 'female'
put 'user', 'rk0002', 'info:nationality', '中国'

查询数据

直接查询

通过RowKey进行直接查询

1
2
#获取user表中RowKey为rk0001的所有信息
get 'user', 'rk0001'

查看RowKey下面的某个列族的信息

1
2
#获取user表中row key为rk0001,info列族的所有信息
get 'user', 'rk0001', 'info'

查看RowKey指定列族指定字段的值

1
2
#获取user表中row key为rk0001,info列族的name、age列标示符的信息
get 'user', 'rk0001', 'info:name', 'info:age'

查看RowKey指定多个列族的信息

1
2
3
4
5
6
#获取user表中row key为rk0001,info、data列族的信息
get 'user', 'rk0001', 'info', 'data'

get 'user', 'rk0001', {COLUMN => ['info', 'data']}

get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic']}

指定RowKey与列值查询

1
2
#获取user表中row key为rk0001,cell的值为zhangsan的信息
get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:zhangsan')"}

指定RowKey与列值模糊查询

1
2
3
#获取user表中row key为rk0001,列标示符中含有a的信息
get 'user', 'rk0001', {FILTER => "(QualifierFilter(=,'substring:a'))"}
get 'user', 'rk0002', {FILTER => "ValueFilter(=, 'binary:中国')"}

扫描

全表扫描

1
2
#查询user表中的所有信息
scan 'user'

限制扫描数量

1
2
#扫描user表中10条记录
scan 'user',{'LIMIT' => 10}

列族查询

1
2
3
4
#查询user表中列族为info的信息
scan 'user', {COLUMNS => 'info'}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 3}

多列族查询

1
2
3
#查询user表中列族为info和data的信息
scan 'user', {COLUMNS => ['info', 'data']}
scan 'user', {COLUMNS => ['info:name', 'data:pic']}

指定列族与某个列名查询

1
2
#查询user表中列族为info、列标示符为name的信息
scan 'user', {COLUMNS => 'info:name'}

指定列族与列名以及限定版本查询

1
2
#查询user表中列族为info、列标示符为name的信息,并且版本最新的5个
scan 'user', {COLUMNS => 'info:name', VERSIONS => 5}

指定多个列族与按照数据值模糊查询

1
2
#查询user表中列族为info和data且列标示符中含有a字符的信息
scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}

RowKey的范围值查询

1
2
#查询user表中列族为info,rk范围是[rk0001, rk0003)的数据
scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}

指定RowKey模糊查询

1
2
#查询user表中row key以rk字符开头的
scan 'user',{FILTER=>"PrefixFilter('rk')"}

指定数据范围值查询

1
2
#查询user表中指定范围的数据
scan 'user', {TIMERANGE => [1392368783980, 1392380169184]}

Java

使用 Java 代码实现 HBase 数据库当中的数据增删改查的操作。

导入依赖

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.6.0-mr1-cdh5.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.0-cdh5.14.0</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!--<scope>test</scope>-->
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<!--<scope>test</scope>-->
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<!--<verbal>true</verbal>-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*/RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
  • 本文作者: SANNAHA
  • 本文链接: https://sannaha.moe/HBase/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!