如何设计高效的 HBase 数据模型
从学习和使用 HBase 的经历中,整理出对使用者而言,需要了解的 HBase 基础知识,Mark 一下。
1.背景知识
1.1 数据模型
学习 HBase/BigTable 最困难的部分,是理解它的数据模型,换句话说它究竟是咋用的?在 BigTable 论文中明确说明:
论文做了进一步解释:
推荐两篇文章,对此解释的非常清楚:understanding-hbase-and-bigtab 和 Introduction to HBase Schema Design,下面是一个更形象的示例:
真实的存储是平面文件结构,存储模型是类似下面的结构:
1.2 读/写/压缩
HBase/BigTable 存储使用 LSM 方式实现,这个网上文章很多,这里只简单介绍需要了解的主要流程:
可以看出,HBase/BigTable 非常适合有大量写操作的应用,顺序读性能也不错,适合批量数据处理(例如 MapReduce)。BigTable 论文提到的其中两个使用场景都符合这个特征:
1.3 存储分区
HBase 支持数据自动分区,分区方式: 水平分割+垂直分割,
水平分割:KeyValue 数据依据 RowKey 划分到不同的 Region,每一个 Region 被分配给一个 Region Server,具备良好的扩展性。当一个 Region 过大时,会被分割成两个 Region。当一个 Region Server 负载过重时,把其中的部分 Region 迁移到其他 Region Server。
垂直分割:在一个 Region 内部,每个 ColumnFamily 的数据是单独存储的,这使他们有更好的访问局部性。
参考http://hbase.apache.org/book.html#trouble.namenode.hbase.objects
,HBase 在 HDFS 存储数据的目录结构如下:
1.5 KeyValue 存储格式
The KeyValue format inside a byte array is:
keylength
valuelength
key
value
在新版本中,支持为 Cell 附加 tags,KeyValue 的格式为: {keylength,valuelength, key, value, tags}
。
The Key is further decomposed as:
rowlength
row (i.e., the rowkey)
columnfamilylength
columnfamily
columnqualifier
timestamp
keytype (e.g., Put, Delete, DeleteColumn, DeleteFamily)
行键和列族/列属性,会编码到每一个行当中,所以行键、列族和列属性应该尽可能短一些。
1.4 访问模型和事务
HBase 主要使用 Put/Delete/Scan 这几个接口访问数据,支持批量读写:
Version/TimeStamp:HBase/BigTable 支持一个 Key 的多个 Value 版本(依靠 TimeStamp 区分),查询的时候可以访问最新版本,也可以访问指定时间区间的所有版本。
Column:每一个 Column Family 都可以有任意多个 Column,所以必须指定要访问的 Column Qualifiers,才能确认要访问的数据。
HBase 可以保证对同一个 Row 的操作是原子操作,这是因为:
Row 只属于一个 Region,只能通过一个 Region Server 进行写操作,不存在写冲突;
通过 WAL,可以保证对一个 Row 的多个操作(可以是多个 ColumnFamily)要么都成功,要么都失败。
一个 Region Server 的多个 Region 共享一组 WAL 日志文件,一个 Batch 操作做为一个 Record 写入 WAL,所以可以保证要么 都成功,要么都失败。
1.5 TTL
可以对表和列族设置 TTL(秒),HBase 会自动删除过期的 Rows;在新近的版本中,HBase 支持对每个 Cell 单独设置 TTL(毫秒)。
1.6 版本数量
HBase 支持多版本,一个 RowKey 可以有多个版本的 Value,使用时间戳区分版本。
Maximum Number of Versions。 一般不建议设置成很大的值保(例如几百或更多),除非这些旧版本的数据非常有价值,因为这会使 StoreFile 大小剧增。缺省值是 1。
Minimum Number of Versions。这个值和 ttl 参数一起使用,实现类似“保留最后 T 分钟的数据,最多 N 个版本,但至少保留 M 个版本”的需求。缺省值是 0,也就是不启用这个 feature。
2. 模式设计指南
HBase 本质上是一个 kv 数据库,不支持 RDBMS 中常见的索引、事务等特性,它的设计目标是应对高吞吐量、海量数据扩展性的需求。
应用程序应该根据业务需求,来设计高层数据模式。
2.1 梳理数据访问模式
访问模式直接决定我们的设计方案,仔细梳理数据访问模式,列出主要访问场景,在后面设计中时时回看,我们的设计能否满足这些访问场景?还有没有更高的设计方案?
2.2 设计行键
RowKey 是 HBase 表设计中最重要的事情,它决定了应用与 HBase 交互的方式,直接影响数据访问的性能。
2.3 设计列族和列属性
2.4 规划分区
3.案例解析-OpenTSDB
OpenTSDB 使用 HBase 存储数据,它的两个核心设计思想:
(1) 使用一行存储一个时间区间的所有数据
OpenTSDB 把 1 小时内的事件作为一行存储,所有事件存储在列族 t 中,Key 中的时间戳精确到小时,列名称为以本小时起始的秒数(1 小时 3600 秒,最多也就 3600 个事件),或毫秒数(1 小时可以容纳的事件数就多了)。
在当前时间段过去以后,可以把 1 个小时内的数据压缩到一个列中存储(对照 KeyValue 结构,这能节省太多的冗余数据)。
(2) 对字符串编码,减小 key 的长度
TSDB 把字符串映射成数值,来减小 Key 的长度。指标名称,标签 Key,标签 Value,都映射成一个变长整数(使用映射表:tsdb-uid 存储文本和整数的映射关系),这就使得 Key 值非常短。
图 1 OpenTSDB tsdb 表结构
参考:
(1) Bigtable: A Distributed Storage System for Structured Data
(2) Apache HBase Reference Guide
(3) understanding hbase andbigtab
(4) Introduction to HBase Schema Design
(6) Hbase 最佳实践系列
版权声明: 本文为 InfoQ 作者【Jowin】的原创文章。
原文链接:【http://xie.infoq.cn/article/21d0cd3f37a02e089b5ec6be8】。文章转载请联系作者。
评论