读书笔记-HBase in Action-第二部分Advanced concepts-(1)HBase table design
本章以山寨版Twitter为例介绍HBase Schema设计模式。广义的HBase Schema设计不仅仅包含创建表时指定项,还应该综合考虑Column families/Column qualifier/Cell value/Versions/Rowkey等相关内容。
灵活的Schema&简单的存储视图
Schema设计和数据存储及訪问模式关系密切,先回想下HBase数据模型。有几个要点:
- 被索引的部分包含Row Key+Col Fam+Col Qual+Time Stamp
- 因为HBase的Schema-Less和列式存储特性,列无需在表创建时定义好,能够动态加入。
并且列名也存储在HFile中。用它来保存数据和用Cell value没有什么不同。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaWRvbnR3YW50b2Jl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
循序渐进实战
Schema设计的首要切入点是为待解决的问题建模。下文从逐步完好Twitter用户关系表的过程中总结相关设计原则。
用户关系表follows要回答的问题包含:
- A用户关注哪些用户?
- A用户是否关注B用户?
- 谁关注了A用户?
最初版设计例如以下,以用户为rowkey。follows列族中包括多个列,每一个列名为序号。存储的值为关注用户。
最明显的问题有两个:
- 当用户新增关注时,还须要进行查找当前已关注人。递增序号等逻辑。
- 查找某个特定关注人效率一般。
改进例如以下,将关注人直接作为列名:
宽表VS窄表
之前的设计为宽表模式,一行记录包括了用户全部关注人。假设使用窄表,Schema例如以下:
窄表设计最大的长处是能通过rowkey查找高效回答之前的问题2:A用户是否关注用户B。而问题1:A用户关注哪些用户,则变成了扫描操作,但从HBase底层列式存储看。I/O读取数据量是一样的(get操作内部实现为针对单行的scan操作)。代码片段例如以下:
Scan s = new Scan();s.addFamily(Bytes.toBytes("f"));
s.setStartRow(Bytes.toBytes("A"));
s.setStopRow(Bytes.toBytes("A"+ 1));
ResultScanner results = followsTable.getScanner(s);
窄表带来的最大问题是。HBase仅仅有单行操作才是原子性的。
如果用户新关注了多个用户,在宽表中能通过一次Put原子操作完毕。而在窄表操作中则须要多次操作。
注:回答问题3。谁关注了A用户,能够再建一张被关注用户表。rowkey为followed+follower。由应用端维护两张表数据一致性。
Rowkey设计
使用Hash rowkey有助于数据在regionserver之间均匀分布,一般能够使用MD5获取定长key。
比較棘手的一个场景是在时间序列数据中,使用时间戳作为rowkey。那么你始终在表底部插入数据,因为rowkey的有序性存储,表的最后一个region成为热点。而应用又须要依据时间范围进行扫描查询,所以不能简单将时间戳Hash,这时能够考虑“Salting”方法:
int salt = new Integer(new Long(timestamp).hashCode()).shortValue()% <number of region servers>
byte[] rowkey = Bytes.add(Bytes.toBytes(salt)\ + Bytes.toBytes("|") + Bytes.toBytes(timestamp));
生成的Rowkey例如以下。查询处理变得略微复杂些,须要在应用端合并处理。
0|timestamp1
0|timestamp5
0|timestamp6
1|timestamp2
1|timestamp9
2|timestamp4
2|timestamp8
反规范化
上节中,Rowkey包括了被关注人ID。CQ中存储被关注人名称。而不用再join用户表查询。已经是某种程度的反规范化。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaWRvbnR3YW50b2Jl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
因为HBase列的动态性,能够用单个HBase表使用嵌套列来表达数据库中一对多关系(类似于MongoDB文档模型)。
继续以twitter为例,如果已经有follows和twits表,那么用户登录后,通过follows读取关注人信息,然后从twits表中依据第一步读取的用户ID读取关注人的twits,最后合并取最新结果展如今用户首页。能够考虑添加一张冗余表用来存储用户首页上展示的twits,Rowkey为登录用户+倒序时间戳。存储所关注人的最新twits。
该表提供了更好的读取性能。还能解决一个常见问题:某大V帐号被海量用户关注。如果不使用冗余表。他的twits数据所在的regionserver将成为热点,可能导致性能瓶颈。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaWRvbnR3YW50b2Jl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
该表的数据生成能够通过coprocessor实现(下章介绍,类似于数据库的触发器),数据保留由TTL实现(Time To Live,下节介绍)
Column family配置
HBase提供了一些配置參数。在创建表时能够按需定制。
1. HFile block size:和HDFS block size不同。默认大小是64KB。Block索引存储了每一个block的起始key。所以block size大小会影响索引大小。假设你的应用偏重于随机查找,能够选择小一点的block size;假设側重于顺序扫描。那么能够使用较大的block size。
hbase(main):002:0> create'mytable', {NAME => 'colfam1', BLOCKSIZE => '65536'}
2. Block cache:顺序扫描场景下block cache不是那么重要,能够禁用cache。将内存空间留给其它表或者列族。
hbase(main):002:0> create'mytable',
{NAME => 'colfam1', BLOCKCACHE => 'false’}
3. Aggressive caching:为某些列族设置更高的block cache优先级,HBase会更积极地将其保留在LRU cache中。
hbase(main):002:0> create'mytable', {NAME => 'colfam1', IN_MEMORY => 'true'}
4. Bloom filters:block索引中仅仅存储了block的起始key,默认block size为64KB,假设表中每行数据都偏小,那么一个block中记录行数过多,可能会出现辛苦查找半天,发现所查找数据不存在的情况。通过Bloom filter引入negative test能高速推断数据是否存在
hbase(main):007:0>create 'mytable',
{NAME=> 'colfam1', BLOOMFILTER => 'ROWCOL'}
5. TTL:用于自己主动清理过期数据
hbase(main):002:0>create 'mytable', {NAME => 'colfam1', TTL => '18000'}
6. Compression:Google公布的Snappy格式是个好选择。
hbase(main):002:0>create 'mytable',
{NAME => 'colfam1', COMPRESSION => 'SNAPPY'}<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
7. Cell versioning:默觉得3.
base(main):002:0>create 'mytable', {NAME => 'colfam1', VERSIONS => 1}
Filter过滤器
Filter作用在RegionServer上,数据依旧会从磁盘载入到RegionServer。所以Filter一般降低的是网络I/O,而不是硬盘I/O(有一些Filter能降低硬盘数据读取,比方ColumnPrefixFilter)。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaWRvbnR3YW50b2Jl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
HBase提供了Filter接口。用户实现接口能够自己定义过滤功能。当中的过滤方法回调顺序例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaWRvbnR3YW50b2Jl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
HBase还预置了一些filter。典型的如RowFilter
public RowFilter(CompareOprowCompareOp, WritableByteArrayComparable rowComparator)
当中CompareOp代表比較操作符枚举类,比方相等、大于和小于等。Comparator代表详细比較逻辑。常见的有字符串比較、正则匹配和二进制比較等。
读书笔记-HBase in Action-第二部分Advanced concepts-(1)HBase table design的更多相关文章
- unix 环境高级编程-读书笔记与习题解答-第二篇
第四节 输入与输出 上次的笔记中写到的 open, read, write, lseek 以及close ,都是不带缓存的IO函数,这些函数都使用文件描述符进行工作. 上一篇笔记用到的 read(ST ...
- [读书笔记]算法(Sedgewick著)·第二章.初级排序算法
本章开始学习排序算法 1.初级排序算法 先从选择排序和插入排序这两个简单的算法开始学习排序算法.选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序. public s ...
- 《Linux内核》课本读书笔记 第一章、第二章
- Python基础教程 读书笔记(2)第二章 列表和元组
2.1序列概览 列表和元组的主要区别在于,列表可以修改,元组则不能.也就是说如果要根据要求来添加元素,那么列表可能会更好用;而出于某些原因,序列不能修改的时候,使用元组则更为合适.使用后者的理由通常是 ...
- 读书笔记--iBATIS in Action 目录
1.iBATIS的理念 2.iBATIS是什么 3.安装和配置iBATIS 4.使用以映射语句 5.执行非查询语句 6.使用高级查询技术 7.事务 8.使用动态SQL 9.使用高速缓存提高性能 10. ...
- 读书笔记--Hibernate in Action 目录
1.理解对象/关系持久化 2.启动项目 3.领域模型和元数据 4.映射持久化类 5.继承和定制类型 6.映射集合和实体关联 7.高级实体关联映射 8.遗留数据库和定制SQL 9.使用对象 10.事务和 ...
- 读书笔记--Spring in Action 目录
1.Spring之旅 1.1 简化java 开发 1.1.1 激发pojo 的潜能 1.1.2 依赖注入1.1.3 应用切面1.1.4 使用模板消除样板式代码1.2 容纳你的bean1.2.1 与应用 ...
- 读书笔记 - javascript 高级程序设计 - 第二章 在Html中使用JavaScript
1 <script>的6个属性 async 立即下载当前script标签的外部脚本 但不能影响别的 charset 没用了 defer 文档显示之后再执行脚本,只对外部脚本有效 lan ...
- 读书笔记 | Kubernetes in Action
1 Kubernetes介绍 Kubernetes(以下简称K8s) 是一个部署和管理容器化应用的软件系统.它将底层基础设施抽象,简化了应用的开发.部署,以及对开发和运维团队的管理. K8s由一个主节 ...
- 图解TCP/IP读书笔记(二)
图解TCP/IP读书笔记(二) 第二章.TCP/IP基础知识 一.TCP/IP出现的背景及其历史 年份 事件 20世纪60年代后半叶 应DoD(美国国防部)要求,美国开始进行通信技术相关的研发 196 ...
随机推荐
- c# 如何通过反射 获取\设置属性值、
//定义类public class MyClass{public int Property1 { get; set; }}static void Main(){MyClass tmp_Class = ...
- 解决nginx 504 Gateway Time-out的一些方法
在CentOS下配置lnmp组合基本上用的都是同样的配置文件,一直都没出现过问题,可最近在一个vps上安装同样的环境之后,网站在线10多人就出 现了打开速度非常缓慢的情况,有好几次都是直接达到了ngi ...
- JNI/NDK开发指南(一)—— JNI开发流程及HelloWorld
转载请注明出处:http://blog.csdn.net/xyang81/article/details/41777471 JNI全称是Java Native Interface(Java本地接口)单 ...
- C语言清空输入缓冲区的N种方法对比
转自C语言清空输入缓冲区的N种方法对比 C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int get ...
- http://www.cnblogs.com/xdp-gacl/p/4040019.html
http://www.cnblogs.com/xdp-gacl/p/4040019.html
- VisualStudio替换所有空行
[一篮饭特稀原创,转载请注明出自http://www.cnblogs.com/wanghafan/p/3371620.html] Ctrl+Shift+H 查找内容\r\n\r\n //如果要替换 ...
- [wikioi]传纸条
http://wikioi.com/problem/1169/ 棋盘型的动态规划,这道题可以看成是从左上角向右下角走两条不重合的路(除了开始和结尾).动态规划要想的是状态和阶段,状态是(x1,y1,x ...
- 最简单的CRC32源码-逐BYTE法
从按BIT计算转到按BYTE计算,要利用异或的一个性质,具体见前面的文章<再探CRC >. 其实方法跟逐BIT法是一样的,我们只是利用异或的性质,把数据分成一BYTE一BYTE来计算,一B ...
- google python/c++ code style naming
python: Guidelines derived from Guido's Recommendations Type Public Internal Packages lower_with_und ...
- Java 多维数组 按某列 排序
public MetaCell[][] getByColumn(final int columnIndex, int decisionIndex) {//[注意]final咯 ...