本篇结构:
- 宽表和高表定义
- 宽表和高表的优劣
- 宽表和高表的应用场景
一、宽表和高表定义
HBase 中的表可以设计为高表(tall-narrow table) 和 宽表(flat-wide table):
- 宽表是指很多列较少行,即列多行少的表,一行中的数据量较大,行数少;
- 高表是指很多行较少列,即行多列少,一行中的数据量较少,行数大。
二、宽表和高表的优劣
HBase的键分为两种:
- 列键:包括了列族名和限定符,定位到列的索引
- 行健:相当于关系型数据库中的主键,通过行健得到逻辑布局中一行的所有列
由于列键是由列族名和限定符组成的,属于定位具体 StoreFile 的,所以应该将需要查询的维度或者信息存储在 row key 中,因为用它来筛选数据效率最高!
Hbase 的 row key 是分布式的索引,也是分片的依据。Hbase 的 row key + column family + column qualifier + timestamp + value 是 HFile 中数据排列依据。
据此,在HBase中使用宽表、高表的优劣总结如下:
- 查询性能:高表查询更好,因为查询条件都在 row key 中,是全局分布式索引的一部分。高表一行中的数据较少。所以查询缓存 BlockCache 能缓存更多的行,以行数为单位的吞吐量会更高。
- 分片能力:高表分片粒度更细,各个分片的大小更均衡。HBase按行来分片,高表一行的数据较少,宽表一行的数据较多。
- 元数据开销:高表元数据开销更大。高表行多,row key 多,可能造成region 数量也多,- root -、 .meta 表数据量更大。过大的元数据开销,可能引起 HBase 集群的不稳定、master 更大的负担。
- 事务能力:宽表事务性更好。HBase对一行的写入(Put)是有事务原子性的,一行的所有列要么全部写入成功,要么全部没有写入。但是多行的更新之间没有事务性保证。
- 数据压缩比:如果我们对一行内的数据进行压缩,宽表能获得更高的压缩比。因为宽表中,一行的数据量较大,往往存在更多相似的二进制字节,有利于提高压缩比。通过压缩,缓解了宽表一行数据量太大,并导致分片大小不均匀的问题。查询时,根据 row key 找到压缩后的数据,进行解压缩。而且解压缩可以通过协处理器(coproesssor)在 HBase 服务器上做,而不是在业务应用的服务器上做,以充分应用 HBase 集群的CPU能力。
三、宽表和高表的应用场景
3.1、高表的应用
在一个电子邮箱系统中,将行健设置为用户的唯一ID,其余属性作为列族或者列族中的列,如此一来,同一个用户的所有邮件信息都会被存储在同一行中(因为他们的行健相同),这在大部分情况下是通用的,但是有些用户的邮件数量非常非常大,大到一行数据就超出了HFile 的最大限度,这样一来,宽表设计方式就出现了致命的缺陷:表数据无法拆分,更无法进行 HBase 的负载均衡等特性。
PS:也许会有疑问,HFile 和 Region 达到一定大小的时候不是会自动切分的吗? 这是因为HBase 只能按行切分,当行数量达到阈值的时候会根据行健进行切分。
解决这个问题更好的办法是代替宽表,设计一个高表: 可以将行健设置为用户Id + 邮件Id,这样一来,每封邮件都是单独的一行,将宽表中的行数据释放出来。
这样做的好处是:
- 行数量可以更容易的被拆分;
- 行健中包含关键的筛选信息(邮件 Id 被移到了 row key),用户可以直接根据行健定位到唯一的一封邮件;
- 拥有很好的扩展性,高表也是推荐的用法。
但是要使用高表还是宽表还要根据具体的业务场景来确定,因为在以上高表的设计中,同一用户的数据分布在多行中,用户不可能在一个简单的操作中修改一个收件箱的全局属性,因为这涉及到了原子性的操作,如果用户没有一次修改整个收件箱的需求时,这种设计是非常合适的,但是如果用户真的有这种需求,而且需求很大,那么宽表反而更加合适,因为 HBase 能够保证行级别的原子性。
3.3、宽表的应用
Hbase 宽表可以应用在社区系统中,比如 BBS:可以用帖子的 Url 地址作为row key 保存,而后面的每一个回复,作为列族中单独的列。
回复越多,列族中单独的列就越多,表就变宽了。
设计表时,可以不绝对追求高表、宽表,而是在两者之间做好平衡。根据查询模式,需要分布式索引、分片、有很高选择度(即能据此查询条件迅速锁定很小范围的一些行)的查询用字段,应该放入row key;能够均匀地划分数据字节数的字段,也应该放入 row key,作为分片的依据。选择度较低,并且不需要作为分片依据的查询用字段,放入 column family 和 column qualifier,不放入row key。
网友评论