HBase
HBase的特性
- 容量大
HBase 分布式数据库中的表可以存储成千上万的行和列组成的数据 - 面向列
Hbase 面向列存储和权限控制,支持独立检索。按照列存储根据数据动态增加列,并且可以单独对列进行各种操作。 - 多版本
表中的每一个列的数据存储都会有多个版本(version), 一般每列对应一条数据,但是有些数据会有多个版本,例如个人的历史修改信息。 - 稀疏性
表允许为空,空列不会占用存储空间,因此表可以设计的非常稀疏 - 扩展性
底层依赖于 HDFS。当磁盘空间不足是,可以动态增加机器节点(DataNode)来增加磁盘空间,从而避免关系型数据库一样需要数据迁移。 - 高可靠性
底层使用的是 HDFS, HDFS 具有备份机制, Spark 出现问题时,Replication(即副本)机制能够保证数据不会发生丢失或损坏。
HBase 与传统数据库的区别
- 存储模式。传统数据库基于行存储,而HBase是基于列存储
- 表字段。传统数据库表字段不能超过 30 个,而 HBase 不设限制
- 可延伸性。传统数据库存储的列是固定的,HBase可以去动态地增加列,列是不固定的
HBase 的数据模型
Row Key(行键)
每个 HBase 表中只能有一个行键,它在 HBase 中以字典序的方式存储。数据存储的规则是相近的数据存储到一起。例如www.apache.org、mail.apache.org,可以将其反转为org.apache.www、org.apache.mail, 然后进行存储,这样会把所有的 org.apache 域名存储在一起,避免子域名分散在各处.Timestamp(时间戳)
记录每次操作数据的时间,通常作为数据的版本号。Column(列)
HBase 表是有列族名、限定符以及列名组成的,其中“:”为限定符。创建 HBase 表不需要指定列,因为列是可变的,非常灵活。ColumnFamily(列族)
在 HBase 中,列族由许多列组成。同一个表里,不同列族由完全不同的属性,但是一个列族内的所有列都会有系统的属性,而属性都是定义在列族上的。c1、c2、c3 均为列族名。
| Row Key | Timestamp | Column Family:c1 | Column Family:c2 | Column Family:c3 | |||
| Column | value | Column | value | Column | value | ||
| r1 | t7 | c1:col-1 | value-1 | c3:col-1 | value-1 | ||
| t6 | c1:col-2 | value-2 | c3:col-2 | value-2 | |||
| t5 | c1:col-3 | value-3 | |||||
| t4 | |||||||
| r2 | t3 | c1:col-1 | value-1 | c2:col-1 | value-1 | c3:col-1 | value-1 |
| t2 | c1:col-2 | value-2 | |||||
| t1 | c1:col-3 | value-3 | |||||
HBase 的集群部署
HBase 通过使用 Zookeeper 来实现高可用集群。
步骤
到官网下载HBase
解压到 /export/servers/ 下
将 ${hadoop_path}/etc/hadoop 目录下的 hdfs-site.xml 和 core-site.xml 配置文件复制到 HBase 的 conf 目录下
1
cp hadoop-2.10.1/etc/hadoop/{hdfs-site.xml,core-site.xml} /export/servers/hbase-2.4.2/conf/
进入 ${hbase_path}/conf 目录修改 hbase-env.sh 配置文件, 指定 JDK 环境变量并配置 Zookeeper.
1
2export JAVA_HOME=/export/servers/jdk
export HBASE_MANAGES_ZK=false配置 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<!-- 指定Zookeeper地址,用.,.分隔 -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
<!-- 指定HBase在HDFS的存储路径 -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop01:9000/hbase</value>
</property>
<!-- 指定HBase是分布式的 -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.tmp.dir</name>
<value>./tmp</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>修改 regionservers
1
2hadoop02
hadoop03修改 backup-masters 配置文件,当中单点故障配置备用 主节点
1
hadoop02
修改 profile 文件
1
2
3
4
5
6
7vi /etc/profile
# 添加到 profile文件里
# HBase
export HBASE_HOME=/export/servers/hbase-2.4.2
# 配置zookeeper使用外部zookeeper(默认内部zookeeper)
export PATH=$PATH:$HBASE_HOME/bin:将安装目录 分发到其他服务器
1
2
3# 分发到另外两台电脑
scp -r /export/servers/hbase-2.4.2/ hadoop02:/export/servers/
scp -r /export/servers/hbase-2.4.2/ hadoop03:/export/servers/启动HBase集群
启动zookeeper 和 HDFS
1
2
3
4# 所有节点运行
zkServer.sh start
# 在主节点运行
start-dfs.sh启动HBase集群
启动HBase保证时间同步,否则报错 ClockOutOfSynException, 用data查看, 用__ntpdate –u cn.pool.ntp.org__命令同步时间.
启动HBase集群: start-hbase.sh
浏览器输入: hadoop01:16010
HBase 的基本操作
| 命令名称 | 相关说明 | 命令名称 | 相关说明 |
|---|---|---|---|
| create | 创建表 | count | 统计表中数据的行数 |
| put | 插入或更新数据 | delete | 删除指定行或列的数据 |
| scan | 扫描表并返回表的数据 | deleteall | 删除整个行或列的数据 |
| describe | 查看表的结构 | truncate | 删除整个表中的数据,不删除表结构 |
| get | 获取指定行或列的数据 | drop | 删除整个表,数据和结构都删除 |
HBase Shell 操作
1 | hbase-2.4.2/bin/hbase shell |
HBase 的 Java API 操作
常见的 Java API操作
| 类或接口名称 | 相关说明 |
|---|---|
| Admin | 类,建立客户端和 HBase 数据库的连接 |
| HBaseConfiguration | 类,将 HBase 配置添加到配置文件中 |
| HTableDescriptor | 接口,用于描述表的信息 |
| HColumnDescriptor | 类,用于描述列族的信息 |
| Table | 接口,实现 HBase 表的通信 |
| Put | 类,插入数据操作 |
| Get | 类,查询单条记录 |
| Delete | 类,删除数据 |
| Scan | 类,查询所有记录 |
| Result | 类,查询返回单条记录结果 |
- 导入 Maven 依赖
1 | <!-- ++++++++++++++++ HBase 学习 ++++++++++++++++ --> |
- Java 代码
- 连接集群,创建 HBase 表
1 | import org.apache.hadoop.conf.Configuration; |
- 插入数据
1 |
|
查看指定字段的数据
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
public void testGet() throws Exception{
// 获取一个 table 对象
Table table = conn.getTable(TableName.valueOf("t_user_info"));
// 创建 get 查询承诺书对象,指定要获取的是哪一行
Get get = new Get("user001".getBytes());
// 返回查询结果的数据
Result result = table.get(get);
// 获取结果所有的 cell
List<Cell> cells = result.listCells();
// 遍历所有的 cell
for(Cell c : cells) {
// 获取行键
System.out.println("行:" + Bytes.toString(CellUtil.cloneRow(c)));
// 得到列族
System.out.println("列族:" + Bytes.toString(CellUtil.cloneFamily(c)));
System.out.println(":" + Bytes.toString(CellUtil.cloneQualifier(c)));
System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(c)));
}
// 关闭
table.close();
conn.close();
}- 扫描数据
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
public void testScan() throws Exception {
// 获取 table 对象
Table table = conn.getTable(TableName.valueOf("t_user_info"));
// 创建 Scan 对象
Scan scan = new Scan();
// 获取查询结果
ResultScanner rs = table.getScanner(scan);
// 获取查询的数据
Iterator<Result> iterator = rs.iterator();
while (iterator.hasNext()){
// 获取当前每一行数据
Result result = iterator.next();
// 获取当前每一行的 cell 对象
List<Cell> cells = result.listCells();
for (Cell cell : cells){
// 获取行键
byte[] rowArray = cell.getRowArray();
byte[] familyArray = cell.getFamilyArray();
byte[] qualifierArray = cell.getQualifierArray();
byte[] valueArray = cell.getValueArray();
// 获取行键
System.out.println("行:" + new String(rowArray, cell.getRowOffset(), cell.getRowLength()));
System.out.println("列族::" + new String(familyArray, cell.getRowOffset(), cell.getRowLength()));
System.out.println(":" + new String(qualifierArray, cell.getRowOffset(), cell.getRowLength()));
System.out.println("值:" + new String(valueArray, cell.getRowOffset(), cell.getRowLength()));
}
System.out.println("--------------------------");
}
table.close();
conn.close();
}- 删除表
1
2
3
4
5
6
7
8
9
10
11
public void testDrop() throws Exception {
// 获取一个表的管理器
Admin admin = conn.getAdmin();
// 删除表是先需要 disable
admin.disableTable(TableName.valueOf("t_user_info"));
admin.deleteTable(TableName.valueOf("t_user_info"));
admin.close();
conn.close();
}HBase 原理
架构
HBase 构建在 HDFS 之上, HDFS 为此提供了高可用的底层存储支持, Hadoop MapReduce 为此提供了高性能的计算能力,Zookeeper 为 HBase 提供了稳定的服务和容错机制。
- Client: 通过 RPC 协议与 HBase 通信
- Zookeeper: 分布式协调服务,用作监控 HRegionServer 状态,将 HRegionServer 上线情况实时通知给 HMaster,确保集群只有一个 HMaster 在工作
- HMaster: HBase 的主节点,协调、监控 HRegionServer 以及 平衡 HRegionServer 之间的负载。 HMaster 还负责为 HRegionServer 分配 HRegion
- HRegionServer: HBase 的从节点,包括了多个 HRegion,用于响应用户 I/O 请求,向 HDFS 写入数据
- HRegion:HBase 表的分片,每个分片报错的是表中某段连续的数据。
- Store:HRegion 包含一个或多个 Store,每个 Store 都用于管理一个 Region 上的一个列族
- MemStore: 内存级缓存,MemStore 存放在 Store 中,用于保存修改的数据(K-V 形式)当存储数据达到一个阀值(默认 128M)时,数据就会被 flush 操作,将数据写入 StoreFile 文件,flush 操作由专门的线程负责。
- StoreFile: MemStore 数据写入到文件后存储的就是 StoreFile,StoreFile 底层是以 HFile 的格式保存在 HDFS 上。
- HFile: HBase 中键值对类型的数据均以 HFile 文件格式进行存储
- HLog:预写日志文件,负责记录 HBase 的修改。当 HBase 读写数据是,数据不是直接写进磁盘,而是在内存中保留一段时间。如果数据写入预写日志文件中,然后再写入内存中,一旦系统故障,可以通过日志文件恢复数据。
物理存储
- 按照行键 Row Key 的字典序进行排列,切分多个 HRegion 存储。
- 每个 Region 存储的数据是有限的,达到一个阀值(128MB)是会被等切分成两个新的 Region 。
- 一个 HRegionServer上可以存储多个 Region 但是每个 Region只能分布到一个 HRegionServer 上
- MemStore 中存储的是用户写入的数据,达到阀值时,会以 HFile 存储到 HDFS 上。
寻址机制
Zookeeper 存储的是 ROOT 表的数据,而 ROOT 表存储的是 META 表的 Regin 信息,也就是所有 RegionServer 的地址。
- Client 访问 Zookeeper 请求行键 RK001 数据所在的 RegionServer 地址
- Zookeeper 从 ROOT 表中查询所有表的 META 信息
- META 表将具体存储行键RK001 数据的 ReginServer 地址返回给 Client,相当于 Client从 Zookeeper中 META 表中查询到 ReginServer 的地址。
- Client 获取到地址后,直接向RegionServer 发送查询行键为 RK001 的这条数据的请求,RegionServer 收到请求就会查询行键 RK001 的 Regino
- RegionServer 将行键为 RK001 的数据返回给 Client
HBase 和 Hive 整合
HBase 不支持 SQL 语法,因此 操作和计算 HBase 分布式数据库时非常不方便,效率也偏低。通过 Hive 数据仓库操作 HBase 分布式数据库中的数据,可以满足业务需求。
环境搭建 vi /etc/profile
1
2
3
4
5export HBASE_HOME=/export/servers/hbase-2.4.2
export PATH=$PATH:$HBASE_HOME/bin:
export HIVE_HOME=/export/servers/hive-3.1.2
export PATH=$PATH:$HIVE_HOME/bin:导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15cd /export/servers/hbase-2.4.2
# HBase 基本包
cp -r lib/hbase-common-2.4.2.jar \
# HBase 服务端
lib/hbase-server-2.4.2.jar \
# HBase 客户端
lib/hbase-client-2.4.2.jar \
# HBase 通信
lib/hbase-protocol-2.4.2.jar \
# 整合其他框架做测试
lib/hbase-it-2.4.2 \
# 兼容 Hadoop 其他版本
lib/hbase-hadoop2-compat-2.4.2.jar \
lib/hbase-hadoop-compat-2.4.2.jar \
/export/servers/hive-3.1.2/lib/修改配置文件 __vi hive-3.1.2/conf/hive-site.xml __
1 | <!-- 指定 zookeeper 集群地址 --> |
- 启动相关服务(Zookeeper Hadoop MySQL Hive HBase)
1 | # 启动 zookeeper 集群,脚本 |
创建表
1
2
3
4
5
6
7
8
9
10
11
12CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");创建 hive 临时中间表
1
2
3
4
5
6
7
8
9
10
11
12
13CREATE TABLE emp (
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';
# 查看
show tables;创建文件 vi /export/data/emp.txt
1
2
3
4
5
6
7
8
9
10
117369 SMITH CLERK 7902 1980-12-11 800.0 20
7379 LIWSI CLERK 7902 1980-12-11 800.0 20
7383 ZHANGSAN SALESMAN 7602 1980-12-11 1100.0 20
7384 QQXIU SALEMAN 7602 1988-12-15 1000.0 30
7386 FORTHEW MANGER 1202 1980-02-20 20000.0 20
7409 ABCDE MANGER 1202 1976-03-03 20000.0 20
7419 LIBIBI CLERK 7902 1945-04-23 800.0 20
7452 BILIBIL ANALYST 7782 1923-11-26 2000.0 20
7529 BEIKLI CLERK 7902 1998-11-12 800.0 20
7534 HEKLILK CLERK 7902 1967-08-15 800.0 20
7603 MIIIUK CLERK 7902 1980-02-15 800.0 20插入数据
1
2
3
4
5
6
7
8
9# 插入到临时表
load data inpath '/export/data/emp.txt' into table emp;
# 临时表导入到 hive_hbase_emp_table 表
insert into table hive_hbase_emp_table select * from emp;
# 查看整合情况
hive> select * from hive_hbase_emp_table;
hbase> scan 'hbase_emp_table'
- 本文作者: MISAKIGA
- 本文链接: https://misakiga.github.io/2021/05/28/big-data/HBase/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!
