Hypertable应用实践:基于BigTable模型优化业务
文 / 杨栋在2月刊刊登的《Hypertable应用实践:比肩HBase》一文中,作者主要从Hypertable的系统层面介绍了如何改进和优化系统来更好地支持业务。本文则主要从业务层面介绍如何基于BigTable模型设计表格及导入/查询策略。NoSQL和SQL数据库谁更重要的争论从来都没停止,甚至NoSQL中哪些软件更好的争论也很多。和大多数人的观点类似,我的看法是基础架构软件的使用取决于...
·
文 / 杨栋 在2月刊刊登的《
Hypertable应用实践:比肩HBase》一文中,作者主要从Hypertable的系统层面介绍了如何改进和优化系统来更好地支持业务。本文则主要从业务层面介绍如何基于BigTable模型设计表格及导入/查询策略。 NoSQL和SQL数据库谁更重要的争论从来都没停止,甚至NoSQL中哪些软件更好的争论也很多。和大多数人的观点类似,我的看法是基础架构软件的使用取决于其应用场景和系统成熟度,也取决于研发/支撑团队的能力。
在互联网平台软件行业里,有一种论调“大者恒大”。那些大家普遍看好的平台软件,会有更多人聚在其周围,会有更多人贡献。从长远来看,使用这种软件可以得到更好的生态系统支持。 HBase和Hypertable是BigTable的两个开源产物。HBase的社区影响力比Hypertable大,使用HBase的公司也更多。不过在这里我却持相反的论调,因为所有使用开源软件的公司,内部都会对其进行一些定制和优化,内部维护的版本和社区版本有一定差别。就社区版本而言,由于为HBase贡献代码的人数众多,所以引入的Bug也相应会多;而Hypertable的主体开发主要由少数核心人员完成,并且目前Doug Judd成立了专门的公司来维护,因此在稳定性上不比HBase差,性能上又超过HBase。这对于强调节约成本的互联网公司来说,是个不小的诱惑。
社区论坛 在社区论坛中,不同用户可以在不同讨论区中的不同主题下跟帖。假设考虑使用Hypertable作为论坛数据的底层存储。
建表策略
主表字段划分。在实现系统中,同一个帖子的标题、内容等数据存放在同一个字段(Column)中,而不是像传统数据库那样分别存放在不同的Column中,主要出于以下考虑。
[/caption] 超链历史存储模块每天例行运行,超链变化信息归并到历史数据库。读取库数据时,可能只访问最新版本 ,也可能访问所有历史版本记录。比如统计记录状态经常变化到del的频度,可以发现死链。总的来说,可以将历史库的应用需求列为如下三点。
[/caption]
[/caption] 通过将版本信息(记录计数)写入表格,使用超链库的应用能够读出版本序列。比如读cloud.csdn.net/a/20120315/313137.html,会得到版本变化序列0、2、3,它就表示了链接的状态变化,不连续的版本数表示了del和new的变化,连续的版本数表示了mod的变化。 不过这种方案的不足之处在于,插入计数是针对每个页面(From)的,即插入程序需要维护每个页面的计数,量级可能是百亿或千亿,每次导入都要先查询页面的计数。这些信息的存储将超过TB级,每次导入时这次额外的查询将比较费时。
[/caption] (value Day3)、(value Day1)是数据列,Day4、Day3、Day1、Day0是时间列。假设Day2那天没有这个页面的相关链接记录插入。首先将数据列和时间列按照时间一一对应起来,即Pair3<(null Day4), Day4>,Pair2<(value Day3), Day3>,Pair1<(value Day1), Day1>和Pair0<(null Day0), Day0>。 由于Pair0和Pair1时间按天连续,并且Ton列的value值从null→value,因此表示该链接(ton)的状态变为null→new。由于Pair1和Pair2时间按天不连续(Day2未导入该页面相关的链接信息),对这种情况,依照按天连续处理,并且此时cloud.csdn.net/a/20120315/313137.html列的值从value→value,表示页面链接在这三天间的变化是new→mod。Pair2和Pair3时间按天连续,并且且cloud.csdn.net/a/20120315/313137.html列的值从value→null,表示页面链接的变化是mod→del。 通过这个额外附加的时间列,我们能够在应用超链库时较方便地获取页面的状态变化,付出的代价是为超链表增加了1个稠密列。 表格的数目(是否所有记录存储一张表)是个问题,一种方案是整个库一张大表,From作为表的Row key,To作为表的各个列。假设超链库中每个页面大概有100个To链接,如果页面超过百亿,那么表格需要创建百亿(1010)量级的列,虽然在逻辑上Hypertable是支持的。 另一种方案是每个页面(From)对应一个表,这样每张表的列数不超过100,但表格数目会超过百亿。从Root Range推算,假设Range阈值是1GB,每条Range的记录按照100字节计算,它能记录107个Meta Range,每个表至少一个Meta Range,即只能表示107个表格,距离1010差距较大,因此第二种方案不适用。 当然,折中考虑,可以先将From(Row key)做哈希计算,再划分到各个表格,从而能够减少表格的列数。 假设将From集合划分成1万多个子集,每个子集对应一张表格,以From为key,每个To占一列。即便是这样划分之后,每个链接库表格的列数也会是106量级,这需要实际测试。
[/caption] 超链库的Column Family包括两列,Anchor和Timestamp,Timestamp记录着该条记录的时间。列数的固定(小于10个)使得整个表产生的文件数目大大减少,也无须在插入记录时考虑表的Schema。 选择这种建表方案,超链库的易用性降低了。使用超链库的应用想要获取某个页面(From)某个链接(To)的状态变化,需要首先将某个页面(From)的所有Timestamp列扫描出来,然后进行排序,比如图5会排序成Day0、Day1、Day3、Day4的时间序列,然后又可以效仿方案三中的策略,将时间序列和数据列做Join,获得指定From和To的链接的状态变化。
小结 总之,BigTable的模型和传统RDBMS有所不同,基于BigTable进行开发,除了考虑规模问题,还需要注意随机读性能会影响业务逻辑。如果需要基于BigTable的复杂操作,最好在Hypertable之上的内存中进行处理,再将计算结果导入系统。
作者杨栋,百度分布式高级研发工程师,从事Hypertable、Hadoop及流式计算的研究和开发。
本文选自《程序员》杂志2012年04期,未经允许不得转载。如需转载请联系 market@csdn.net
《程序员》2012年杂志订阅送好礼活动火热进行中
- 由于Hypertable的数据存储是key-value方式,因此每个字段都要存放一份Row key和Column name等,若字段数很多,存储开销较大。
- 除删除操作外,基本不存在单独修改一个字段的情况。而删除只需要打一个管理标记,如果增加一个单独的字段存放管理标记(flag字段),则可以完美支持删除操作。
- 几乎所有的查询操作都是查询整个帖子的内容,即使存在只查询部分字段的需求,也可以通过客户端过滤实现,所损失的仅仅是部分带宽。
- 既可以支持单纯按index value查询,如查询user id = 100发的所有帖子,只需指定 “100:” < row < “100;”;也可以附加时间段限制,如查询user id = 100在北京时间2009年1月1日发的所有帖子:“100:1230796800” <= row <= “100: 1230883200”。
- 防止一个index value下的帖子过多导致溢出。BigTable有一个限制,确保同一个Row key下的数据不能超过某个阈值(例如200MB),而增加时间后缀可以有效规避这个限制。
- 对于简单的复合查询,如某个用户在某个讨论区中发的所有帖子,也可以通过简单的index value叠加建立索引表。但对于较复杂的查询,如某一组IP在某时间段内发在某几个讨论区中尚未被删除的帖子,使用简单的索引表就无能为力了。这种情况只能通过客户端逻辑对查询条件进行拆分,对查询结果进行过滤、求交集等操作来实现,很难做到实时。好在底层系统可以不考虑这类查询需求,交给上层Cache系统即可。
- 为了支持稀疏表,Hypertable每个value是单独存的,而不是按行存,因此每个value都需要存一份key(包括Row key、Column family、Column qualifier和Timestamp,最小开销16字节),再加上map数据结构的开销24字节,一个value至少有40字节额外开销,一个帖子就是40×13=520字节,比帖子的实际内容(平均300多字节)还多。
- 为了支持高并发,Hypertable采用MVCC(multi-version concurrency control)模式存储key和value,即删改一个value只是追加了一个补丁,而不是在原值基础上修改。只有当Cell Cache大小达到一定程度时才会清理多余的版本。
- 需要统计出链(To)的变化,可能要统计所有出链,而不只是一个入链(From)下的。
- 需要统计最新的To。
- 如果From和To是分开存储的,最好把#号后面的那些字段(Anchor)和From一起存储,因为这些字段也是有用的。
- 方案一
- 方案二
- 与table Schema相关的额外操作。每次插入时需要去查询Schema。如果是新链接插入,还需要修改Schema。
- 链接状态变化的表示。图2只示意了通过稀疏表的空闲位置和有效位置来共同表示链接状态的变化,但Hypertable插入下条记录时:csdn.net$cloud.csdn.net/a/20120315/313137.html不会在空白列自动添加字段,它的存储方式是Rowkey+Column+value。
- 在每次插入时,在相应的空列处插入特殊标记$。这种做法的弊端是增大额外存储(Rowkey+Column+$),把稀疏表变成了稠密表,因为超链库的记录是大key。
- 不在稀疏表的空白处做标记。在应用使用超链库时,扫描列的同时扫描行,再做交(Join)运算,这样能够发现相应的“空格”位置。但这种方式使得只扫描一列的开销变得很大。
- 单独设置一个静态值,保存插入超链历史库的记录数。每次插入时,将这个记录数也写到表格中。假设写到每一列中,结果如图3所示。
- 方案三
- 方案四
更多推荐
已为社区贡献1642条内容
所有评论(0)