HBase 核心数据结构:四维坐标定数据,一张表长什么样?
关系型数据库的表是”二维”的——行和列。
HBase 的表是”四维”的——行键(RowKey)+ 列族(Column Family)+ 列(Column)+ 时间戳(Timestamp) 四者共同定位一个值。
1 | (RowKey, Column Family:Column, Timestamp) → Value |
整体视图:四维坐标定位数据
HBase 的表可以想象成一张巨大的稀疏矩阵,用四个维度定位数据:
1 | RowKey(行键) → 列族 → 列 → 时间戳 → 值 |
举个例子:
1 | RowKey="user_001", Column Family="info", Column="name", Timestamp=t1 → "张三" |
同一个 RowKey 下,不同列族、不同列、不同版本的数据可以自由组合。空值不占存储空间。
命名空间(Namespace):表的”文件夹”
命名空间是最高层的逻辑组织单元,相当于 MySQL 里的 Database。
1 | 创建命名空间 |
作用:
- 表名隔离(不同命名空间可以有同名表)
- 权限批量管理
- 资源限额控制
两个默认命名空间:
default:用户表默认归属hbase:系统元数据表(如hbase:meta)
RowKey(行键):排序 + 查询的唯一入口
RowKey 是 HBase 表里每行数据的唯一标识。它不只是”主键”那么简单——所有查询都依赖它。
三个核心特性:
- 按字典序排序存储
user_001、user_002、user_100按字符串顺序排。user_100在user_002前面,因为"1"<"2"。 - 只有三种查询方式
- 精确查询:
get 'user_001' - 范围查询:
scan from 'user_001' to 'user_200' - 全表扫描(不推荐)
- 精确查询:
- 本质是字节数组
可以存任意字符串,通常长度 10-100 字节。
RowKey 设计的核心原则:位置相关性。 把经常一起查的数据放在相邻的位置。比如按时间倒序排 RowKey,最新数据在最前面。
列族(Column Family):物理存储的隔离单位
列族是 HBase 表结构里必须预先定义的部分。表创建的时候就要定好有哪些列族。
1 | 创建表时指定列族 |
两个关键点:
- 列族是物理隔离的
同一列族的数据存在一起(同一个 Store),不同列族的数据完全分开。查询时只读目标列族,不碰其他列族。 - 列族数量不宜多
建议 2-3 个,多了 Region 分裂和合并效率下降。一个列族下可以有任意多个列(Qualifier)。
列(Qualifier):动态添加的字段
列是列族下的具体字段,不需要预先定义,写入时直接指定即可。
1 | info:name ← info 列族下的 name 列 |
这就是 HBase 灵活性的来源: 每行的列可以不一样,不用改表结构。
时间戳(Timestamp):多版本管理
每个单元格可以存多个版本,用时间戳区分。
1 | RowKey=user_001, info:name |
默认行为:
- 写入时自动用当前系统时间作为时间戳
- 查询时默认返回最新版本
- 可以指定时间戳读历史数据
版本回收:
可以配置每个列族保留最近 N 个版本,或保留最近 N 天的版本。超过限制的版本会在 Compaction 时被清理。
1 | 保留最近 5 个版本 |
Cell:最小的数据单元
Cell 就是 (RowKey, Column Family:Column, Timestamp) 三者确定的值。
1 | Cell = (RowKey, 列族:列, 时间戳) → 值(字节数组) |
Cell 的特性:
- 值无类型:存的都是字节数组(
byte[]),数据类型由应用程序自己决定(存 String 还是存 Protobuf,写入和读取时保持一致就行) - 不可变:更新操作 = 写入新版本,旧版本保留
- 空值不占空间:稀疏存储,没有的列不占任何存储
一张完整的 HBase 表长什么样
