Article
第一章:HBase 概述
1.1 什么是 HBase
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| HBase 定义 | HBase 是一个分布式的、面向列的开源 NoSQL 数据库,构建在 Hadoop HDFS 之上,支持海量数据的随机实时读写。 | HBase 并非传统数据库,不支持 SQL(原生),需通过 Phoenix 等工具提供 SQL 支持。 |
| 开源与生态 | 属于 Apache 软件基金会顶级项目,是 Hadoop 生态系统的重要组成部分。 | 依赖 Hadoop(尤其是 HDFS)和 ZooKeeper,不能独立运行于普通文件系统。 |
| 设计目标 | 高可靠性、高扩展性、强一致性、低延迟访问,适用于 PB 级结构化/半结构化数据存储。 | 不适合复杂事务(如多行 ACID)、频繁 JOIN 或复杂查询场景。 |
| 典型应用场景 | 时序数据(如监控日志)、用户画像、推荐系统、消息系统、实时分析等。 | 行键设计对性能影响极大,需提前规划。 |
1.2 HBase 与传统关系型数据库的区别
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 数据模型 | HBase 是稀疏、多维映射表(Key-Value 形式),按列族存储;关系型数据库基于行存储的二维表。 | HBase 表无需预定义列(除列族外),列可动态增加。 |
| Schema 灵活性 | HBase 是 schema-less(列族需预定义,但列限定符可动态添加);关系型数据库需严格预定义表结构。 | 列族数量建议控制在个位数(通常 1~3 个),因每个列族对应一个 StoreFile。 |
| 事务支持 | HBase 仅支持单行 ACID 事务;关系型数据库支持跨行/跨表 ACID 事务。 | 多行一致性需应用层协调或使用协处理器(Coprocessor)。 |
| 扩展性 | HBase 水平扩展能力强,可轻松扩展至数千节点;关系型数据库垂直扩展为主,水平分片复杂。 | 扩展时自动负载均衡由 HMaster 和 RegionServer 协作完成。 |
| 查询能力 | HBase 原生仅支持基于 RowKey 的点查和范围扫描,不支持 JOIN、GROUP BY 等;关系型数据库支持完整 SQL。 | 复杂查询需结合 Hive、Spark 或 Phoenix 实现。 |
| 存储引擎 | 基于 LSM-Tree(Log-Structured Merge-Tree),写入高效;关系型数据库多基于 B+Tree。 | 写入先写 WAL 再写 MemStore,保证崩溃恢复。 |
1.3 HBase 的数据模型
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 表(Table) | 逻辑数据容器,由行组成,行按 RowKey 字典序排序。 | 表必须至少包含一个列族。 |
| 行键(RowKey) | 唯一标识一行的字节数组,决定数据物理存储位置和访问效率。 | RowKey 设计不当会导致热点问题(如时间戳前缀)。建议加盐或哈希。 |
| 列族(Column Family) | 表的顶层列分组,物理上存储在一起,需在建表时定义。 | 列族名应简短(如 cf1),因每单元格都存储列族名,影响存储开销。 |
| 列限定符(Qualifier) | 列族下的具体列标识,无需预定义,可动态创建。 | Qualifier 可重复使用于不同行,且不同行可拥有不同 Qualifier。 |
| 时间戳(Timestamp) | 每个单元格值的版本标识,默认为写入时的系统时间(毫秒),也可显式指定。 | 默认保留 1 个版本,可通过列族属性设置 VERSIONS 保留多个历史版本。 |
| 单元格(Cell) | 由 {RowKey, Column Family, Qualifier, Timestamp} 唯一确定的数据项,存储二进制值。 | Cell 值无类型,均为字节数组(byte[]),应用层负责序列化/反序列化。 |
| 稀疏性 | 空列不占用存储空间,适合存储稀疏数据(如用户行为日志中大量空字段)。 | 与关系型数据库中 NULL 占用空间不同,HBase 对未写入的列视为不存在。 |
1.4 HBase 的架构组成
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Client | 提供访问 HBase 的接口,维护缓存(如 Region 位置信息),直接与 RegionServer 通信。 | Client 不经过 HMaster 读写数据,降低中心节点压力。 |
| ZooKeeper | 协调服务,管理集群状态,存储 HBase 元数据(如 hbase:meta 表位置、Master 地址)。 | ZooKeeper 故障将导致 HBase 不可用,需高可用部署。 |
| HMaster | 主节点,负责表管理(创建/删除/修改)、Region 分配、故障恢复、负载均衡等。 | HMaster 无单点故障(支持 standby),但不参与数据读写路径。 |
| RegionServer | 工作节点,管理多个 Region,处理客户端读写请求,执行 Compaction 和 Split。 | 每个 RegionServer 管理的 Region 数量受内存和磁盘限制。 |
| Region | 表的水平分区,每个 Region 负责一段连续的 RowKey 范围,是分布式存储的基本单位。 | Region 默认大小 10GB,过大影响分裂和恢复速度。 |
| HFile | Region 中列族数据的底层存储文件,基于 HDFS,采用块索引和布隆过滤器加速查询。 | HFile 是只读的,由 MemStore flush 生成。 |
| MemStore | 写入缓冲区,每个列族在 Region 中有一个 MemStore,数据先写入内存再刷盘。 | MemStore 满(默认 128MB)或周期性触发 flush 到 HFile。 |
| Write-Ahead Log (WAL) | 预写日志,记录所有写操作,用于 RegionServer 崩溃后数据恢复。 | WAL 默认开启,可针对特定表关闭以提升写性能(牺牲可靠性)。 |
第二章:HBase 环境搭建
2.1 依赖环境准备(Hadoop、ZooKeeper)
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 安装 Java JDK | 安装 JDK 8 或 JDK 11(HBase 2.x 推荐 JDK 8,3.x 支持 JDK 11),配置 JAVA_HOME。 | 必须使用 Oracle JDK 或 OpenJDK,不支持其他 JVM 实现。 |
| 配置 SSH 免密登录 | 在单机或集群节点间配置 SSH 免密码登录(用于 Hadoop 和 HBase 启动脚本)。 | 即使单机模式也建议配置 localhost 免密,避免启动警告。 |
| 安装 Hadoop | 下载并解压 Hadoop(建议 3.x 版本),配置 core-site.xml、hdfs-site.xml,格式化 NameNode 并启动 HDFS。 | HBase 依赖 HDFS 存储数据,不能使用本地文件系统(除单机模式外)。确保 Hadoop 已正常运行(jps 查看 DataNode/NameNode)。 |
| 安装 ZooKeeper | 可使用 HBase 自带的 ZooKeeper(测试用),或独立安装 ZooKeeper(生产推荐)。 | 若使用外部 ZooKeeper,需在 hbase-site.xml 中指定 quorum 地址;若使用内置,HBase 会自动启动 zk 进程。 |
| 设置主机名与 hosts | 配置 /etc/hostname 和 /etc/hosts,确保所有节点能通过主机名互相解析。 | 主机名不能含下划线或大写字母,避免 DNS 解析失败。 |
| 关闭防火墙与 SELinux | 执行 systemctl stop firewalld(CentOS)或 ufw disable(Ubuntu),临时关闭安全策略。 | 生产环境应配置白名单而非完全关闭,但初学可临时关闭以避免连接问题。 |
2.2 单机模式安装
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 下载 HBase | 从 Apache 官网下载 hbase-x.x.x-bin.tar.gz,解压至 /opt/hbase 或用户目录。 | 选择与 Hadoop 版本兼容的 HBase 版本(如 HBase 2.4.x 对应 Hadoop 3.x)。 |
配置 hbase-env.sh | 设置 JAVA_HOME 路径,例如 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk。 | 必须显式设置,否则启动失败。 |
配置 hbase-site.xml | 设置属性:hbase.rootdir=file:///tmp/hbase-${user.name},hbase.cluster.distributed=false。 | 单机模式使用本地文件系统(file://),不依赖 HDFS。 |
| 启动 HBase | 执行 bin/start-hbase.sh,查看进程(jps 应出现 HMaster)。 | 日志位于 logs/ 目录,若启动失败需检查日志。 |
| 进入 HBase Shell | 执行 bin/hbase shell,输入 list 验证是否正常。 | 首次启动会自动创建 hbase:meta 和 hbase:namespace 表。 |
| 停止 HBase | 执行 bin/stop-hbase.sh。 | 强制 kill 可能导致数据损坏,应使用 stop 脚本。 |
2.3 伪分布式模式安装
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 确保 HDFS 已启动 | 在同一台机器上先启动 Hadoop HDFS(start-dfs.sh),确保 NameNode 和 DataNode 运行。 | HBase 数据将写入 HDFS,路径如 hdfs://localhost:9000/hbase。 |
修改 hbase-site.xml | 设置:hbase.cluster.distributed=true,hbase.rootdir=hdfs://localhost:9000/hbase,hbase.zookeeper.quorum=localhost。 | 必须将 hbase.rootdir 指向 HDFS 路径,端口需与 Hadoop core-site.xml 中 fs.defaultFS 一致。 |
| 配置 RegionServer | 默认已启用,无需额外配置;若需多 RegionServer,需配置 regionservers 文件。 | 伪分布式通常只运行一个 RegionServer。 |
| 启动 HBase | 执行 bin/start-hbase.sh,jps 应出现 HMaster、HRegionServer、HQuorumPeer(若用内置 ZK)。 | 若使用外部 ZooKeeper,需先启动 zkServer.sh。 |
| 验证 Web UI | 访问 http://localhost:16010(HMaster Web UI)查看集群状态。 | HBase 2.x 默认 Web 端口为 16010,1.x 为 60010。 |
| 测试读写 | 在 shell 中 create 'test', 'cf',put 'test', 'row1', 'cf:a', 'value1',scan 'test'。 | 确保 HDFS 有足够空间,且 HBase 用户对 HDFS /hbase 目录有写权限。 |
2.4 完全分布式模式部署要点
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 规划集群角色 | 至少 3 节点:1 个 HMaster(可配 standby),多个 RegionServer,3 节点 ZooKeeper 集群。 | HMaster 可部署在 NameNode 节点,RegionServer 应部署在 DataNode 节点(数据本地性)。 |
| 同步配置文件 | 将 hbase-site.xml、regionservers、hbase-env.sh 等配置文件分发到所有节点相同路径。 | 所有节点 HBase 安装路径和配置必须一致。 |
配置 hbase-site.xml | 设置 hbase.rootdir=hdfs://namenode:9000/hbase,hbase.zookeeper.quorum=zk1,zk2,zk3,hbase.master=master-host。 | hbase.zookeeper.property.clientPort 默认 2181,若非默认需显式配置。 |
配置 regionservers 文件 | 列出所有 RegionServer 主机名(每行一个),如 regionserver1、regionserver2。 | 该文件决定哪些节点运行 HRegionServer 进程。 |
| 启动顺序 | 1. 启动 HDFS;2. 启动 ZooKeeper 集群;3. 在 Master 节点执行 start-hbase.sh。 | 顺序不可颠倒,否则 HBase 无法连接依赖服务。 |
| 高可用配置(可选) | 配置 backup-masters 文件,列出备用 Master 主机名,实现 HMaster HA。 | 需依赖 ZooKeeper 选举 Active Master。 |
| 监控与日志 | 通过 Web UI(16010)监控 Region 分布、请求速率;日志集中收集(如 ELK)。 | RegionServer OOM 是常见问题,需合理设置 HBASE_HEAPSIZE(如 8G~16G)。 |
| 目录权限 | 确保 HDFS 上 /hbase 目录属主为 hbase 用户(或启动用户),权限为 755。 | 权限不足会导致 RegionServer 无法写 WAL 或 HFile。 |
第三章:HBase Shell 命令行基础
3.1 启动与退出 HBase Shell
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 启动 Shell | hbase shell | 进入 HBase 交互式命令行环境 | hbase shell | 需确保 HBase 服务已启动(start-hbase.sh),否则连接失败。 |
| 退出 Shell | exit 或 quit | 退出 HBase Shell 返回操作系统终端 | exit | 也可使用 Ctrl+D 快捷键退出。 |
3.2 表管理命令(create, list, describe, disable, drop 等)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
create | create '表名', '列族1', '列族2', ... | 创建新表,必须指定至少一个列族 | create 'users', 'info', 'address' | 列族需在建表时定义,后续可 alter 添加,但不建议频繁修改。 |
list | list | 列出所有表名 | list | 返回表名列表,可用于脚本判断表是否存在。 |
describe | describe '表名' | 查看表的详细结构(列族、配置、Region 信息等) | describe 'users' | 显示 COMPRESSION、VERSIONS、TTL 等列族属性。 |
exists | exists '表名' | 检查表是否存在 | exists 'users' | 返回 true/false,常用于 Shell 脚本条件判断。 |
disable | disable '表名' | 禁用表(必须先禁用才能删除或修改结构) | disable 'users' | 禁用后无法读写该表,操作会抛出 TableNotEnabledException。 |
is_disabled | is_disabled '表名' | 检查表是否处于禁用状态 | is_disabled 'users' | 返回 true 表示已禁用。 |
enable | enable '表名' | 启用已禁用的表 | enable 'users' | 启用后恢复读写能力。 |
is_enabled | is_enabled '表名' | 检查表是否已启用 | is_enabled 'users' | 返回 true 表示可用。 |
drop | drop '表名' | 删除表(必须先 disable) | disable 'users'; drop 'users' | 删除不可逆,数据将从 HDFS 中清除(除非有快照)。 |
drop_all | drop_all '正则表达式' | 批量删除匹配正则的表(需先 disable) | drop_all 'test.*' | 高危操作,慎用;需确认正则匹配范围。 |
3.3 数据写入命令(put)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
put | put '表名', '行键', '列族:限定符', '值' [, 时间戳] | 向指定单元格写入数据 | put 'users', 'user1', 'info:name', 'Alice' | 值为字符串,内部以字节数组存储;若省略时间戳,使用系统当前毫秒时间。 |
put(带时间戳) | put '表名', '行键', '列族:限定符', '值', 时间戳 | 写入指定版本的数据 | put 'users', 'user1', 'info:name', 'Alice_v2', 1700000000000 | 时间戳单位为毫秒,可用于手动控制版本。重复时间戳会覆盖原值。 |
3.4 数据读取命令(get, scan)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
get | get '表名', '行键' | 获取某一行的所有列数据 | get 'users', 'user1' | 返回该行所有列族下所有列的最新版本。 |
get(指定列) | get '表名', '行键', {COLUMN => '列族:限定符'} | 获取某一行指定列的数据 | get 'users', 'user1', {COLUMN => 'info:name'} | 可使用 COLUMNS(复数)指定多个列。 |
get(多版本) | get '表名', '行键', {COLUMN => 'cf:q', VERSIONS => N} | 获取某列的最近 N 个版本 | get 'users', 'user1', {COLUMN => 'info:name', VERSIONS => 3} | 需表/列族已配置保留多版本(默认只保留 1 个)。 |
scan | scan '表名' | 全表扫描(按 RowKey 顺序) | scan 'users' | 大表慎用,可能引发 RegionServer OOM。 |
scan(范围) | scan '表名', {STARTROW => '起始行', STOPROW => '结束行'} | 扫描指定 RowKey 范围(左闭右开) | scan 'users', {STARTROW => 'user1', STOPROW => 'user3'} | STOPROW 不包含自身。 |
scan(过滤列) | scan '表名', {COLUMNS => ['cf1:q1', 'cf2:q2']} | 仅返回指定列 | scan 'users', {COLUMNS => ['info:name']} | 减少网络传输,提升性能。 |
scan(限制行数) | scan '表名', {LIMIT => N} | 限制返回最多 N 行 | scan 'users', {LIMIT => 5} | 常用于调试或分页。 |
3.5 数据删除命令(delete, deleteall)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
delete | delete '表名', '行键', '列族:限定符' [, 时间戳] | 删除指定单元格的某个版本 | delete 'users', 'user1', 'info:name', 1700000000000 | 若省略时间戳,删除最新版本;数据标记为”墓碑”,实际删除在 Compaction 时完成。 |
delete(最新版) | delete '表名', '行键', '列族:限定符' | 删除该列的最新版本 | delete 'users', 'user1', 'info:name' | 同上,不指定时间戳即删最新。 |
deleteall | deleteall '表名', '行键' | 删除整行所有列的所有版本 | deleteall 'users', 'user1' | 相当于对行内所有列执行 delete。 |
deleteall(指定列) | deleteall '表名', '行键', '列族:限定符' | 删除某列所有版本 | deleteall 'users', 'user1', 'info:name' | 比多次 delete 更高效。 |
3.6 表结构修改命令(alter)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
alter(添加列族) | alter '表名', '列族名' | 为表添加新列族 | alter 'users', 'contact' | 表必须处于 disabled 状态(HBase 2.x 起支持在线 add_column_family,但旧版本需 disable)。 |
alter(修改列族属性) | alter '表名', {NAME => '列族', 属性 => 值} | 修改列族配置(如 VERSIONS、TTL) | alter 'users', {NAME => 'info', VERSIONS => 5} | 需先 disable 表(除非使用 HBase 2.0+ 的在线 schema change)。 |
alter(删除列族) | alter '表名', 'delete' => '列族名' | 删除列族(HBase 1.x 语法) | alter 'users', 'delete' => 'old_cf' | HBase 2.x 推荐使用 drop_column_family 命令。 |
alter(HBase 2.x 删除列族) | alter '表名', 'drop_column_family' => '列族名' | 删除列族(新语法) | alter 'users', 'drop_column_family' => 'old_cf' | 删除后,该列族所有数据将被标记删除,Compaction 后物理清除。 |
alter(生效变更) | alter '表名', {...}, true | 在旧版本中,部分 alter 需加 true 参数触发执行 | alter 'users', {NAME => 'info', TTL => 86400}, true | HBase 2.x 多数操作自动生效,无需 true。 |
第四章:HBase 数据模型深入
4.1 行键(Row Key)设计原则
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 唯一性 | RowKey 是表中每一行的唯一标识,由应用层生成,HBase 不提供自增 ID。 | 必须保证全局唯一,否则会覆盖已有行。 |
| 字典序排序 | 所有行按 RowKey 的字典序(byte-wise)物理存储,影响扫描效率和数据局部性。 | 设计时应将高频查询字段前置(如 user_id + timestamp),避免全表扫描。 |
| 热点问题 | 若 RowKey 具有单调递增性(如时间戳开头),会导致写入集中于单个 Region,形成热点。 | 解决方案:加盐(prefix hashing)、反转时间戳、哈希分桶等。 |
| 长度控制 | RowKey 是二进制字节数组,建议控制在 10~100 字节以内。 | 过长会增加存储开销(每个 Cell 都重复存储 RowKey)和网络传输负担。 |
| 可读性 vs 性能 | 可使用组合字段(如 device_id#event_time)提升可读性,但需权衡解析成本。 | 生产环境建议使用紧凑编码(如 Base64、Protobuf)而非明文字符串。 |
| 查询模式驱动设计 | RowKey 应围绕主要查询模式设计(点查、范围查、前缀匹配)。 | 无法通过非 RowKey 字段高效查询,需借助二级索引(如 Coprocessor 或外部系统)。 |
4.2 列族(Column Family)与列限定符(Qualifier)
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 列族(Column Family) | 表的顶层逻辑分组,物理上对应一个 Store(含 MemStore + StoreFiles)。 | 列族数量应尽量少(通常 1~3 个),因每个列族独立存储,过多会增加 I/O 和内存开销。 |
| 列族预定义 | 建表时必须显式声明列族,后续可通过 alter 添加,但不建议频繁变更。 | 列族名应简短(如 cf、f1),因每个 Cell 都存储列族名,影响存储效率。 |
| 列限定符(Qualifier) | 列族下的具体列标识,无需预定义,可动态创建,由应用自由命名。 | Qualifier 可为任意字节数组(如 "name"、"1700000000000"),支持高维稀疏数据。 |
| 存储隔离 | 不同列族的数据物理分离,可独立设置压缩算法、TTL、块大小等属性。 | 高频访问列与低频列应分属不同列族,便于优化存储策略。 |
| 访问粒度 | 读写操作以列族为单位加载(HFile 块缓存),即使只读一个 Qualifier 也会加载整个列族块。 | 避免将无关列放入同一列族,防止”读放大”。 |
| 动态 schema | 同一表中不同行可拥有完全不同的 Qualifier 集合,体现 NoSQL 灵活性。 | 应用需自行维护数据语义一致性,HBase 不校验列是否存在。 |
4.3 时间戳(Timestamp)与版本控制
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 时间戳(Timestamp) | 每个 Cell 的版本标识,默认为写入时的系统时间(毫秒),也可由客户端显式指定。 | 时间戳为 long 类型,单位毫秒;相同 RowKey+CF+Qualifier+TS 的写入会覆盖原值。 |
| 多版本支持 | HBase 默认保留 1 个版本,可通过列族属性 VERSIONS 设置保留 N 个历史版本。 | VERSIONS=5 表示保留最近 5 个不同时间戳的值。 |
| 版本查询 | get/scan 可通过 VERSIONS 参数获取多个历史版本。 | 返回结果按时间戳降序排列(最新在前)。 |
| 手动指定时间戳 | 客户端可在 put 时传入自定义时间戳,用于回填历史数据或实现逻辑版本。 | 需确保时间戳唯一性,否则可能意外覆盖。 |
| TTL(Time To Live) | 列族可设置 TTL(秒),超过 TTL 的 Cell 在 Compaction 时自动删除。 | TTL=86400 表示保留 1 天;设为 FOREVER(-1)则永不过期。 |
| 删除与版本 | delete 操作会写入”墓碑”标记,后续读取时过滤被删版本,Compaction 时物理清除。 | 删除某版本后,仍可读取更早的有效版本(若存在)。 |
4.4 单元格(Cell)与稀疏存储特性
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 单元格(Cell) | 数据存储的最小单位,由 {RowKey, Column Family, Qualifier, Timestamp} 唯一确定,值为 byte[]。 | Cell 无数据类型,应用负责序列化(如 JSON、Avro、Thrift)。 |
| 稀疏性 | 未写入的列不占用任何存储空间,适合存储大量空字段的宽表。 | 与关系型数据库中 NULL 占用空间不同,HBase 对缺失列视为不存在。 |
| 存储结构 | Cell 在 HFile 中按 RowKey → CF → Qualifier → TS 排序存储,支持快速定位。 | LSM-Tree 结构使写入高效,但读取可能需合并多个 HFile。 |
| 值大小限制 | 单个 Cell 值建议不超过 10MB,过大影响性能(如 BlockCache 效率、RPC 超时)。 | 大对象(如图片)应存 HDFS/S3,HBase 仅存路径引用。 |
| 无模式约束 | 同一 Qualifier 在不同行可存储不同类型数据(如一行存数字,另一行存字符串)。 | 应用需自行保证数据一致性,HBase 不做类型检查。 |
| 多版本 Cell | 相同 RowKey+CF+Qualifier 可存在多个不同 Timestamp 的 Cell,构成版本链。 | 读取时默认返回最新有效版本(未被删除且未过期)。 |
第五章:HBase Shell 高级操作
5.1 扫描过滤器(Filter)使用
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| PrefixFilter | scan '表名', {FILTER => "PrefixFilter('前缀')"} | 按 RowKey 前缀过滤 | scan 'logs', {FILTER => "PrefixFilter('202501')"} | 仅匹配 RowKey 以指定字符串开头的行;前缀需为字符串形式。 |
| RowFilter | scan '表名', {FILTER => "RowFilter(=, 'binary:行键值')"} | 按 RowKey 精确或比较过滤 | scan 'users', {FILTER => "RowFilter(=, 'binary:user123')"} | 支持 =, !=, >, >=, <, <=;binary 表示字节比较,可替换为 regexstring 等。 |
| QualifierFilter | scan '表名', {FILTER => "QualifierFilter(=, 'binary:name')"} | 按列限定符过滤 | scan 'users', {FILTER => "QualifierFilter(=, 'binary:email')"} | 仅返回包含指定 Qualifier 的列;常与 ColumnPrefixFilter 结合使用。 |
| ValueFilter | scan '表名', {FILTER => "ValueFilter(=, 'binary:Alice')"} | 按单元格值过滤 | scan 'users', {FILTER => "ValueFilter(=, 'binary:Alice')"} | 性能较差,因需扫描所有 Cell 值;大表慎用。 |
| SingleColumnValueFilter | scan '表名', {FILTER => "SingleColumnValueFilter('cf','q',=,'binary:v')"} | 按某列值决定是否返回整行 | scan 'users', {FILTER => "SingleColumnValueFilter('info','status',=,'binary:active')"} | 若该列不存在,默认不返回行;可通过 filterIfMissing=>false 改变行为。 |
| PageFilter | scan '表名', {FILTER => "PageFilter(10)"} | 限制返回行数(分页) | scan 'logs', {FILTER => "PageFilter(5)"} | 仅控制客户端接收行数,RegionServer 仍可能扫描更多数据。 |
| SkipFilter | scan '表名', {FILTER => "SkipFilter(ValueFilter(...))"} | 跳过满足子过滤器条件的行 | scan 't', {FILTER => "SkipFilter(ValueFilter(=,'binary:temp'))"} | 与 WhileMatchFilter 等组合使用可实现复杂逻辑。 |
| 多过滤器组合 | scan '表', {FILTER => "AND(过滤器1, 过滤器2)"} 或 "OR(...)" | 逻辑组合多个过滤器 | scan 't', {FILTER => "AND(PrefixFilter('u'), ValueFilter(=,'binary:admin'))"} | 支持 AND、OR、NOT;注意括号匹配和引号转义。 |
5.2 计数与统计命令(count)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
count | count '表名' [, INTERVAL=>N, CACHE=>M] | 统计表中总行数 | count 'users' | 默认每 1000 行打印一次进度;大表执行慢,因需全表 scan。 |
count(带间隔) | count '表名', {INTERVAL => 10000} | 每 N 行输出一次进度 | count 'logs', {INTERVAL => 50000} | INTERVAL 控制日志频率,不影响结果。 |
count(带缓存) | count '表名', {CACHE => 1000} | 设置 scanner 缓存行数 | count 'users', {CACHE => 2000} | CACHE 越大,RPC 次数越少,但内存消耗增加;默认 1000。 |
| 手动估算(替代方案) | 使用 HBase Web UI 或 Region 信息估算 | 快速获取近似行数 | — | 生产环境大表应避免 count,可用采样或外部计数器替代。 |
5.3 快照管理(snapshot, clone_snapshot, restore_snapshot)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
snapshot | snapshot '表名', '快照名' | 为表创建快照(元数据+HFile 引用) | snapshot 'users', 'users_backup_20250201' | 快照创建瞬间完成,不复制数据;依赖 HDFS 快照功能(需启用)。 |
list_snapshots | list_snapshots | 列出所有快照 | list_snapshots | 显示快照名、表名、创建时间、状态。 |
describe_snapshot | describe_snapshot '快照名' | 查看快照详细信息 | describe_snapshot 'users_backup_20250201' | 包含 Region 列表、HFile 引用等。 |
clone_snapshot | clone_snapshot '快照名', '新表名' | 从快照克隆出新表 | clone_snapshot 'users_backup_20250201', 'users_restored' | 新表独立于原表,可读写;不占用额外存储(HFile 共享)。 |
restore_snapshot | restore_snapshot '快照名' | 将原表恢复到快照状态 | disable 'users'; restore_snapshot 'users_backup_20250201'; enable 'users' | 必须先 disable 表;会覆盖当前表数据,不可逆。 |
delete_snapshot | delete_snapshot '快照名' | 删除快照(释放 HFile 引用) | delete_snapshot 'users_backup_20250201' | 若快照被 clone 表引用,删除后 clone 表仍可访问数据(HDFS 引用计数机制)。 |
5.4 权限与安全命令(grant, revoke, user_permission)
注:以下命令需在 HBase 启用安全认证(如 Kerberos + ACL)后才生效。
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
grant | grant '用户', '权限', '表名' | 授予用户对表的权限 | grant 'alice', 'RWXCA', 'users' | 权限字符:R=Read, W=Write, X=Execute, C=Create, A=Admin;可作用于命名空间(如 @default)。 |
revoke | revoke '用户', '表名' | 撤销用户对表的所有权限 | revoke 'bob', 'logs' | 撤销后用户无法再访问该表(除非有全局权限)。 |
user_permission | user_permission '表名' | 查看表的权限分配情况 | user_permission 'users' | 显示用户及其拥有的权限;若省略表名,列出所有表权限。 |
grant(列族级) | grant '用户', '权限', '表', '列族' | 授予列族级细粒度权限 | grant 'charlie', 'RW', 'users', 'info' | HBase 2.x 支持列族级 ACL,1.x 仅支持表级。 |
| superuser | 配置 hbase.superuser 参数 | 设置超级用户(绕过权限检查) | 在 hbase-site.xml 中设置 hbase.superuser=root,hbase | 超级用户可执行任何操作,需谨慎配置。 |
| 启用安全模式 | 设置 hbase.security.authorization=true | 开启 HBase ACL 功能 | 需在 hbase-site.xml 中配置并重启集群 | 未启用时,grant/revoke 命令无效。 |
第六章:HBase Java API 编程
6.1 连接配置与 Connection 管理
| 方法/类名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| Configuration | Configuration conf = HBaseConfiguration.create(); | 创建 HBase 客户端配置对象 | Configuration conf = HBaseConfiguration.create(); | 必须设置 ZooKeeper 地址;若使用默认端口(2181),可省略 clientPort。 |
| 设置 ZK 地址 | conf.set("hbase.zookeeper.quorum", "zk1,zk2"); | 指定 ZooKeeper 集群地址 | conf.set("hbase.zookeeper.quorum", "localhost"); | — |
| 设置 ZK 端口 | conf.set("hbase.zookeeper.property.clientPort", "2181"); | 指定 ZooKeeper 客户端端口 | — | — |
| Connection | Connection connection = ConnectionFactory.createConnection(conf); | 建立到 HBase 集群的连接(线程安全、重量级) | Connection conn = ConnectionFactory.createConnection(conf); | Connection 是共享资源,应在应用生命周期内复用,避免频繁创建/关闭。 |
close() | connection.close(); | 关闭连接并释放资源 | conn.close(); | 应在应用退出或不再使用时调用;未关闭可能导致连接泄漏。 |
getAdmin() | Admin admin = connection.getAdmin(); | 获取 Admin 对象用于 DDL 操作(建表、删表等) | Admin admin = conn.getAdmin(); | Admin 非线程安全,每次使用后应 close()。 |
getTable() | Table table = connection.getTable(TableName.valueOf("users")); | 获取 Table 对象用于 DML 操作 | Table table = conn.getTable(TableName.valueOf("users")); | Table 是轻量级、线程安全的,可多线程共享;使用后应 close()。 |
6.2 表创建与删除
| 方法/类名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
TableName.valueOf() | TableName tableName = TableName.valueOf("表名"); | 将字符串转换为 TableName 对象 | TableName tn = TableName.valueOf("logs"); | 所有表操作需使用 TableName 类型。 |
| TableDescriptorBuilder | TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName).build(); | 构建表描述符 | TableDescriptor td = TableDescriptorBuilder.newBuilder(tn).build(); | 需配合 ColumnFamilyDescriptorBuilder 使用。 |
| ColumnFamilyDescriptorBuilder | ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("cf")).build(); | 定义列族属性(如 VERSIONS、TTL) | ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder .newBuilder(Bytes.toBytes("info")) .setVersions(1, 5) .setTimeToLive(86400) .build(); | 属性链式调用;必须指定列族名(byte[])。 |
createTable() | admin.createTable(td); | 创建表 | admin.createTable(td); | 表必须包含至少一个列族;若表已存在,抛出 TableExistsException。 |
deleteTable() | admin.disableTable(tableName); admin.deleteTable(tableName); | 删除表(需先禁用) | admin.disableTable(tn); admin.deleteTable(tn); | 必须先 disable,否则抛出 TableNotDisabledException。 |
tableExists() | boolean exists = admin.tableExists(tableName); | 检查表是否存在 | if (!admin.tableExists(tn)) { ... } | 用于安全创建表前判断。 |
6.3 Put/Get/Scan/Delete 操作
| 方法/类名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| Put | Put put = new Put(Bytes.toBytes("row1")); put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("qual"), Bytes.toBytes("value")); | 构造写入操作 | Put p = new Put(Bytes.toBytes("user1")); p.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("Alice")); | 支持 addColumn(cf, qual, ts, value) 指定时间戳;值必须为 byte[]。 |
put() | table.put(put); | 执行单条写入 | table.put(p); | 自动 flush;也可批量提交(见 6.4)。 |
| Get | Get get = new Get(Bytes.toBytes("row1")); get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("qual")); | 构造读取操作 | Get g = new Get(Bytes.toBytes("user1")); g.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name")); | 可设置 setMaxVersions(N) 获取多版本。 |
get() | Result result = table.get(get); byte[] val = r.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")); | 执行单行读取 | Result r = table.get(g); byte[] val = r.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")); | 若行不存在,Result.isEmpty() 返回 true。 |
| Scan | Scan scan = new Scan(); scan.withStartRow(Bytes.toBytes("a")); scan.withStopRow(Bytes.toBytes("z")); | 构造扫描操作 | Scan s = new Scan(); s.addColumn(Bytes.toBytes("info"), Bytes.toBytes("email")); | 支持 setFilter() 设置过滤器;stopRow 不包含自身。 |
getScanner() | ResultScanner scanner = table.getScanner(scan); for (Result r : rs) { ... } rs.close(); | 执行扫描并返回迭代器 | ResultScanner rs = table.getScanner(s); for (Result r : rs) { ... } rs.close(); | 必须显式 close() ResultScanner,否则 RegionServer 资源泄漏。 |
| Delete | Delete delete = new Delete(Bytes.toBytes("row1")); delete.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("qual")); | 构造删除操作 | Delete d = new Delete(Bytes.toBytes("user1")); d.addColumns(Bytes.toBytes("info"), Bytes.toBytes("name")); | addColumn() 删除最新版本;addColumns() 删除所有版本。 |
delete() | table.delete(delete); | 执行删除 | table.delete(d); | 支持批量删除(List)。 |
6.4 批量操作与缓存控制
| 方法/类名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
put(List) | List puts = new ArrayList<>(); puts.add(put1); puts.add(put2); table.put(puts); | 批量写入多行 | List list = new ArrayList<>(); list.add(new Put(...)); table.put(list); | 比循环单条 put 更高效;自动分 region 提交。 |
delete(List) | table.delete(deletes); | 批量删除 | List dels = ...; table.delete(dels); | 同上,支持批量。 |
setWriteBufferSize() | table.setWriteBufferSize(128 * 1024 * 1024); | 设置客户端写缓冲区大小(字节) | table.setWriteBufferSize(64 * 1024 * 1024); | 缓冲区满时自动 flush;仅对 AutoFlush=false 有效(旧 API)。 |
| BufferedMutator | BufferedMutator mutator = connection.getBufferedMutator(tableName); mutator.mutate(put); mutator.flush(); | 异步批量写入(新 API) | BufferedMutator mutator = conn.getBufferedMutator(tn); mutator.mutate(put); mutator.close(); | 自动批处理和重试;适合高吞吐写入场景。 |
setReadRpcTimeout() | Get get = new Get(row); get.setReadRpcTimeout(5000); | 设置单次读 RPC 超时(毫秒) | get.setReadRpcTimeout(10000); | 防止慢查询阻塞;全局超时可在配置中设置 hbase.rpc.timeout。 |
setBatch() | scan.setBatch(10); | 设置每次 RPC 返回的最大列数 | scan.setBatch(5); | 防止大行导致 OOM;与 setCaching() 区分(caching 控制行数)。 |
第七章:HBase 性能与运维
7.1 Region 分裂与合并机制
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Region 分裂(Split) | 当 Region 大小超过阈值(默认 10GB),HBase 自动将其一分为二,新 Region 由 HMaster 分配到其他 RegionServer,实现负载均衡。 | 分裂过程不阻塞读写(HBase 2.x 支持”无缝分裂”);但频繁分裂会增加元数据负担和 Compaction 压力。 |
| 分裂触发条件 | 由 hbase.hregion.max.filesize 控制(默认 10737418240 字节 = 10GB);也可手动执行 split '表名', 'splitKey'。 | 不建议将阈值设得太小(如 <1GB),否则 Region 数量爆炸;太大则影响恢复速度和负载均衡。 |
| 预分区(Pre-splitting) | 建表时通过 SPLITS 参数预先划分多个 Region,避免初期热点。例如:create 'logs', 'cf', {SPLITS => ['1000','2000','3000']}。 | 预分区键需按 RowKey 字典序分布;适用于已知 RowKey 范围的场景(如用户 ID 区间)。 |
| Region 合并(Merge) | 手动将两个相邻 Region 合并为一个,减少小 Region 数量,降低管理开销。命令:merge_region 'ENCODED_REGION_A', 'ENCODED_REGION_B'。 | 合并不自动触发,需管理员干预;合并前需 disable 表(HBase 2.x 支持在线 merge,但需谨慎)。 |
| Region 热点 | 某个 Region 接收大量请求,导致单点性能瓶颈。常见于单调递增 RowKey(如时间戳开头)。 | 解决方案:RowKey 加盐、哈希、反转时间戳;或使用 salting + 二级索引。 |
| Region 定位 | Client 通过 ZooKeeper 获取 hbase:meta 表位置,再从 meta 表查目标 Region 地址,缓存后直连 RegionServer。 | meta 表本身也是一个 HBase 表,其 Region 永远不会分裂;若 meta 损坏,集群不可用。 |
7.2 Compaction 机制
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Minor Compaction | 合并少量小 HFile 为一个较大 HFile,不删除过期或被删除的数据(墓碑保留)。 | 自动触发,频率高;减少文件数量,提升读性能。 |
| Major Compaction | 合并所有 HFile 为一个,同时清理过期数据(TTL)、多版本超限数据、墓碑标记。 | 默认 7 天一次(hbase.hregion.majorcompaction);I/O 和 CPU 开销大,生产环境常关闭自动 major,改为手动低峰期执行。 |
| Compaction 触发条件 | MemStore flush 后 HFile 数量 ≥ hbase.hstore.compactionThreshold(默认 3);或 HFile 大小差异过大。 | 可通过 hbase shell 执行 major_compact '表名' 手动触发。 |
| 墓碑(Tombstone)清理 | delete 操作写入墓碑标记,仅在 Major Compaction 时物理删除对应 Cell。 | 若长期不执行 Major Compaction,存储空间无法释放,查询性能下降(需跳过墓碑)。 |
| Off-peak Compaction | 在低峰期调度 Major Compaction,避免影响在线服务。 | 需结合 cron 或 HBase 自带调度器(如通过 hbase-site.xml 配置窗口期)。 |
| Compaction 策略 | 支持 RatioBasedCompactionPolicy(默认)、ExploringCompactionPolicy 等,控制哪些 HFile 参与合并。 | 可通过列族属性设置:alter 't', {NAME=>'cf', COMPACTION_POLICY_CLASS=>...}。 |
7.3 常见 Shell 诊断命令(status, version, whoami)
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
status | status 或 status 'simple' / 'summary' / 'detailed' | 查看集群运行状态(RegionServer 数、请求速率、负载等) | status 'detailed' | simple 显示概要;detailed 显示每个 RegionServer 的 load、requests、regions。 |
version | version | 显示 HBase、ZooKeeper、Hadoop 版本信息 | version | 用于排查版本兼容性问题(如 HBase 2.4 需 Hadoop 3.x)。 |
whoami | whoami | 显示当前 Shell 用户身份(Kerberos 认证下显示 principal) | whoami | 在启用安全认证时用于确认权限上下文。 |
balancer | balancer_switch true/false / balancer | 手动开关或触发 Region 负载均衡 | balancer_switch true; balancer | balancer 命令立即执行一次均衡;自动均衡由 HMaster 定期调度。 |
regioninfo | locate_region '表名', '行键' | 查看某行所在的 Region 信息(编码、服务器地址) | locate_region 'users', 'user100' | 用于定位热点或调试路由问题。 |
is_in_maintenance_mode | is_in_maintenance_mode | 检查集群是否处于维护模式 | is_in_maintenance_mode | 维护模式下禁止自动均衡和分裂。 |
7.4 备份与恢复策略
| 策略名称 | 说明 | 注意事项 |
|---|---|---|
| 快照备份(Snapshot) | 使用 snapshot 命令创建表的只读快照,基于 HDFS 快照,几乎瞬时完成,不中断服务。 | 最推荐的备份方式;支持 clone_snapshot 快速恢复为新表;依赖 HDFS 快照功能(需 dfs.allow.snapshots=true)。 |
| Export/Import 工具 | 使用 org.apache.hadoop.hbase.mapreduce.Export 将表导出为 HFile,再用 Import 导入。 | 适合跨集群迁移;但导出过程需 scan 全表,对在线服务有压力。 |
| CopyTable 工具 | 通过 MapReduce 将表复制到同集群或远程集群。 | 支持增量复制(指定 starttime/endtime);需开启 replication 或网络互通。 |
| DistCp + HDFS 备份 | 直接使用 Hadoop DistCp 复制 /hbase 目录到备份集群。 | 高风险!必须在 HBase 停止状态下执行,否则 HFile 不一致;仅用于灾难恢复。 |
| WAL 恢复 | RegionServer 崩溃后,HMaster 通过 WAL 重放未刷盘的写入,保证数据不丢失。 | WAL 必须开启(默认开启);若 WAL 损坏,可能丢失最近写入。 |
| 多级备份策略 | 生产环境建议:每日快照 + 异地 DistCp 归档 + 监控快照有效性。 | 快照不防人为 drop 表(drop 会删快照关联的 HFile);重要数据应定期 clone 快照为独立表归档。 |
| 恢复流程 | 1. 从快照 restore_snapshot(覆盖原表);2. 或 clone_snapshot 为新表后 rename;3. 验证数据一致性。 | restore 前必须 disable 表;clone 方式更安全,可并行验证后再切换。 |