背景知识
HBase基本类型定义:Table:表
RowKey:行健,主键
Column Family:列族,包含一个或者多个相关列
Column:属于某一个columnfamily,familyName:columnName,每条记录可动态添加
timestamp:每次操作对应的时间戳,支持用户自定义,默认为当前时间的毫秒值
value:值,和timestamp一起支持多version的概念
通过HBase Shell可以拿到一条数据,如下:
hbase(main):007:0> scan 'bi.dpdim_imei_dpid_mapping',{LIMIT=>1}
ROW COLUMN+CELL
352784041181135 column=dim:dpid, timestamp=1400657685457, value=4369382019346202985
对应内容:
352784041181135 =》 RowKey
dim =》 Column Family
column =》 dpid
timestamp => 1400657685457
4369382019346202985 => value
HBase存储结构:
1.HBase以表(HTable)的形式存储数据
2.HTable包括很多行,每行通过RowKey唯一标记,行按照RowKey的字典序排列,表在行的方向上分割为多个HRegion
3.每行包括一个RowKey和多个Column Family,数据按照Column Family进行物理切割,即不同Column Family的数据放在不同的Store中,一个Column Family放在一个Strore中
4. HRegion由多个Store组成。一个Store由物理上存在的一个MemStrore(内存中)和多个StoreFile(HFile)中
设计
从应用角度,有两点比较重要:1. HBase中RowKey是按照字典序排列的
2. 不同Column Family的数据,在物理上是分开的
在做table设计的时候,主要围绕上述两点做文章。
RowKey的设计需要根据请求数据特点:
1.单个查询, 需要尽量缩小Key的长度
2.范围查询,根据RowKey按字典序排列的特点,针对查询需求设计rowkey,保证范围查询的rowkey在物理上存放在一起
Column Family的设计需遵循: 尽量避免一次请求需要拿到的Column分布在不同的Column Family中
实例
对于基于RowKey的范围查询设计,我们来看 一个实例:1. 给出userid,返回这个userid最近插入的N条数据
2. 给出userid,及一个时间区间,返回这个时间区间的N条数据
针对需求,Key设计如下:
Userid_DataTime_InertTime
Userid:即userid
DataTime:数据所属时间(ms),定义为:Long.MAX_VALUE - dataTime.getTime(),由于RowKey字典序排列,可以使最近插入的数据排在前面,支持“最近插入的N条数据”的需求
InsertTime:数据入库时间(ns),取nanotime(InsertTime的存在是由于在这个应用中,Userid+DataTime不能唯一定位一条数据)
Key生成代码如下:
//生成RowKey
private String buildPutRowKey(int userId, Date addTime) {
String key = userId + "_" + getRowKeyTimestamp(addTime) + "_" + System.nanoTime();
return key;
}
//构建DataTime
private long getRowKeyTimestamp(Date addTime) {
return Long.MAX_VALUE - addTime.getTime();
}