👈👈👈 欢迎点赞收藏关注哟
首先分享之前的所有文章 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...
一. 前言
之前 Hadoop 入门 时讲过 , Hadoop 本身属于底层框架,在其上层有很多功能上的实现 ,并且这些实现都取得了不错的成绩。
HBase 就是其中一个, HBase 是一个列数据库, 其核心是基于 Hadoop 来实现的。
- 文章内容概述 :
- HBase 概念宏观一览
- HBase 快速部署
- HBase Java 调用案例
二. HBase 简述
2.1 HBase 特性快读
- HBase 依赖于
Hadoop
存储数据 ,可以认为 HBase 的数据是存储在HDFS
中 - HBase 是一个
列式数据
- HBase 并不快,只是在数据量较大的,性能衰减要比其他数据库小的多 @
HBase不睡觉书
- HBase 本身
不支持连表查询
, 写GroupBy
和Order By
会很麻烦
2.2 HBase 适用场景
- 单表超千万 ,并发很高
- 不需要复杂的数据分析,实时性要求不高
2.3 HBase 部署架构
- HBase有两种服务器:Master服务器 和 RegionServer服务器
- 一个集群通常有
一个
Master 服务器 和多个
RegionServer服务器 - Master 用于维护
表结构关系
,RegionServer 负责存储数据
- HBase 基于
ZooKeeper
管理 RegionServer 信息
补充知识点 : Master 的主要功能
- 为 RegionServer 分配 Region
- 负责 RegionServer 的
负载均衡
- 发现失效的 RegionServer 并重新分配其上的 Region
- HDFS 上的垃圾文件(HBase)回收
- 处理 Schema 更新请求(表的创建,删除,修改,列簇的增加等等)
RegionServer 和 Region 的关系
- RegionServer 存储和处理数据,它负责存储一个或多个 Region
- Region 是 HBase 中的存储和管理数据的单位
- 一个
RegionServer
可以存储多个Region
- 一个
Region
只属于一个RegionServer
- RegionServer 负责管理其托管的 Region 的所有读写操作
- RegionServer 会定期将 Region 的数据刷新到 HDFS 上
2.4 HBase 的存储结构
- 基本单元是列 (Column)
- 一个列或者多个列形成一行 (Raw )
- HBase 中每一行的列可以完全不同 (
即行列并不是严格对齐
)
- HBase 中每一行的列可以完全不同 (
- 每一行都有一个唯一的行键 (rowKey)
- 每个列又存在多个版本 , 多个版本的值存储在单元格中 (Cell)
- Hbase 中若干的列可以组成列族(columnFamily)
补充知识点 :
- 📍补充知识 : RowKey
- RowKey 是由用户指定的
一串不重复的字符串
- RowKey 是HBase
唯一的排序字段
- 当使用相同的 RowKey 时,会覆盖之前的数据,而之前的数据可以通过版本号访问
- RowKey 是由用户指定的
- 📍补充知识 : 版本号
- HBase 当
更新数据
的时候,并不会导致数据直接消失 - HBase 可以通过版本号访问之前的数据
- HBase 当
- 📍补充知识点 : 单元格
- 唯一确定一条结果的表达式应该是
行键:列族:列:版本号
- 一个列上可以存储多个版本的值 , 这些值被放在
不同的单元格中
- 唯一确定一条结果的表达式应该是
- 📍补充知识 : 列族 (ColumnFamily的概念)
- 表的一些
通用数据
可以定义在列族
上 , 因为列是可变的 ,而一个列族内的所有列都会有相同的属性 - HBase 一个列名称的前面
总是带有所属的列族
(brother:age) - HBase 会把相同列族的列尽量放在同一台机器上
- Hbase 的列族不是越多越好,官方推荐的是列族最好小于或者等于3
- Hbase 表的创建的时候就必须指定列族
- 表的一些
- 📍补充知识 : Region
- 一个 Region 是多个行的集合
2.5 阶段总结
关于 HBase 的基础就这么多 ,再多反而会影响学习的效果。
三. 快速安装
由于主要是学习,所以这里不会采用生产级的部署方式,采取 Docker 快速安装的方法。
java
// S1 : 拉取镜像
docker pull harisekhon/hbase:latest
// S2 : 启动 Docker
docker run -d -h docker-hbase \
-p 2181:2181 \
-p 8080: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
// S3 : 进入容器 base 页面
docker exec -it <容器ID> bash
// S4 : 创建数据库(其他命令这一篇就不细看了)
hbase shell
create 'test','f'
// 进入图形界面
http://11.97.45.123:16010/master-status
Zookeeper 中的数据
HBase Master 管理页面
四. Java 调用方式
4.1 Maven 依赖
java
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.4.10</version>
</dependency>
4.2 基础操作
java
// 此处 default.com 是我 HOST 映射到服务器IP上
public static Connection buildConnect() throws Exception {
// 创建 HBase 配置
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "default.com:2181");
configuration.set("zookeeper.znode.parent", "/hbase");
configuration.set("hbase.zookeeper.property.clientPort", "2181");
configuration.set("hbase.zookeeper.property.connectionString", "default.com:2181");
// 创建 HBase 客户端连接
return ConnectionFactory.createConnection(configuration);
}
全操作生命周期
java
private void testDemo() throws Exception {
Connection connection = buildConnect();
// 获取表
TableName tableName = TableName.valueOf("testtable");
Table table = connection.getTable(tableName);
// Put 数据
Put put = new Put("row1".getBytes());
put.addColumn("cf1".getBytes(), "col1".getBytes(), "value1".getBytes());
table.put(put);
log.info("数据插入完成");
// Get 数据
Get get = new Get("row1".getBytes());
Result result = table.get(get);
byte[] value = result.getValue("cf1".getBytes(), "col1".getBytes());
log.info("获取到数据:{}", value);
// Close 连接
table.close();
connection.close();
}
校验并且创建表
java
Connection connection = HbaseConnectionUtil.buildConnect();
// S1 : 查询表是否存在
HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
if (!admin.tableExists(TableName.valueOf(tableNameStr))) {
log.info("table 表不存在,对表进行创建");
// S2 : 如果表不存在,创建表
TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableNameStr));
// 添加列族 (创建表的时候必须添加列族)
builder.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder("user".getBytes()).build());
builder.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder("address".getBytes()).build());
// 创建表
admin.createTable(builder.build());
System.out.println("Table " + tableNameStr + " created successfully.");
}
4.3 特定功能
插入数据
java
private void createRowMany(Table table) throws Exception {
String rowKey = "Row" + UUID.randomUUID();
Put put = new Put(rowKey.getBytes());
String valueUser = "AntBlack" + new Random().nextInt(99999);
put.addColumn("user".getBytes(), "name".getBytes(), valueUser.getBytes());
String valueAddress = "ShangHai" + new Random().nextInt(99999);
put.addColumn("address".getBytes(), "info".getBytes(), valueAddress.getBytes());
table.put(put);
}
单条数据查询
java
public JSONObject getOne(String rowKeyStr, Table table) throws Exception {
JSONObject resultJson = new JSONObject();
// 这里通过 RowKey 进行查询
byte[] rowKey = Bytes.toBytes(rowKeyStr);
Get get = new Get(rowKey);
// 此处定义要查询的列族
get.addFamily(Bytes.toBytes("address"));
get.addFamily(Bytes.toBytes("user"));
try {
Result result = table.get(get);
if (result.isEmpty()) {
System.out.println("No data found for row key: " + Bytes.toString(rowKey));
} else {
// 输出行键
System.out.println("RowKey: " + Bytes.toString(result.getRow()));
// 遍历并输出所有的单元格数据
for (Cell cell : result.rawCells()) {
String family = Bytes.toString(CellUtil.cloneFamily(cell));
String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
String value = Bytes.toString(CellUtil.cloneValue(cell));
resultJson.put(family + ":" + qualifier, value);
}
}
} catch (Exception e) {
log.info("查询异常");
}
return resultJson;
}
全表扫描
java
public List<JSONObject> scanAllData(Table table) throws IOException {
// 创建扫描器
Scan scan = new Scan();
scan.addFamily(Bytes.toBytes("user"));
scan.addFamily(Bytes.toBytes("address"));
// 扫描表中的所有数据
ResultScanner scanner = table.getScanner(scan);
// 迭代结果
List<JSONObject> resultList = new ArrayList<>();
for (Result result : scanner) {
// 获取行键
byte[] rowKey = result.getRow();
// 获取列族和列名
JSONObject resultJson = new JSONObject();
for (Cell cell : result.rawCells()) {
String family = Bytes.toString(CellUtil.cloneFamily(cell));
String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
String value = Bytes.toString(CellUtil.cloneValue(cell));
resultJson.put(family + ":" + qualifier, value);
}
resultList.add(resultJson);
}
// 关闭扫描器
scanner.close();
return resultList;
}
总结
这一篇就写到这里了,入门篇不涉及到复杂查询方式,但是后续文档会深入这一块。
参考 :
- <HBase 不睡觉书>
- Gemini And ChatGPT
- Apache HBase -- Apache HBase™ Home