HBase的设计目标是海量,高吞吐存储。数据在底层是基于LSMT那一套的实现(当然分了很多region,支持分布式)。简单来说,要维护一套memstore + 可分裂的filestore的存储,差不多就是:
新数据写入/更改先写入WAL,然后进入memstore
memstore满了就进filestore
filestore太大了就分裂
而这一套机制实现的单位是column family——每个column family有自己的memstore和filestore。尽管在高层上看起来是同一张表,但是表里每一个column family的存储都是相互独立的。如果和mysql比较的话,column family更像是mysql里的table,而hbase的table更像是mysql里的一个db。如果同时查询同一个hbase table的不同column family,大概等价于不同mysql table之间基于row key做了一个join。
那到底为啥要区分column family呢?
3个原因:
访问的方式不一样(access pattern )。试想一下用hbase存储一个产品的信息,比如A列是产品详情。这个详情可能非常大,但是并不会经常变。而B列是产品的关注次数,会频繁地随着用户点击“关注“/“取消关注”而变化。对于hbase来讲,新的数据更新总会进入memstore,然后满了就会写filestore。如果A和B在一个column family,那么这个写入的过程是要A和B两列都要写的。但实际上A的数据可能压根就没变,所以直观上A列的写入浪费了IO。如果A和B拆到两个column family,那么B的手游拍卖更改只会引发他自己的filestore写入。
压缩(compression)方式不一样。HBase允许为每个column family配置一个compressor。问题是不同数据类型适合的压缩方式不一样。比如文本很适合压缩。但是类似于jpg和png这种图片就不适合——它们的数据本身已经是被压缩的了,再压一遍只是浪费CPU而已。但是如果不同类型数据在同一个column family,就意味着它们要共享同一个压缩方式。这时也许需要考虑将他们拆开成不同的column family。
权限管理。HBase的ACL控制可以定义每个column family可以定义不同的权限。所以如果有希望一拨人能访问列A、B、C,另外一拨人访问列D、E、F这样的需求,可以考虑使用column family。
那么为什么一般都不建议弄很多个column family呢?因为太多了会影响性能,比如做file compact和file splict时,备选的文件会增多(记得每个column family都会增加一批文件);比如说memstore里要为每个column family分配一部分空间。毕竟我们用HBase的原因是希望他能高吞吐明显影响性能就得不偿失了。于是乎设计时就要折衷,比如上面产品详情和关注数的例子,我们是可以考虑直接拆成两个HBase table然后再进行app join的。
总之,trade off is everything