你好,游客 登录
背景:
阅读新闻

浅谈Hbase

[日期:2016-07-05] 来源:简书  作者:codertom [字体: ]

  什么是Hbase

  Hbase是一种基于HDFS的分布式数据库

  支持海量的数据的存储,千亿、万亿级别

  表存储比较稀疏,Schema十分灵活

  支持数据的多版本

  列式存储

  主键索引,低延迟的随机查询

  扩展性与生俱来

  HBase的基本概念和架构:

Hbase

  Hbase总体架构图

  HMaster:Hbase的管理协调进程,用于Schema的管理,管理对Table的增、删、改、查操作,调整Region的分布,Region进行分裂的时候负责新的Region的分配。

  RegionServer:Hbase的数据节点进程,主要是负责响应用户的I/O请求。

  Zookeeper在这里主要起命名和通知的功能,Zk主要负责多HMaster的选举,存贮部分元数据、实时监控RegionServer,宕机之后迅速进行Region的转移、保证集群中只有一个HMaster。

  数据存储:

  HRegion 是RegionServer内部维护的一个对象,是一个Table的一个子集,一个Region和一个表一一对。

  HLOG是Hbase的WAL(Write-Ahead Logging)机制的一个实现,通过预写日志,来避免节点宕机带来的数据丢失的问题,当写入HLOG成功,此时此节点宕机,HMaster控制Region转移到其他节点后,在Region上线的过程中会将HLOG上的数据重新写入,保证可靠性。

  MemStore:数据写入时先进行MemStore的写入,当MemStore写满之后进行Flush,将数据FLush成一个HRegion。这样就保证了高吞吐,同时数据写入内存后,请求即返回,响应速度十分快。

  Store是Region的子集,一个Store对应着Hbase的一个列族,所以Hbase的列族是分开存储的,通常将经常放在一个查询的数据放在一个列族中,同时官方不建议用多列族,原因是会导致数据不均匀的问题。

  StoreFile对应着Hbase的底层存储—HFile,HFile是Hbase的底层存储,所有数据以固定的数据格式存储在HDFS的特定目录下,会定期的Split和Compact。

  Table的层级和在HDFS上的存储:

  表在HDFS上的存储

  hbase_table

  表的层级关系:

  Region.png

  表结构:

  Hbase基本概念

  逻辑视图:

  row-colum

  ​Hfile里是怎么存储的:

  数据膨胀:

  从上面的图我们可以看见,数据的基本格式为:rowkey:timestamp:columm_family:coloum:value.逻辑上的一行数据被拆成了两行数据进行存储,同时存储的数据大大的膨胀了主要是冗余了rowkey timestamp 和coloumFamily字段,通常数据会膨胀2倍以上,具体大小视具体的数据。

  更小的单元

  Cell

  Cell的概念是在Hbase0.96之后出现的,用来表征一行数据,Cell的前身是KeyValue,Cell的格式如下:

  ​ {row, column, version}

  Version:

  Version使用来标识数据版本的概念,Hbase支持多版本的机制,同一份数据具有多个版本,这样可以追踪到一条数据的上一个版本的信息,Hbase中的Cell是按照Version倒序排列的,所以第一个读取到的一定是最新版本的数据。

  Hbase 默认的版本数为1,过量的Version数据将在Compact的过程中被删除,官方的建议是Version最大数最好不要超过100,因为这样会很大程度上消耗存储空间。

  TTL( Time To Live)

  TTL是一个标识一个数据的生命周期,对一个列族设定TTL之后,在到达TTL的时间时,数据会自动删除,尽管设置了Version,到达了TTL之后数据仍然会被删除:

  Hbase的存储模型:

  LSM思想:LSM的基本思想是将修改的数据保存在内存,达到一定数量后在将修改的数据批量写入磁盘,在写入的过程中与之前已经存在的数据做合并。同B树存储模型一样,LSM存储模型也支持增、删、读、改以及顺序扫描操作。LSM模型利用批量写入解决了随机写入的问题,虽然牺牲了部分读的性能,但是大大提高了写的性能.

  因为小树先写到内存中,为了防止内存数据丢失,写内存的同时需要暂时持久化到磁盘,对应了HBase的MemStore和HLog

  MemStore上的树达到一定大小之后,需要flush到HRegion磁盘中(一般是hadoop DataNode),这样MemStore就变成了DataNode上的磁盘文件StoreFile,定期HRegionServer对DataNode的数据做merge操作,彻底删除无效空间,多棵小树在这个时机合并成大树,来增强读性能。

  MemStore的Flush过程:

  ​ 在Hbase的写入过程中,首先追加到HLOG上,来保证数据的可靠性,随后append到MemStore上,当MemStore写满了之后会进行Flush过程,Flush过程中Hbase会开启一个新的MemStore接收新的写入,Flush会产生一个新的HFile到HDFS上,当Hfile数量和大小达到一定程度时,已经大大的影响到了查询性能,随后会进行Compact操作。

  Compact过程:

  随着MemStore的不断Flush,在HDFS上会形成越来越多的小文件,文件数量过多会大大的降低查询效率,Compact过程会尽可能的将它们合并成规模更少但是更大的文件

  合并过程又分为minor compact和major的compact。

  minor compact:主要是将小于一定阈值的文件合并成更大的文件。

  major compact:主要是将所有的文件都合并成一个文件。

  文件合并之后会大大的提高查询效率,但是由于合并过程中会读取全量的数据,这样会大量的占用磁盘的IO,导致查询效率大幅下降,甚至不可用。

  Split过程:

  ​ 当一个Region的大小达到一定程度的时候,会进行Region的Split过程,Split过程中Region会进行下线操作,此时不响应任何请求,直到Split过程结束。多列族且数据不均匀的情况会导致,大列族触发了Split,尽管小列族的数据很小,但是依然会进行split导致数据不均,同时大列族的flush会带动小列族的flush,导致反复的IO,十分影响效率,久而久之会严重的影响Scan查询效率。

  Hbase对查询的优化:

  Server端缓存——BlockCache

  一个Hbase的查询请求首先会先到Memstore中查数据,查不到就到BlockCache中查,再查不到就会到磁盘上读,BlockCache采用LRU机制,这样相当于对常用数据进行缓存,提高查询效率,但是在进行Scan的时候尽量避免使用cache,因为这样会大大的降低查询效率,例如MapReduce在做全表Scan的时候一定要关闭cache。

  多File的选择——Bloom Filter

  ​ Hbase在HDFS上存储可能会有多个文件,在没有合并的情况下,各个File之间Rowkey索引可能互有交集,查询时最坏情况下要遍历全部文件,这样就大大的降低了查询效率,Hbase提供了Bloom Filter来实现快速的定位目标记录所在的文件。

  ​ Bloom Filter可以保守的确定一条数据在不在一个集合中,如果Bloom Filter认为一条数据在一个文件中,但事实上不一定在。但是Bloom Filter认为不在那么该数据一定不在。

  ​ Bloom Filter的原理使用一个十分大的二进制数组将File中的所有数据进行多种Hash算法hash到这个二进制数组上。当查询到来时,对查询进行同样的Hash处理,该结果在该File中,那么就判断该数据在这个集合中,但是由于Hash冲突的存在,这种判断的正确性不能100%保证,但是也能帮我们挡住大量的请求了。

  MapReduce对Hbase的支持:

  Hbase是Hadoop生态系统中很重要的一员,所以Hbase和MapReduce的契合度十分高,Mapreduce为Hbase提供了抽象度很高的Api,能快速的对Hbase中的数据进行计算。Mapredece中提供了TableMapReduceUtil来支持读取和写入Hbase两种场景:

  在Map函数中继承下TableMapper:

  实现Reduce函数:

  此处有坑! 在Hbase作为Mapreduce为输入的时候,Scan需要关闭blockCache 否则容易拖垮集群。

  虽然这种是比较常用的mapreduce方式,但是,它的性能十分不好,数据吞吐量比较大的时候会给Hbase造成十分大的负载。

  另一种加载机制:BulkLoad和HFileInputFormat

  为了避免大量数据批量涌入造成Hbase Region进行频繁的compact和Split 造成短暂性不可用的问题。 Hbase提供了一种批量写入到Hbase底层存储的机制——bulkLoad。

  bulkLoad是通过直接写底层Hbase存储的机制避开了整个Hbase的写入流程,从而避免Region的Compact和Split。

  为什么选择bulkLoad:

  处理流程:

  流程图

  bulkload3.png

  应用场景:

  bulkLoad4.png

  对于直接读取Hbase底层Hfile,官方没有提供方法,不过可以通过自定义HfileInputFormat实现,但是这里面存在的问题是,对于还在内存中的数据通过这种方式查询不到(不知道现在有没有解决)。

  “诟病”——热点问题

  在初次写入或者rowkey分布不均匀的情况下,容易导致集群负载不一致,查询和写入速度变慢。

  rowkey被设计为顺序,或分布比较集中的情况。顺序的rowkey虽然能为scan带来比较高的性能,但是会在写入时带来写人热点的问题。

  ​ 初次写入问题则是第一次写入时默认只有一个region,那么如果第一次有大量数据写入,会导致Region会很快的进行compact和Split,会短暂的导致数据不可用,进而阻塞写操作。

  hotpointpic.png

  解决:合理设置rowkey(主要针对写入热点问题,同时实时写入数据):

  对rowkey进行hash或MD5

  翻转倒序

  避免顺序时间或者时间戳

  加盐(salting)

  salting1.png

  salting2.png

  aftersalting.png

  局限性:虽然做了salting 但是还是不能把数据准确的分到不同的region上

  预分区:

  预分区是在建表的时候根据预先设计的Rowkey,预先进行rowkey的划分。这样可以解决数据初始写入压力大的问题。

  preregion.png

  局限:随着数据量的增加,还是会产生,compact、split的,region短暂性下线的问题。

  终极大招bulkload:

  bulkload巧妙的避开了Hbase Api的写入,所以不会产生Compact和Split的问题。同mapreduce配合使用,系统吞吐量十分大。

  局限:只能做离线的数据导入,不支持实时写入,一般场景为离线非实时的场景。

 

  以上均为自己总结的,作为自己的备忘录,希望大家看到错误之处,帮忙指出,共同学习,谢谢。





收藏 推荐 打印 | 录入: | 阅读:
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款