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