wiki:hbase_table_design

 官网 首先要分区NoSQL 数据模型设计一般从业务应用的具体数据查询入手,而不是数据间的关系,关系型的数据模型基本上是分析数据间的结构和关系。
因为HBASE不支持join,所以一般是通过 反规格化(Denormalization)和灵活的Schema嵌套的方式来减少Join的需求

1、表的属性

(1) 最大版本数:通常是3,如果对于更新比较频繁的应用完全可以设置为1,能够快速的淘汰无用数据,对于节省存储空间和提高查询速度有效果。

(2) 压缩算法:尝试使用snappy算法,相对lzo来说,压缩率接近,压缩效率稍高,解压效率高很多,而且安装相对方便

(3) inmemory:表在内存中存放,同时磁盘上也会存放,可以提高访问速度,可以设置到某个CF,HBASE并不保证数据都在内存。

(4)  bloomfilter:开启可以提升Get和Exist的速度,根据应用来定,看需要精确到rowkey还是column。不过这里需要理解一下原理,bloomfilter的作用是对一个region下查找记录所在的hfile有用。即如果一个region下的hfile数量很多,bloomfilter的作用越明显。适合那种compaction赶不上flush速度的应用,单这种应用在我们这里比较少见。如果你在表中设置了Bloomfilter,那么HBase会在生成StoreFile时包含一份bloomfilter结构的数据,称其为MetaBlock;MetaBlock与DataBlock(真实的KeyValue数据)一起由LRUBlockCache维护。所以,开启bloomfilter会有一定的存储及内存cache开销。

在0.90版,Get只是Scan的一个特殊操作,没有做特别的优化,不知道新版有没有优化。

2.rowkey

rowkey是hbase的key-value存储中的key,通常使用用户要查询的字段作为rowkey,查询结果作为value。可以通过设计满足几种不同的查询需求。

(1) 数字rowkey的从大到小排序:原生hbase只支持从小到大的排序(这里是指scanner的next方法),这样就对于排行榜一类的查询需求很尴尬。那么采用rowkey = Integer.MAX_VALUE-rowkey的方式将rowkey进行转换,最大的变最小,最小的变最大。在应用层再转回来即可完成排序需求。

(2) rowkey的散列原则:如果rowkey是类似时间戳的方式递增的生成,建议不要使用正序直接写入rowkey,而是采用reverse的方式反转rowkey,使得rowkey大致均衡分布,这样设计有个好处是能将regionserver的负载均衡,否则容易产生所有新数据都在一个regionserver上堆积的现象,这一点还可以结合table的预切分一起设计。

3.columnfamily

列族(CF)尽量少,如果一个列族(CF)搞定就不要把它分开成两个,不同列族(CF)是分文件存储

4.column

(1) 对于column需要扩展的应用,column可以按普通的方式设计,但是对于列相对固定的应用,最好采用将一行记录封装到一个column中的方式,这样能够节省存储空间。封装的方式推荐protocolbuffer。

(2) column的数目不要超过百万,不然会出现OOM。如果column过多,可以考虑将column设计到rowkey的方法解决。例如原来的rowkey是uid1,,column是uid2,uid3...。重新设计之后rowkey为<uid1>~<uid2>,<uid1>~<uid3>...,采用scan(startkey,endkey)的扫描方法来读数据

5.counter

使用counter自增可以保证操作的原子性

import java.io.IOException;
 
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.util.Bytes;
 
public class test_counter {
 
    public static void main(String[] args) throws IOException {
 
        Configuration conf = null;
        conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", "192.168.11.64");
 
        HTable table = new HTable(conf, Bytes.toBytes("test_table"));
        long c = table.incrementColumnValue(Bytes.toBytes("100"), Bytes.toBytes("cf1"),
                Bytes.toBytes("column1"), 4);
        table.close();
 
    }
 
}

程序开发是注意的地方

(1)、需要判断所求的数据行是否存在时,尽量不要用HTable.exists(final byte [] row) 而用HTable.exists(final byte [] row, final byte[] column)等带列族的方法替代。

(2)、不要使用HTable.get(final byte [] row, final byte [] column) == null来判断所求的数据存在,而是用HTable.exists(final byte [] row, final byte[] column)替代

(3)、HTable.close()方法少用.因为我遇到过一些很令人费解的错误 (这点没有验证)


HBASE表格设计例子

场景1:记录用户操作行为
原文:[ http://blog.chinaunix.net/uid-9460004-id-2002507.html ]

场景2:多层次的entity设计 海量产品可以采这种
原文在附件的pdf中

场景3:mozilla 实时下载统计系统 类似于魔方的统计
原文:[ https://wiki.mozilla.org/BouncerRealTimeMetricsProject ]


如果要为HBASE做一些索引表,或者通过其他方法提高查询速度,可以参考这篇文章 HBase 二级索引与 Join
其他参考文章

 NoSQL 数据建模技术 HBaseSchema_HBaseCon2012

Attachments