一条数据的HBase之旅,简明HBase入门教程

发表于:2018-4-19 09:32

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:51Testing软件测试网采编

  示例数据
  给出一份我们日常都可以接触到的数据样例,先简单给出示例数据的字段定义:
  示例数据字段定义
  本文力求简洁,仅给出了最简单的几个字段定义。如下是”虚构”的样例数据:
  示例数据
  在本文大部分内容中所涉及的一条数据,是上面加粗的最后一行"Mobile1"为"13400006666"这行记录。在下面的流程图中,我们使用下面这样一个红色小图标来表示该数据所在的位置:
  数据位置标记
  可选接口
  HBase中提供了如下几种主要的接口:
  Java Client API
  HBase的基础API,应用最为广泛。
  HBase Shell
  基于Shell的命令行操作接口,基于Java Client API实现。
  Restful API
  Rest Server侧基于Java Client API实现。
  Thrift API
  Thrift Server侧基于Java Client API实现。
  MapReduce Based Batch Manipulation API
  基于MapReduce的批量数据读写API。
  除了上述主要的API,HBase还提供了基于Spark的批量操作接口以及C++ Client接口,但这两个特性都被规划在了3.0版本中,当前尚在开发中。
  无论是HBase Shell/Restful API还是Thrift API,都是基于Java Client API实现的。因此,接下来关于流程的介绍,都是基于Java Client API的调用流程展开的。
  关于表服务接口的抽象
  同步连接与异步连接,分别提供了不同的表服务接口抽象:
  Table 同步连接中的表服务接口定义
  AsyncTable 异步连接中的表服务接口定义
  异步连接AsyncConnection获取AsyncTable实例的接口默认实现:
  Create AsyncTable
  同步连接ClusterConnection的实现类ConnectionImplementation中获取Table实例的接口实现:
  Create Table
  写数据的几种方式
  Single Put
  单条记录单条记录的随机put操作。Single Put所对应的接口定义如下:
  在AsyncTable接口中的定义:
  CompletableFuture<Void> put(Put put);
  在Table接口中的定义:
  void put(Put put) throws IOException;
  Batch Put
  汇聚了几十条甚至是几百上千条记录之后的小批次随机put操作。
  Batch Put只是本文对该类型操作的称法,实际的接口名称如下所示:
  在AsyncTable接口中的定义:
  List<CompletableFuture<Void>> put(List<Put> puts);
  在Table接口中的定义:
  void put(List<Put> puts) throws IOException;
  Bulkload
  基于MapReduce API提供的数据批量导入能力,导入数据量通常在GB级别以上,Bulkload能够绕过Java Client API直接生成HBase的底层数据文件(HFile)。
  构建Put对象
  设计合理的RowKey
  RowKey通常是一个或若干个字段的直接组合或经一定处理后的信息,因为一个表中所有的数据都是基于RowKey排序的,RowKey的设计对读写都会有直接的性能影响。
  我们基于本文的样例数据,先给出两种RowKey的设计,并简单讨论各自的优缺点:
  样例数据:
  示例数据
  RowKey Format 1: Mobile1 + StartTime
  为了方便读者理解,我们在两个字段之间添加了连接符”^”。如下是RowKey以及相关排序结果:
  RowKey Format 1
  RowKey Format 2: StartTime + Mobile1
  RowKey Format 2
  从上面两个表格可以看出来,不同的字段组合顺序设计,带来截然不同的排序结果,我们将RowKey中的第一个字段称之为“先导字段”。第一种设计,有利于查询”手机号码XXX的在某时间范围内的数据记录”,但不利于查询”某段时间范围内有哪些手机号码拨出了电话?”,而第二种设计却恰好相反。
  上面是两种设计都是两个字段的直接组合,这种设计在实际应用中,会带来读写热点问题,难以保障数据读写请求在所有Regions之间的负载均衡。避免热点的常见方法有如下几种:
  Reversing
  如果先导字段本身会带来热点问题,但该字段尾部的信息却具备良好的随机性,此时,可以考虑将先导字段做反转处理,将尾部几位直接提前到前面,或者直接将整个字段完全反转。
  将先导字段Mobile1翻转后,就具备非常好的随机性。
  例如:
  13400001111^201803010800
  将先导字段Mobile1反转后的RowKey变为:
  11110000431^201803010800
  Salting
  Salting的原理是在RowKey的前面添加固定长度的随机Bytes,随机Bytes能保障数据在所有Regions间的负载均衡。
  RowKey With Salting
  Salting能很好的保障写入时将数据均匀分散到各个Region中,但对于读取却是不友好的,例如,如果读取Mobile1为”13400001111″在20180301这一天的数据记录时,因为Salting Bytes信息是随机选择添加的,查询时并不知道前面添加的Salting Bytes是”A”,因此{“A”, “B”, “C”}所关联的Regions都得去查看一下。
  Hashing
  Hashing是将一个RowKey通过一个Hash函数生成一组固定长度的bytes,Hash函数能保障所生成的随机bytes具备良好的离散度,从而也能够均匀打散到各个Region中。Hashing既有利于随机写入,又利于基于知道RowKey各字段的确切信息之后的随机读取操作,但如果是基于RowKey范围的Scan或者是RowKey的模糊信息进行查询的话,就会带来显著的性能问题,因为原来在字典顺序相邻的RowKey列表,通过Hashing打散后导致这些数据被分散到了多个Region中。
  因此,RowKey的设计,需要充分考虑业务的读写特点。
  本文内容假设RowKey设计:reversing(Mobile1) +StartTime
  也就是说,RowKey由反转处理后的Mobile1与StartTime组成。对于我们所关注的这行数据:
  关注的数据记录
  RowKey应该为: 66660000431^201803011300
  因为创建表时预设的Region与RowKey强相关,我们现在才可以给出本文样例所需要创建的表的”Region分割点“信息:
  假设,Region分割点为“1,2,3,4,5,6,7,8,9”,基于这9个分割点,可以预先创建10个Region,这10个Region的StartKey和StopKey如下所示:
  Region划分信息
  第一个Region的StartKey为空,最后一个Region的StopKey为空
  每一个Region区间,都包含StartKey本身,但不包含StopKey
  由于Mobile1字段的最后一位是0~9之间的随机数字,因此,可以均匀打散到这10个Region中
  定义列
  每一个列在HBase中体现为一个KeyValue,而每一个KeyValue拥有特定的组成结构,这一点在上一篇文章的数据模型章节已经提到过。
  所谓的定义列,就是需要定义出每一个列要存放的列族(Column Family)以及列标识(Qualifier)信息。
  我们假设,存放样例数据的这个表名称为”TelRecords” ,为了简单起见,仅仅设置了1个名为”I”的列族。
  Column Family以及列标识定义
  因为Mobile1与StartTime都已经被包含在RowKey中,所以,不需要再在列中存储一份。关于列族名称与列标识名称,建议应该简短一些,因为这些信息都会被包含在KeyValue里面,过长的名称会导致数据膨胀。
  基于RowKey和列定义信息,就可以组建HBase的Put对象,一个Put对象用来描述待写入的一行数据,一个Put可以理解成与某个RowKey关联的1个或多个KeyValue的集合。
  至此,这条数据已经转变成了Put对象,如下图所示:
  Put
  数据路由
  初始化ZooKeeper Session
  因为meta Region存放于ZooKeeper中,在第一次从ZooKeeper中读取META Region的地址时,需要先初始化一个ZooKeeper Session。ZooKeeper Session是ZooKeeper Client与ZooKeeper Server端所建立的一个会话,通过心跳机制保持长连接。
  获取Region路由信息
  通过前面建立的连接,从ZooKeeper中读取meta Region所在的RegionServer,这个读取流程,当前已经是异步的。获取了meta Region的路由信息以后,再从meta Region中定位要读写的RowKey所关联的Region信息。如下图所示:
  Region Routing
  因为每一个用户表Region都是一个RowKey Range,meta Region中记录了每一个用户表Region的路由以及状态信息,以RegionName(包含表名,Region StartKey,Region ID,副本ID等信息)作为RowKey。基于一条用户数据RowKey,快速查询该RowKey所属的Region的方法其实很简单:只需要基于表名以及该用户数据RowKey,构建一个虚拟的Region Key,然后通过Reverse Scan的方式,读到的第一条Region记录就是该数据所关联的Region。如下图所示:
  Location User Region
  Region只要不被迁移,那么获取的该Region的路由信息就是一直有效的,因此,HBase Client有一个Cache机制来缓存Region的路由信息,避免每次读写都要去访问ZooKeeper或者meta Region。



上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号