读书笔记-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数据模型,有几个要点:

  1. 被索引的部分包括Row Key+Col Fam+Col Qual+Time Stamp
  2. 由于HBase的Schema-Less和列式存储特性,列无需在表创建时定义好,可以动态添加。而且列名也存储在HFile中,用它来保存数据和用Cell value没有什么不同。

循序渐进实战

Schema设计的首要切入点是为待解决的问题建模。下文从逐步完善Twitter用户关系表的过程中总结相关设计原则。

用户关系表follows要回答的问题包括:

  1. A用户关注哪些用户?
  2. A用户是否关注B用户?
  3. 谁关注了A用户?

最初版设计如下,以用户为rowkey,follows列族中包含多个列,每个列名为序号,存储的值为关注用户。

最明显的问题有两个:

  1. 当用户新增关注时,还需要进行查找当前已关注人,递增序号等逻辑。
  2. 查找某个特定关注人效率一般。

改进如下,将关注人直接作为列名:

宽表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用户表查询,已经是某种程度的反规范化。

由于HBase列的动态性,可以用单个HBase表使用嵌套列来表达数据库中一对多关系(类似于MongoDB文档模型)。

继续以twitter为例,假设已经有follows和twits表,那么用户登录后,通过follows读取关注人信息,然后从twits表中根据第一步读取的用户ID读取关注人的twits,最后合并取最新结果展现在用户首页。可以考虑增加一张冗余表用来存储用户首页上展示的twits,Rowkey为登录用户+倒序时间戳,存储所关注人的最新twits。该表提供了更好的读取性能,还能解决一个常见问题:某大V帐号被海量用户关注,如果不使用冗余表,他的twits数据所在的regionserver将成为热点,可能导致性能瓶颈。

该表的数据生成可以通过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)。

HBase提供了Filter接口,用户实现接口可以自定义过滤功能。其中的过滤方法回调顺序如下:

HBase还预置了一些filter。典型的如RowFilter

public RowFilter(CompareOprowCompareOp, WritableByteArrayComparable rowComparator)

其中CompareOp代表比较操作符枚举类,比如相等、大于和小于等。Comparator代表具体比较逻辑,常见的有字符串比较、正则匹配和二进制比较等。

读书笔记-HBase in Action-第二部分Advanced concepts-(1)HBase table design,布布扣,bubuko.com

时间: 2024-10-22 08:05:08

读书笔记-HBase in Action-第二部分Advanced concepts-(1)HBase table design的相关文章

[读书笔记]算法(Sedgewick著)·第二章.初级排序算法

本章开始学习排序算法 1.初级排序算法 先从选择排序和插入排序这两个简单的算法开始学习排序算法.选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序. 1 public static void sort(Comparable a[]){ 2 int N = a.length; 3 for(int i = 0; i < N; i ++){ 4 int min = i; //最小元素索引 5 for(int j = i + 1; j < N; j++){ 6 if(

软件工程读书笔记(2)——第二章 软件过程

第二章 软件过程 软件工程的目标是在规定的时间和预算内开发出高质量软件. 软件项目失败的主要原因几乎与技术和工具没有任何关系,更多的是由于缺少过程规范,只有建立规范的软件开发过程,并持续不断地加以改进,才能管理和控制软件产品的质量. 一.软件过程的概念 1.任务思维与过程思维 软件发展的前期阶段:强调软件开发结果,忽略软件开发过程.(类似于黑盒子) Watts Humphery首先将过程管理的原则和思想引入软件开发过程中,将软件开发任务看做是一个可控的,可度量的和可改进的过程. 2.软件过程的定

读书笔记 - javascript 高级程序设计 - 第二章 在Html中使用JavaScript

1 <script>的6个属性 async  立即下载当前script标签的外部脚本 但不能影响别的 charset 没用了 defer  文档显示之后再执行脚本,只对外部脚本有效 language 没用了 src type 描述代码内容Mine类型 默认就是text/javascript 没什么用 2 在解释器对<script>元素内部的所有代码求值完毕以前 页面中的其余内容都不会被浏览器加载或显示 3 有两种script 嵌入式 外部引入式 在解析外部引入式的js文件时,页面的

【读书笔记】精通CSS 第二版

div和span: div用来对块级元素分组,span用来对行级元素分组.div代表division,它可以将文档分隔为几个有意义的部分,应该只在没有现有元素能实现区域分隔的情况下使用div. 微格式(microformat): HTML中缺少相应的元素,很难突出显示人,地点,日期等类型的信息 参考:  微格式 文档类型定义DTD: DTD是一组机器可读的规则,它们定义XML或HTML的特定版本中允许有什么不允许有什么,在解析网页时,浏览器将使用这些规则检查页面的有效性并且采取相应的措施 DOC

我编程,我快乐——读书笔记(二)

我编程,我快乐--读书笔记(二) 第二章 在产品上投资 1. 我之所以说自己有天赋,是因为我发现自己在工作中不断学习,并且不断进步. 2. 只有向这件产品中投入心血.汗水.眼泪和资金,才能使它真正具有价值. 3. 要主动问,不要等着别人来告诉你.授人以鱼不如授人以渔. 4. 如果你想要雇佣某人来为你工作,你会希望这个人总是要受那些专家的支配吗?我不愿意.我想要的是一个能够自立的员工. 5. 与客户的互动式非常重要的,清楚地了解客户的要求比似懂非懂然后自己填写细节要好得多. 6. 学习行业是如何运

七周七数据库读书笔记(1)

七周七数据库读书笔记(1) 看到别人推荐买了这本书,决定以后每读一本书都开始写读书笔记 这本书的第二章开始部分简单的回顾了关系数据库的CRUD,这里主要讲一下数据库中INNER JOIN, LEFT JOIN和RIGHT JOIN的区别.这块很多初学数据库的人会搞不清楚而很多Blog写得又比较深反而不易理解. 先谈谈INNER JOIN INNER JOIN 我们一般解释为内联,通常来说INNER在SQL中可以被省略.简单来说就是通过两个表的某列将两个表相连.这里举例来说有假设数据库中有两张表(

《Microsoft Sql server 2008 Internals》读书笔记--第六章Indexes:Internals and Management(1)

<Microsoft Sql server 2008 Internals>索引目录: <Microsoft Sql server 2008 Internals>读书笔记--目录索引 在第五章主要学习了table的内部存储结构,第七章<Special storage>中将继续深入学习存储机制,那将是本书最难理解的一章.第六章主要介绍index的基础知识,第八章是<query Optimizer>,下面我们先来看看第六章:Indexes:Internals an

读书笔记-HBase in Action-第二部分Advanced concepts-(3)非Java客户端

HBase Shell HBase shell使用起来最方便,进入HBase shell控制台即可使用. $ $HBASE_HOME/bin/hbase shell 常见操作有create(创建表)/put(插入或更新数据)/get(根据rowkey查询)/scan(范围查询)/delete(删除列)/deleteAll(根据rowkey删除整行数据)/disable&drop(禁用表之后再删除). 基于数据库的项目,往往会在某个目录下存储专门的sql脚本,记录每次迭代数据库变更:同理,HBas

读书笔记-HBase in Action-第二部分Advanced concepts-(2)Coprocessor

Coprocessor是HBase 0.92.0引入的特性.使用Coprocessor,可以将一些计算逻辑下推到HBase节点,HBase由一个单纯的存储系统升级为分布式数据处理平台. Coprocessor分为两种:Observer和Endpoint.Observer能修改扩展已有的客户端操作功能,而Endpoint能引入新的客户端操作. Observer Observer的作用类似于数据库的触发器或者AOP中的advice.下图为Put操作增加Observer,其中1-2-4-6是一次正常的