HBase应用场景非常广泛;社区前面有一系列文章。大家可以到社区看看看;张少华同学本篇主要讲HBASE最重要的一个基础知识,rowkey的涉及,非常赞!大力推荐!
社区系列文章:
HBase由于其存储和读写高性能,在实时查询中越来越发挥重要的作用,但是由于其属于NOSQL数据库类型,对于关系型数据并不适用。HBase查询只能通过其rowkey来查询(我们可以认为是HBase中表的唯一索引)。所以rowkey的设计在使用HBase的设计中尤为重要,另外rowkey设计也关乎到数据库中数据的存放位置,若rowkey设计不当,在HBase分区中,会引发数据热点(hotspot)问题出现,即数据访问集中在某个节点或者region,最终会导致性能降低或者region由于负载大而不可用。
为了防止在写的操作时出现数据热点,在设计rowkey时应该让数据尽可能同时写入多个region,下面介绍几种常见的rowkey设计方式。
1 . Salt
Salting在HBase中的应用是将每一个rowkey前缀指定一随机字符,这样就使得数据在分散在多个不同的region,达到均衡负载。
若HBase中表region按照每个字母前缀来区分,我们来对比rowkey 加salt前后的变化,首先我们给一组未salt前的rowkey:
rk001
rk002
rk003
上述rowkey根据分区来看是在同一个region中,下面我们对上述rowkey加salt处理:
a-rk001
b-rk002
c-rk003
经过处理的rowkey,数据分布在3个region中,理论上此时的吞吐量是未处理之前的3倍。由于前缀是随机的在读这些数据时若要按照字典序查找则需要耗费更多的时间(可能对每个region服务器发起请求),所以salt增加了写操作的吞吐量,但却增加了读操作的开销。
2 .Hash散列
用hash 散列来替代随机指派前缀,能使一个给定的行在salt时有相同的前缀,从某种程度上说,这在分散了RegionServer间的负载的同时,也允许在读操作时能够预测。确定性hash(deterministic hash )能让客户端重建完整的rowkey,可以用get操作直接获取想要的行。
例如将上述的3个rowkey(未salt)经过hash处理,此处我们采用MD5散列算法,结果如下
f18a79a8eb39267173fd0d113e3282f4
277ba32a1610268cdb7733192010c127
bd1258481401ea1be6377c5aaeae3a1f
若以首个字符作为不同分区,上面几个数据均衡分布在3个region中。下面是我们实际的一个数据在各个分区的分布情况:
在上图的16个分区中,数据基本实现均衡分布,当数据量越来越大的时候,分区的这种均衡会更平衡。
上面介绍的两种rowkey常用的rowkey设计方法。由于在HBase中数据存储是k-v形式,若在HBase中同一表的同一列插入相同rowkey(除自带版本),则原先的数据会被覆盖掉,所以为了保证rowkey的唯一性,在实际的设计中我们可能更多的是结合多种设计方法来实现rowkey的最大优化设计,比如MD5+salt。
HBase的数据读取主要通过rowkey来查询获取数据,我们可以借助Hive、Phoenix等通过SQL方式获取数据,也可以将索引数据存放在Solr、ElestaticSearch中,间接的查询数据,但是这样的方式都没有通过rowkey来直接查询数据的性能高,同时实时性也不高,所以我们在rowkey设计时我们应该包含更多可用信息。这里我们参考了《大数据之路—阿里巴巴大数据实践》一书中讲到的设计规则
设计规则:MD5+主维度+维度标识+子维度1+时间维度+子维度2
例如:卖家ID的MD5前四位+卖家ID+app+一级目录+date+二级目录
以MD5的前四位作为rowkey的第一部分,可以把数据散列,让服务器负载均衡,避免热点问题。卖家ID是查询必传的这样就缩小了我们scan的范围,能够更快的查询到我们需要的数据。
最后,rowkey的长度也会关乎到我们的性能,由于HBase属于列式数据库,若rowkey长度增加一倍那么整体的存储量会成倍增加。所以rowkey的设计没有固定的模式,在实际的实践中需要我们参考各种因素来实现rowkey的最优化。