HBase 自学完整教程
学习前准备:为什么学 HBase?
在开始之前,先明确一下学习目标,HBase 不是万能的,它有特定的应用场景。
什么是 HBase? HBase 是一个开源的、分布式的、面向列的 NoSQL 数据库,它构建在 HDFS (Hadoop Distributed File System) 之上,提供了对大规模数据的实时随机读写访问能力。

HBase 的核心特点:
- 海量存储: 可以 PB 级别的数据存储。
- 高并发读写: 支持高并发的随机读写,适合实时查询。
- 列式存储: 数据按列族存储,适合稀疏数据(很多字段为空)和列式分析。
- 高可靠性: 基于 HDFS,数据有多个副本,容错性好。
- 自动分片: 表会自动按 Region 分片,并分布在集群的不同节点上,易于水平扩展。
适用场景:
- 海量日志/时序数据存储: 如监控系统日志、IoT 设备数据、App 用户行为日志。
- 高并发查询: 如社交网站的用户信息、商品信息,需要快速根据 RowKey 查询。
- 消息/数据存储: 作为消息队列的持久化层,或存储需要快速更新的数据。
不适用场景:
- 需要复杂事务: HBase 不支持多行事务。
- 需要复杂 SQL 查询: HBase 的查询能力有限,不支持 JOIN、子查询等。
- 数据量小: 对于小规模数据,MySQL 等关系型数据库更简单高效。
理论基础:核心概念
在学习操作之前,必须理解 HBase 的核心数据模型,这是重中之重。

逻辑模型:
HBase 的表是一个巨大的、稀疏的、排序的映射表,通过 (RowKey, Column Family, Column Qualifier, Timestamp) 四个维度可以唯一确定一个单元格的值。
-
RowKey (行键):
- 唯一性: 表中每行数据都有一个唯一的 RowKey。
- 排序性: RowKey 是字典序排序的。这是 HBase 查询优化的核心!
- 设计原则: 长度尽量短、散列分布(避免热点)、查询模式匹配。
-
Column Family (列族 / CF):
- 表在物理上按列族存储,一个表可以有多个列族。
- 创建后不能修改! 只能增删列族。
- 列族下的列(Column Qualifier)是动态的,可以随时增加。
-
Column Qualifier (列限定符 / 列):
- 属于某个列族,是列族下的具体列名。
cf1:name,cf1:age。
- 属于某个列族,是列族下的具体列名。
-
Cell (单元格):
- 由
(RowKey, CF, CQ, Timestamp)唯一确定。 - Cell 中的数据没有类型,都是字节数组
byte[]。
- 由
-
Timestamp (时间戳):
- 每个单元格都有多个版本,版本由时间戳标识。
- 写入数据时,HBase 会自动写入当前时间戳作为版本。
- 读取时,默认返回最新版本,也可以指定版本或版本范围。
物理模型:
- Table (表): 逻辑上的数据集合。
- Region (区域): 表按 RowKey 范围被切分成多个 Region,Region 是 HBase 数据负载均衡和分布式存储的基本单位。
- Store: 一个 Region 由多个 Store 组成,每个 Store 对应一个列族。
- StoreFile (HFile): Store 在底层由一个或多个 StoreFile(HFile)文件组成,这些文件存储在 HDFS 上,HFile 是 HBase 的实际物理存储文件。
- MemStore: 每个 Store 都有一个内存缓冲区,叫做 MemStore,写入数据时,先写入 MemStore,当 MemStore 达到阈值后,会刷写到 HDFS,形成一个 StoreFile。
- WAL (Write-Ahead Log): 预写日志,为了保证数据不丢失,写入数据前会先写 WAL,RegionServer 宕机,可以通过 WAL 恢复 MemStore 中未刷写的数据。
架构组件:
- HMaster (主节点):
- 管理集群,负责表的创建、删除、修改。
- 负责 Region 的分配和负载均衡。
- 不参与数据读写,是“管家”。
- RegionServer (工作节点):
- 集群中真正负责数据读写的工作节点。
- 管理一个或多个 Region。
- 处理客户端的读写请求,管理 Region 的 MemStore 和 StoreFile。
- ZooKeeper:
- 协调服务,存储 HMaster 和 RegionServer 的状态信息。
- 客户端首先通过 ZooKeeper 找到 HMaster,然后通过 HMaster 找到数据所在的 RegionServer。
- HDFS:
底层分布式文件系统,负责持久化存储 HBase 的数据(StoreFile)和 WAL 日志。
环境搭建:单机版与伪分布式
实践是检验真理的唯一标准,我们先搭建一个学习环境。
推荐环境:
- 操作系统: Linux (CentOS/Ubuntu)
- Hadoop 版本: 3.x.x
- HBase 版本: 2.x.x (与 Hadoop 版本兼容)
- Java: JDK 1.8+
单机模式 (Standalone Mode) 最简单的模式,所有组件都运行在一个 JVM 进程中,适合快速验证和学习。
# 1. 下载并解压 HBase
wget https://archive.apache.org/dist/hbase/2.4.11/hbase-2.4.11-bin.tar.gz
tar -zxvf hbase-2.4.11-bin.tar.gz
cd hbase-2.4.11
# 2. 配置环境变量
vi ~/.bashrc
# 添加以下内容
export HBASE_HOME=/path/to/hbase-2.4.11
export PATH=$PATH:$HBASE_HOME/bin
source ~/.bashrc
# 3. 配置 hbase-env.sh
vi conf/hbase-env.sh
# 取消注释并设置 JAVA_HOME
export JAVA_HOME=/path/to/your/java
# 4. 配置 hbase-site.xml
vi conf/hbase-site.xml
# 添加以下内容
<configuration>
<property>
<name>hbase.rootdir</name>
<value>file:///path/to/hbase/data</value> <!-- 本地文件系统目录 -->
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/path/to/hbase/zookeeper</value> <!-- ZooKeeper 数据存储目录 -->
</property>
</configuration>
# 5. 启动 HBase
start-hbase.sh
# 6. 验证
# 查看进程
jps
# 应该看到 HMaster 和 HRegionServer 进程
# 进入 Shell
hbase shell
# 在 shell 中输入 'version' 查看版本
伪分布式模式 (Pseudo-Distributed Mode) 模拟一个完整的分布式集群,所有组件都在一台机器上,但以独立进程运行,这是学习 HBase 架构和特性的最佳环境。
# 前提:Hadoop 已正确安装并启动(HDFS 和 YARN)
# 1. 配置 hbase-site.xml
vi conf/hbase-site.xml
# 修改为以下内容
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://localhost:8020/hbase</value> <!-- 使用 HDFS 作为存储 -->
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>localhost</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/path/to/hbase/zookeeper</value>
</property>
</configuration>
# 2. 配置 regionservers
vi conf/regionserverslocalhost
# 3. 在 HDFS 上创建 HBase 目录
hdfs dfs -mkdir /hbase
hdfs dfs -chown hbase:hbase /hbase
# 4. 启动 HBase
start-hbase.sh
# 5. 验证
# 查看进程
jps
# 应该看到 HMaster, HRegionServer, QuorumPeerMain (ZooKeeper)
# 检查 HDFS
hdfs dfs -ls /hbase
# 应该看到 tmp, data 等目录
# 进入 Shell
hbase shell
HBase Shell 实战操作
HBase 提供了一个功能强大的 Shell,方便我们进行管理和数据操作。
基本命令
# 进入 shell hbase shell # 查看帮助 help # 查看所有命令 list_commands # 查看版本 version
表管理
# 创建表
# create '表名', '列族1', '列族2', ...
create 'student', 'info', 'score'
# 查看所有表
list
# 查看表结构
# describe '表名'
describe 'student'
# 修改表结构 (只能修改属性,不能增删列族)
# disable '表名' -> alter '表名' -> enable '表名'
disable 'student'
alter 'student', {NAME => 'info', VERSIONS => 3}
enable 'student'
# 删除表
# disable '表名' -> drop '表名'
disable 'student'
drop 'student'
# 检查表是否存在
exists 'student'
# 激活/禁用表
disable 'student'
enable 'student'
数据操作 (CRUD)
# 插入/更新数据 (put)
# put '表名', 'RowKey', '列族:列', '值', [时间戳]
put 'student', '1001', 'info:name', 'Zhang San'
put 'student', '1001', 'info:age', 20
put 'student', '1001', 'score:math', 90
put 'student', '1001', 'score:english', 85
put 'student', '1002', 'info:name', 'Li Si'
put 'student', '1002', 'info:age', 21
put 'student', '1002', 'score:math', 88
put 'student', '1002', 'score:english', 92
# 查询数据 (get)
# get '表名', 'RowKey', ['列族:列', ...]
get 'student', '1001'
get 'student', '1001', 'info:name'
get 'student', '1001', {COLUMN => ['info:name', 'score:math']}
# 扫描全表 (scan)
# scan '表名', {COLUMNS => ['列族:列', ...], LIMIT => N}
scan 'student'
scan 'student', {COLUMNS => 'info:name'}
scan 'student', {LIMIT => 1}
# 删除数据 (delete, deleteall)
# delete '表名', 'RowKey', '列族:列' // 删除某个单元格的最新版本
# deleteall '表名', 'RowKey' // 删除一整行数据
delete 'student', '1001', 'score:math'
deleteall 'student', '1002'
高级查询
# 按范围扫描 (RowKey 范围)
# scan '表名', {STARTROW => '起始RowKey', STOPROW => '结束RowKey'}
# 注意:STOPROW 是开区间,不包含此 RowKey
scan 'student', {STARTROW => '1001', STOPROW => '1002'}
# 计数器
# create 'counter_table', 'cf'
# incr 'counter_table', 'row1', 'cf:count'
# get_counter 'counter_table', 'row1', 'cf:count'
create 'counter_table', 'cf'
incr 'counter_table', 'row1', 'cf:count'
get_counter 'counter_table', 'row1', 'cf:count' # 应该返回 1
incr 'counter_table', 'row1', 'cf:count', 5
get_counter 'counter_table', 'row1', 'cf:count' # 应该返回 6
Java API 编程
在实际生产中,我们通常通过 Java API 来操作 HBase。
Maven 依赖
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.4.11</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>2.4.11</version>
</dependency>
<!-- 如果你的 HBase 是依赖 HDFS 的,还需要这个 -->
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-hadoop2-compat</artifactId>
<version>2.4.11</version>
</dependency>
核心类
Connection: 代表一个到 HBase 集群的连接。线程安全,全局唯一,用ConnectionFactory创建。Table: 代表一个 HBase 表的实例。非线程安全。Admin: 用于管理集群和表,如创建表、删除表等。Put: 用于封装要插入或更新的数据。Get: 用于封装查询条件。Scan: 用于封装扫描条件。Result: 查询结果集。
代码示例
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
public class HBaseJavaApiExample {
private static final String TABLE_NAME = "java_api_table";
private static final String CF_NAME = "info";
private static final String COL_NAME = "name";
public static void main(String[] args) throws IOException {
// 1. 创建配置
Configuration config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", "localhost"); // 修改为你的ZooKeeper地址
// 2. 创建连接 (Connection 是重量级对象,只需创建一次)
try (Connection connection = ConnectionFactory.createConnection(config);
// 3. 创建 Admin 对象
Admin admin = connection.getAdmin()) {
// 4. 创建表
createTable(admin, TABLE_NAME, CF_NAME);
// 5. 获取 Table 对象
Table table = connection.getTable(TableName.valueOf(TABLE_NAME));
// 6. 插入数据
putData(table, "row1", CF_NAME, COL_NAME, "Alice");
putData(table, "row2", CF_NAME, COL_NAME, "Bob");
// 7. 查询数据
getData(table, "row1");
// 8. 扫描数据
scanTable(table);
// 9. 关闭 Table
table.close();
}
System.out.println("操作完成!");
}
private static void createTable(Admin admin, String tableName, String columnFamily) throws IOException {
TableName tn = TableName.valueOf(tableName);
if (!admin.tableExists(tn)) {
TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tn);
ColumnFamilyDescriptorBuilder cfBuilder = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily));
builder.setColumnFamily(cfBuilder.build());
admin.createTable(builder.build());
System.out.println("表 " + tableName + " 创建成功!");
} else {
System.out.println("表 " + tableName + " 已存在!");
}
}
private static void putData(Table table, String rowKey, String cf, String col, String value) throws IOException {
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(Bytes.toBytes(cf), Bytes.toBytes(col), Bytes.toBytes(value));
table.put(put);
System.out.println("插入数据: " + rowKey);
}
private static void getData(Table table, String rowKey) throws IOException {
Get get = new Get(Bytes.toBytes(rowKey));
Result result = table.get(get);
if (!result.isEmpty()) {
String name = Bytes.toString(result.getValue(Bytes.toBytes(CF_NAME), Bytes.toBytes(COL_NAME)));
System.out.println("查询结果 - RowKey: " + rowKey + ", Name: " + name);
} else {
System.out.println("未找到 RowKey 为 " + rowKey + " 的数据");
}
}
private static void scanTable(Table table) throws IOException {
Scan scan = new Scan();
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
String rowKey = Bytes.toString(result.getRow());
String name = Bytes.toString(result.getValue(Bytes.toBytes(CF_NAME), Bytes.toBytes(COL_NAME)));
System.out.println("扫描结果 - RowKey: " + rowKey + ", Name: " + name);
}
scanner.close();
}
}
进阶学习与最佳实践
当你掌握了基础后,可以进入更深入的学习。
性能优化
- RowKey 设计: 这是 HBase 性能的灵魂。
- 避免热点: 不要使用递增或递减的 ID(如时间戳、自增ID)作为 RowKey,可以使用 MD5/SHA1 哈希、反转、加盐等方式。
- 长度原则: RowKey 越短越好,可以减少存储空间和 I/O 开销。
- 查询模式: RowKey 的设计要贴合你的查询场景。
- 建表参数调优:
BLOCKSIZE: 块大小,影响 HFile 的大小和缓存,64KB 或更小。VERSIONS: 数据版本数,默认 1,根据业务需求设置。IN_MEMORY: 是否将 BlockCache 优先加载到内存。TTL (Time To Live): 数据的存活时间,过期自动删除。
- 读写优化:
- 写: 使用
BufferedMutator批量写入,减少网络开销。 - 读: 合理使用
Scan的COLUMNS和FILTER,只读取需要的数据,使用Cache。
- 写: 使用
Filter 过滤器 Filter 是 HBase 强大的查询工具,可以在服务端进行数据过滤,减少网络传输。
- PrefixFilter: 按 RowKey 前缀过滤。
- PageFilter: 分页。
- SingleColumnValueFilter: 按列值过滤。
- RegexStringComparator / SubstringComparator`: 正则和子串匹配。
MapReduce/Spark 集成
HBase 提供了 TableInputFormat 和 TableOutputFormat,方便在 MapReduce 或 Spark 中直接读写 HBase 数据,进行离线数据分析。
容灾与备份
- 快照: 快速创建表的备份,对业务影响小。
- 复制: 主从集群复制,用于灾备。
- Export/Import: 导出表数据到 HDFS,再导入。
监控与运维
- HBase UI: HMaster 和 RegionServer 都提供了 Web UI,用于查看集群状态、表信息、Region 分布等。
- Metrics: 集成到 Prometheus/Grafana 等监控系统中,关注关键指标(如 StoreFile 数量、请求延迟、GC 情况等)。
学习资源推荐
- 官方文档 (必读):
- Apache HBase Reference (最权威、最全面)
- 书籍:
《HBase 权威指南》 (第1版或第2版,经典之作)
- 博客与社区:
- Cloudera Blog: 经常有高质量的 HBase 技术文章。
- 美团技术博客: 在 HBase 大规模应用方面有非常深入的实践分享。
- Stack Overflow: 解决具体问题的好去处。
- 视频课程:
在 Coursera、Udemy、Bilibili 等平台搜索 "HBase",可以找到一些不错的入门视频。
学习路线总结
- 第一周:理论与环境。 搞懂核心概念,成功搭建单机和伪分布式环境,能熟练使用 Shell。
- 第二周:Java API。 掌握通过 Java 代码进行 CRUD 操作,理解
Connection,Table,Admin的生命周期。 - 第三周:进阶与优化。 深入学习 RowKey 设计、Filter、以及性能调优的基本原则。
- 第四周:生态与实践。 了解 MapReduce/Spark 集成,学习监控和备份,并尝试阅读美团等公司的 HBase 实战文章。
HBase 是一个强大但复杂的系统,不要指望一蹴而就,多动手实践,多思考其设计原理,你一定能掌握它,祝你学习顺利!