栏目导航

最快现场开奖报码室

Hbase设计实战

更新时间: 2019-10-08

  本文通过一个游戏公司客户实际案例的讲解,分析了 Hbase 表设计及开发在实际案例中的运用,对比了不同的 Hbase 设计考量对客户端访问模式及检索性能的差异。读者通过案例中 Hbase 表设计模式可以更深刻的理解 Hbase 原理及设计,并且熟悉 Hbase 客户端开发的思路及实现。

  由上期文章介绍的 Hbase 的整体架构及检索的时间复杂度分析我们可以看出,行键、列簇等的设计及数据存储决定了 Hbase 总体的性能及执行查询的效率,很多使用 Hbase 的项目及技术人员能熟练的使用 Hbase Shell 或 SDK API 访问 Hbase,进行表创建、删除等 DDL,以及 put/delete/scan 等 DML 操作,但并深入探究需要多少个列簇,一个列簇需要多少列,什么数据应该存入列名中,以及什么数据应该存入单元等开发设计中的关键问题。

  基于 Hbase 的系统设计与开发中,需要考虑的因素不同于关系型数据库,Hbase 模式本身很简单,但赋予你更多调整的空间,有一些模式写性能很好,但读取数据时表现不好,或者正好相反,类似传统数据库基于范式的 OR 建模,在实际项目中考虑 Hbase 设计模式是,我们需要从以下几方面内容着手:

  以下我们以一个使用 Hbase 技术的真实客户案例为例,说明 Hbase 设计模式在真实项目中的实践,并通过不同的表设计模式,可以看出在模式是如何影响到表结构和读写表的方式方法,以及对客户端检索查询的性能的影响。

  客户简介:客户是一个互联网手机游戏平台,需要针对广大手游玩家进行手游产品的统计分析,需要存储每个手游玩家即客户对每个手游产品的关注度(游戏热度),且存储时间维度上的关注度信息,从而能针对客户的喜好进行挖掘并进行类似精准营销的手游定点推送,广告营销等业务,从而扩大该平台的用户量并提升用户粘着度。

  该平台上手游产品分类众多,总共在 500 余以上,注册玩家(用户帐号)数量在 200 万左右,在线 万多,每天使用手游频率峰值在 10 万/人次以上,年增量 10%以上。

  根据以上需求,手游产品动态增长,无法确定哪些手游产品需要被存储,全部存储又会表超过 200 列,造成大量空间浪费,玩家每天使用手游的频率及分类不确定,客户注册用户超百万,按天的使用热度数据量超过 1000 万行,海量数据也使得表查询及业务分析需要的集群数量庞大及 SQL 优化,效率低下,因此传统关系型数据库不适合该类数据分析和处理的需求,在项目中我们决定采用 Hbase 来进行数据层的存储的分析。

  客户案例中表的设计,我们需要存储玩家信息,通常是微信号,QQ 号及在该手游平台上注册的帐号,同时需要存储该用户关注什么手游产品的信息,而用户每天会玩一个或者多个手游产品,每个产品玩一次或者多次,因此存储的应该是该用户对某一手游产品的关注度(使用次数),该使用次数在每天是一个动态的值,而用户对手游产品也是一个多对多的 keyvalue 键值的集合。该手游平台厂商关心的是诸如“XXX 客户玩家关注 YYY 手游了么?”,“YYY 手游被用户关注了么?”这类的业务维度分析。

  假设每天每个手游玩家对每个产品的关注度都存在该表中,则一个可能的设计方案是每个用户每天对应一行,一用户 ID+当天的时间戳作为行健,建立一个保存手游产品使用信息的列簇,每列代表该天该用户对该产品的使用次数。

  本案例中我们只设计一个列簇,一个特定的列簇在 HDFS 上会由一个 Region 负责,这个 region 下的物理存储可能有多个 HFile,一个列簇使得所有列在硬盘上存放在一起,使用这个特性可以使不同类型的列数据放在不同的列簇上,以便隔离,这也是 Hbase 被称为面向列存储的原因,在这张表里,因为所有手游产品并没有明显的分类,对表的访问模式也不需区分手游产品类型,因此并不需要多个列簇的划分,你需要意识到一点:一旦创建了表,任何对该表列簇的动作通常都需要先让表 offline。

  现在你需要检验这张表是否满足需求,为此最重要的事是定义访问模式,也就是应用系统如何访问 Hbase 表中的数据,在整个 Hbase 系统设计开发过程中应该尽早这么做。

  我们现在来看,我们设计的该 Hbase 表是否能回答客户关心的问题:比如“帐号为 的用户关注过哪些手游?”,沿着这个方向进一步思考,有相关业务分析的问题:“ 用户是否玩过 3CountryBattle(三国 3)手游?”“哪些用户关注了 DTLegend(刀塔传奇)?”“3CountryBattle(三国 3)手游被关注过吗?”

  基于现在的 prodFocus 表设计,要回答“帐号为 的用户关注过哪些手游?”这个访问模式,可以在表上执行一个简单的 Scan 扫描操作,该调用会返回整个 前缀的整个行,每一行的列簇进行列遍历就能找到用户关注的手游列表。

  代码解释:首先通过 Configuration 设置 Hbase Master 主机及客户端连接端口,风水在国外_中国,然后使用 HtableInterface 接口示例连接上 prodFocus 表,因为 prodFocus 表 rowkey 设计为用户 ID+$+当天的时间戳,因此我们创建以用户“”为检索前缀的 Scan 扫描,扫描返回的 ResultScanner 即为该用户相关的所有行数据,遍历每行的“degreeInfo”列簇中的各个列即可获得该用户所有关注(玩过)的手游产品。

  第二个问题“ 用户是否玩过 3CountryBattle(三国 3)手游”的业务跟第一个类似,客户端代码可以用 Scan 找出行健为 前缀的所有行,返回的 result 集合可以创建一个数组列表,遍历这个列表检查 3CountryBattles 手游是否作为列名存在,即可判断该用户是否关注某一手游,相应代码与上文问题 1 的代码类似:

  代码解释:同样通过扫描前缀为“”的 Scan 执行表检索操作,返回的 ListkeyValue数组中每一 Key-value 是 degreeInfo 列簇中每一列的键值对,即用户关注(玩过)的手游产品信息,判断其 Key 值是否包含“3CountryBattle”的游戏名信息即可知道该用户是否关注该手游产品。

  看起来这个表设计是简单实用的,但是如果我们接着看第三个和第四个业务问题“哪些用户关注了 DTLegend(刀塔传奇)?”“3CountryBattle(三国 3)手游被关注过吗?”

  如你所看到的,现有的表设计对于多个手游产品是放在列簇的多个列字段中的,因此当某一用户对产品的喜好趋于多样化的时候(product key-value 键值对会很多,意味着某一 rowkey 的表列簇会变长,这本身也不是大问题,但它影响到了客户端读取的代码模式,会让客户端应用代码变得很复杂。

  同时,对于第三和第四问题而言,每增加一种手游关注的 key-value 键值,客户端代码必须要先读出该用户的 row 行,再遍历所有行列簇中的每一个列字段。从上文 Hbase 索引的原理及内部检索的机制我们知道,行健是所有 Hbase 索引的决定性因素,如果不知道行健,就需要把扫描限定在若干 HFile 数据块中,更麻烦的是,如果数据还没有从 HDFS 读到数据块缓存,从硬盘读取 HFile 的开销更大,从上文 Hbase 检索的时间复杂度分析来看,现在的 Hbase 表设计模式下需要在 Region 中检索每一列,效率是列的个数*O(max(el b),从理论上已经是最复杂的数据检索过程。

  对关注该平台业务的客户公司角度考虑,第三个第四个的业务问题更加关注客户端获取分析结果的实时分析的性能,因此从设计模式上应该设计更长的行健,更短的列簇字段,提高 Hbase 行健的检索效率并同时减少访问宽行的开销。

  Hbase 设计模式的简单和灵活允许您做出各种优化,不需要做很多的工作就可以大大简化客户端代码,并且使检索的性能获得显著提升。我们现在来看看 prodFocus 表的另一种设计模式,之前的表设计是一种宽表(wide table)模式,即一行包括很多列。每一列代表某一手游的热度。同样的信息可以用高表(tall table)形式存储,新的高表形式设计的产品关注度表结构如表 2 所示。

  表解释:将产品在某一天被某用户关注的关联关系设计到 rowkey 中,而其关注度数据只用一个 key-value 来存储,行健 Daqier_weixin65 串联了两个值,产品名和用户的帐号,这样原来表设计中某一用户在某天的信息被转换为一个“产品-关注的用户”的关系,这是典型的高表设计。

  HFile 中的 keyvalue 对象存储列簇名字。使用短的列簇名字在减少硬盘和网络 IO 方面很有帮助。这种优化方式也可以应用到行健,列名,甚至单元。紧凑的 rowkey 存储业务数据意味应用程序检索时,IO 负载方面会大大降低。这种新设计在回答之前业务关心的“哪些用户关注了 XXXX 产品?”或者“XXXX 产品被关注过吗?”这类问题时,就可以基于行健使用 get() 直接得到答案,列簇中只有一个单元,所以不会有第一种设计中多个 keyvalue 遍历的问题,在 Hbase 中访问呢驻留在 BlockCache 离得一个窄行是最快的读操作。从 IO 方面来看,扫描这些行在一个宽行上执行 get 命令然后遍历所有单元相比,从 RegionServer 读取的数据量是相同的,但索引访问效率明显大大提高了

  例如要分析“3CountryBattles(三国群雄)手游是否被 用户关注?”时,客户端代码示例如下:

  我们使用压力测试来检验一下两种 Hbase 表设计模式下的并发访问性能的对比,在百万级及千万级行数据条件下,采用宽表和高表的两种设计模式下,在进行”关注 3CountryBattles 手游的用户”查询,取得 result 检索结果的相应时间如下表所示:

  当然还有一些其他优化技巧。你可以使用 MD5 值做为行健,这样可以得到定长的 rowkey。使用散列键还有其他好处,你可以在行健中使用 MD5 去掉“$”分隔符,这会带来两个好处:一是行键都是统一长度的,可以帮助你更好的预测读写性能。第二个好处是,不再需要分隔符后,scan 的操作代码更容易定义起始和停止键值。这样的话你使用基于用户+手游名的 MD5 散列值来设定 Scan 扫描紧邻的起始行(startRow 和 stopRow)就可以找到该手游受关注的最新的热度信息。

  使用散列键也会有助于数据更均匀的分布在 region 上。如该案例中,如果客户的关注度是正常的(即每天都有不同的客户玩不同的游戏),那数据的分布不是问题,但有可能某些客户的关注度是天生倾斜的(即某用户就是喜欢某一两个产品,81444资料2019浙江绍兴市柯桥区各级机关考试录用!每天热度都在这一两个产品上),那就会是一个问题,你会遇到负载没有分摊在整个 Hbase 集群上而是集中在某一个热点的 region 上,这几个 region 会成为整体性能的瓶颈,而如果对 Daqier_weixin65 模式做 MD5 计算并把结果作为行键,你会在所有 region 上实现一个均匀的分布。





2017开奖记录开奖结果| 最快开奖结果现场直播| 本港台j2现场报码| 挂牌玄机彩图| 网上买码| 夜明珠预测ymz01| www.250555.com| 王中王铁算盘开奖结果889918| www.444449a.com| 今日六和彩开什么号码| 马会开奖结果挂牌| 六合神童网免费资料区|