HBase数据类型 #
一、数据模型概述 #
HBase是一个面向列的分布式数据库,其数据模型与传统关系型数据库有显著区别。
1.1 数据模型层次 #
text
┌─────────────────────────────────────────────────────────┐
│ HBase 数据模型 │
├─────────────────────────────────────────────────────────┤
│ │
│ Namespace(命名空间) │
│ └── Table(表) │
│ └── Region(区域)- 数据分片 │
│ └── Store(存储)- 每个列族一个Store │
│ └── MemStore + StoreFile(HFile) │
│ └── Column Family(列族) │
│ └── Column Qualifier(列限定符) │
│ └── Cell(单元格) │
│ └── Version(版本) │
│ │
└─────────────────────────────────────────────────────────┘
1.2 核心概念 #
| 概念 | 说明 | 类比 |
|---|---|---|
| Namespace | 命名空间,表的逻辑分组 | 数据库 |
| Table | 表,数据存储单元 | 表 |
| RowKey | 行键,唯一标识一行 | 主键 |
| Column Family | 列族,物理存储单元 | 列组 |
| Column Qualifier | 列限定符,可动态添加 | 列名 |
| Timestamp | 时间戳,版本标识 | 版本号 |
| Cell | 单元格,最小存储单元 | 字段值 |
二、RowKey设计 #
2.1 RowKey特点 #
text
RowKey特性:
├── 唯一标识一行数据
├── 按字典序排序存储
├── 最大长度64KB(建议10-100字节)
├── 不可修改(只能删除重建)
└── 是数据分区的依据
2.2 RowKey设计原则 #
text
设计原则:
1. 唯一性:确保每行数据有唯一标识
2. 散列性:避免热点问题
3. 长度适中:建议10-100字节
4. 有序性:支持范围查询
2.3 RowKey设计模式 #
text
┌─────────────────────────────────────────────────────────┐
│ RowKey设计模式 │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. 反转模式 │
│ 手机号: 13812345678 → 87654321831 │
│ 优点: 分散热点 │
│ 缺点: 不支持范围查询 │
│ │
│ 2. 加盐模式 │
│ 原始: user001 │
│ 加盐: a-user001, b-user001, c-user001 │
│ 优点: 分散写入压力 │
│ 缺点: 读取需要扫描多个前缀 │
│ │
│ 3. 哈希模式 │
│ 原始: user001 │
│ 哈希: md5(user001).substring(0,4) + '_' + user001 │
│ 优点: 数据均匀分布 │
│ 缺点: 不支持范围查询 │
│ │
│ 4. 组合键模式 │
│ 格式: [分区键]_[排序键]_[时间戳] │
│ 示例: user001_20240101_1704067200 │
│ 优点: 支持范围查询 │
│ 缺点: 需要合理设计分区键 │
│ │
└─────────────────────────────────────────────────────────┘
2.4 RowKey设计示例 #
ruby
# 用户表RowKey设计
# 格式: 用户ID(反转)
create 'user', 'info'
put 'user', '1001', 'info:name', '张三'
# 订单表RowKey设计
# 格式: 用户ID_时间戳(倒序)
create 'order', 'detail'
put 'order', 'user001_9223372036854775807-1704067200', 'detail:amount', '100.00'
# 日志表RowKey设计
# 格式: MD5(设备ID).substring(0,4)_设备ID_时间戳
create 'device_log', 'data'
put 'device_log', 'a1b2_device001_1704067200', 'data:temp', '25.5'
三、列族设计 #
3.1 列族特点 #
text
列族特性:
├── 物理存储单元,同一列族数据存储在一起
├── 需要预先定义,不能动态添加
├── 建议控制在1-3个
├── 每个列族对应一个Store
└── 不同列族可设置不同属性
3.2 列族属性 #
| 属性 | 默认值 | 说明 |
|---|---|---|
| VERSIONS | 1 | 保留版本数 |
| TTL | FOREVER | 数据存活时间(秒) |
| COMPRESSION | NONE | 压缩算法 |
| BLOOMFILTER | ROW | 布隆过滤器类型 |
| BLOCKSIZE | 64KB | HFile块大小 |
| BLOCKCACHE | true | 是否启用块缓存 |
| IN_MEMORY | false | 是否常驻内存 |
| MIN_VERSIONS | 0 | TTL后保留的最小版本数 |
3.3 列族创建示例 #
ruby
# 创建表时指定列族属性
create 'user',
{NAME => 'info', VERSIONS => 3, TTL => 2592000},
{NAME => 'history', VERSIONS => 10, COMPRESSION => 'SNAPPY'},
{NAME => 'settings', BLOOMFILTER => 'ROWCOL'}
# 修改列族属性
alter 'user', {NAME => 'info', VERSIONS => 5}
# 查看列族属性
describe 'user'
3.4 列族设计原则 #
text
设计原则:
1. 列族数量控制在1-3个
2. 经常一起访问的列放在同一列族
3. 不同访问频率的列放在不同列族
4. 不同数据类型的列考虑分列族
5. 避免列族名称过长
四、单元格与版本 #
4.1 单元格定义 #
text
单元格由以下四元组唯一确定:
{RowKey, Column Family, Column Qualifier, Timestamp}
示例:
RowKey: user001
Column Family: info
Column Qualifier: name
Timestamp: 1704067200000
Value: 张三
4.2 版本控制 #
text
┌─────────────────────────────────────────────────────────┐
│ 版本控制机制 │
├─────────────────────────────────────────────────────────┤
│ │
│ 单元格: user001, info:name │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Timestamp │ Value │ │
│ ├──────────────────┼──────────────────────────────┤ │
│ │ 1704067260000 │ 张三丰 │ │
│ │ 1704067230000 │ 张三 │ │
│ │ 1704067200000 │ 小张 │ │
│ └──────────────────┴──────────────────────────────┘ │
│ │
│ 查询时默认返回最新版本 │
│ 可配置保留版本数(VERSIONS参数) │
│ 可指定时间戳查询历史版本 │
│ │
└─────────────────────────────────────────────────────────┘
4.3 版本操作示例 #
ruby
# 创建表,指定保留3个版本
create 'user', {NAME => 'info', VERSIONS => 3}
# 插入多个版本
put 'user', 'user001', 'info:name', '小张'
put 'user', 'user001', 'info:name', '张三'
put 'user', 'user001', 'info:name', '张三丰'
# 查询最新版本
get 'user', 'user001', 'info:name'
# 返回: 张三丰
# 查询所有版本
get 'user', 'user001', {COLUMN => 'info:name', VERSIONS => 3}
# 返回: 张三丰, 张三, 小张
# 指定时间戳查询
get 'user', 'user001', {COLUMN => 'info:name', TIMESTAMP => 1704067200000}
4.4 TTL过期 #
ruby
# 创建表,设置TTL为7天
create 'log', {NAME => 'data', TTL => 604800}
# 插入数据
put 'log', 'log001', 'data:content', '日志内容'
# 7天后数据自动删除
# MIN_VERSIONS可设置TTL后保留的最小版本数
alter 'log', {NAME => 'data', TTL => 604800, MIN_VERSIONS => 1}
五、数据编码 #
5.1 数据存储格式 #
HBase中所有数据都以字节数组形式存储,没有类型系统。
text
存储格式:
┌─────────────────────────────────────────────────────────┐
│ │
│ Java类型 字节表示 │
│ ───────────────────────────────────────────────────── │
│ String UTF-8编码字节 │
│ Integer 4字节大端序 │
│ Long 8字节大端序 │
│ Float 4字节IEEE 754 │
│ Double 8字节IEEE 754 │
│ Boolean 1字节(0/1) │
│ │
└─────────────────────────────────────────────────────────┘
5.2 客户端编码示例 #
java
// Java编码示例
import org.apache.hadoop.hbase.util.Bytes;
// 字符串
byte[] nameBytes = Bytes.toBytes("张三");
String name = Bytes.toString(nameBytes);
// 整数
byte[] intBytes = Bytes.toBytes(100);
int value = Bytes.toInt(intBytes);
// 长整数
byte[] longBytes = Bytes.toBytes(1704067200000L);
long timestamp = Bytes.toLong(longBytes);
// 浮点数
byte[] floatBytes = Bytes.toBytes(3.14f);
float f = Bytes.toFloat(floatBytes);
// 双精度
byte[] doubleBytes = Bytes.toBytes(3.14159265358979);
double d = Bytes.toDouble(doubleBytes);
// 布尔值
byte[] boolBytes = Bytes.toBytes(true);
boolean b = Bytes.toBoolean(boolBytes);
5.3 RowKey编码技巧 #
java
// 数值型RowKey编码(确保排序正确)
public class RowKeyUtil {
// 整数转可排序字节
public static byte[] intToSortableBytes(int value) {
return Bytes.toBytes(Integer.reverseBytes(value));
}
// 长整数转可排序字节
public static byte[] longToSortableBytes(long value) {
return Bytes.toBytes(Long.reverseBytes(value));
}
// 时间戳倒序(最新的在前)
public static byte[] reverseTimestamp(long timestamp) {
return Bytes.toBytes(Long.MAX_VALUE - timestamp);
}
}
六、数据压缩 #
6.1 压缩算法对比 #
| 算法 | 压缩比 | 压缩速度 | 解压速度 | 适用场景 |
|---|---|---|---|---|
| NONE | 1:1 | 最快 | 最快 | 不需要压缩 |
| SNAPPY | 2:1 | 快 | 快 | 实时读写 |
| LZO | 2.5:1 | 快 | 快 | 实时读写 |
| GZ | 4:1 | 慢 | 慢 | 冷数据、归档 |
| LZ4 | 2.5:1 | 最快 | 最快 | 高性能场景 |
| ZSTD | 3:1 | 中等 | 快 | 通用场景 |
6.2 压缩配置 #
ruby
# 创建表时指定压缩
create 'user', {NAME => 'info', COMPRESSION => 'SNAPPY'}
# 修改压缩算法
disable 'user'
alter 'user', {NAME => 'info', COMPRESSION => 'GZ'}
enable 'user'
# 触发Major Compaction使压缩生效
major_compact 'user'
6.3 压缩选择建议 #
text
选择建议:
├── 实时读写场景:SNAPPY 或 LZ4
├── 存储空间敏感:GZ 或 ZSTD
├── 平衡场景:LZO 或 ZSTD
└── 冷数据归档:GZ
七、布隆过滤器 #
7.1 布隆过滤器类型 #
| 类型 | 说明 | 适用场景 |
|---|---|---|
| NONE | 不使用布隆过滤器 | 不需要优化读性能 |
| ROW | 行级布隆过滤器 | 根据RowKey查询 |
| ROWCOL | 行列级布隆过滤器 | 根据RowKey+Column查询 |
7.2 布隆过滤器配置 #
ruby
# 创建表时指定布隆过滤器
create 'user', {NAME => 'info', BLOOMFILTER => 'ROW'}
# 行列级布隆过滤器
create 'user', {NAME => 'info', BLOOMFILTER => 'ROWCOL'}
# 修改布隆过滤器
alter 'user', {NAME => 'info', BLOOMFILTER => 'ROWCOL'}
7.3 布隆过滤器原理 #
text
┌─────────────────────────────────────────────────────────┐
│ 布隆过滤器原理 │
├─────────────────────────────────────────────────────────┤
│ │
│ 查询流程: │
│ 1. 根据RowKey计算布隆过滤器位图 │
│ 2. 检查位图中对应位是否都为1 │
│ 3. 如果有0,则该RowKey一定不存在 │
│ 4. 如果都为1,则可能存在,继续查找 │
│ │
│ 优势: │
│ - 快速判断RowKey不存在,减少磁盘IO │
│ - 内存占用小 │
│ │
│ 注意: │
│ - 存在误判(判断存在但实际不存在) │
│ - 不存在判断100%准确 │
│ │
└─────────────────────────────────────────────────────────┘
八、数据模型设计示例 #
8.1 用户表设计 #
ruby
# 用户信息表
# RowKey: 用户ID反转
# 列族: info(基本信息), settings(设置), history(历史)
create 'user',
{NAME => 'i', VERSIONS => 1, BLOOMFILTER => 'ROW'},
{NAME => 's', VERSIONS => 1},
{NAME => 'h', VERSIONS => 10, TTL => 2592000}
# 插入数据
put 'user', '1001', 'i:n', '张三' # name
put 'user', '1001', 'i:a', '25' # age
put 'user', '1001', 'i:e', 'a@b.com' # email
put 'user', '1001', 's:theme', 'dark'
put 'user', '1001', 'h:login', '2024-01-01'
8.2 订单表设计 #
ruby
# 订单表
# RowKey: 用户ID_时间戳倒序
# 列族: d(详情), i(商品)
create 'order',
{NAME => 'd', VERSIONS => 1},
{NAME => 'i', VERSIONS => 1}
# 插入数据
put 'order', 'user001_9223372036854775807-1704067200', 'd:amount', '100.00'
put 'order', 'user001_9223372036854775807-1704067200', 'd:status', 'paid'
put 'order', 'user001_9223372036854775807-1704067200', 'i:prod001', '商品A'
8.3 时序数据表设计 #
ruby
# 设备传感器数据表
# RowKey: 设备ID_时间戳倒序
# 列族: d(数据)
create 'sensor_data',
{NAME => 'd', VERSIONS => 1, COMPRESSION => 'SNAPPY', TTL => 604800}
# 插入数据
put 'sensor_data', 'device001_9223372036854775807-1704067200', 'd:temp', '25.5'
put 'sensor_data', 'device001_9223372036854775807-1704067200', 'd:humidity', '60'
九、总结 #
本节介绍了HBase的数据模型:
| 概念 | 要点 |
|---|---|
| RowKey | 唯一标识、字典序排序、设计需避免热点 |
| 列族 | 物理存储单元、建议1-3个、可配置属性 |
| 版本 | 支持多版本、可配置版本数和TTL |
| 编码 | 字节数组存储、需客户端编解码 |
| 压缩 | SNAPPY/GZ等算法、权衡压缩比和速度 |
| 布隆过滤器 | 优化读性能、ROW/ROWCOL两种类型 |
下一步,让我们学习HBase的分布式架构!
最后更新:2026-03-27