Hbase常用面试题和高级查询

Hbase常用面试题和高级查询

一、HBase的工作方式
  hbase表中的数据按照行键的字典顺序排序,hbase表中的数据按照行的的方向切分为多个region,最开始只有一个region 随着数据量的增加 产生分裂 这个过程不停的进行 一个表可能对应一个或多个region。region是hbase表分布式存储和负载均衡的基本单元 一个表的多个region可能分布在多台HRegionServer上,region是分布式存储的基本单元 但不是存储的基本单元内部还具有结果。
  一个region由多个Store来组成,有几个store取决于表的列族的数量 一个列族对应一个store 之所以这么设计 是因为 一个列族中的数据往往数据很类似方便与进行压缩节省存储空间,表的一个列族对应一个store store的数量由表中列族的数量来决定,一个store由一个memstore 和零个或多个storefile组成,storefile其实就是hdfs中的hfile 只能写入不能修改。
  数据写入hbase时 先在hlog中记录日志 再修改memstore 直接返回成功 这样 不需要真正等待写入hdfs的过程 所以很快,memstore 内存有限 当写入数量达到一定的阈值的时候 就会创建一个新的memstore继续工作 而旧的memstore 会用一个单独的线程 写出到storefile中,最终清空旧的memstore 并在zookeeper中记录最后写出数据时间的redo point信息,由于storefile 不能修改 所以数据的更新其实是不停创建新的storefile的过程,这样多个storefile中可能存在对同一个数据的多个版本 其中旧的版本其实是垃圾数据 时间一长 垃圾数据就可能很多浪费磁盘空间,所以当达到一定的阈值的时候 会自动合并storefile 在合并的过程中将垃圾数据清理,而当合并出来的文件达到一定程度时 再从新进行切分,防止文件过大,虽然看起来是小变大再变小,但是经过这个过程垃圾数据就被清理掉了。
  所以store中的数据 其实是memstore和storefile来组成的,而memstore由于是内存中的数据 一旦断电就会丢失,为了解决可能的意外造成数据丢失的问题 hbase在整个hregionserver中 通过记录hlog 来保存了所有数据操作的记录,当hbase启动时 会检查zookeeper中的redopoint信息 从hlog中恢复 这个时间点之后的数据 解决数据容易丢失的问题,hlog整个hregionServer中只有一个 所有这台机器中的所有HRegion都公用这个文件 这样整个机器的磁盘性能都可以为这一个文件提供支持提升文件的读写效率,hlog文件最终对应的是hdfs中的文件,也是分布式存储的,保证了日志文件的可靠性。
  而在数据读取时会将store的中memstore和storefile中的数据进行合并提供查询,此处所谓的合并,并不是真正的数据的合并,而是将数据的索引进行合并,由于hbase中的数据天然排序,再加上索引,整个查询也可以非常的快。
二、集群结构信息
  hbase中的老大叫hmaster 小弟叫hregionServer,客户端叫Client,Zookeepr为hbase提供集群协调。
  client:访问hbase 保留一些缓存信息提升效率
  zookeeper:保证任何时候集群只有一个HMaster。监控regionServer的状态 将其上线下线信息通知mater。存储所有Region的寻址地址。存储hbase的元数据信息包括有哪些表、有哪些列族等等。
  Mater:为RegionServer分配Region。为RegionServer进行负载的均衡。hdfs上的垃圾回收。处理对Schema数据的更新请求.
  RegionServer:维护Master分配给它的region,处理对这些region的IO请求。负责切分在运行过程中变得过大的region
三、为什么hbase可以很快?
  从逻辑结构上来说:
   表按照行键进行了排序,所以查询时可以很快定位。
   数据按照行键切分为多个HRegion,分布在多个RegionServer中,查询大量数据时,多个RegionServer可以一起工作,从而提高速度。
  从物理结构上来说:
   HRegion是存活在RegionServer的内存中的,读写会非常的高效。
   还有HFile的支持保证大量的数据可以持久化的保存。
   数据最终落地到HDFS中,分布式的存储,保证数据段可靠性和可扩展性。
四、为什么hbase可以存储很多数据?
  基于hdfs,所以支持可扩展性,可以通过增加大量的廉价的硬件提高存储容量。
  按列存储,空的数据不占用空间,当存储稀疏数据时,不会浪费空间。
  按例存储,同一列的数据存放在一起,而同一列的数据一般都是同样的类型的内容相似的数据,可以实现非常高效的压缩,节省空间。
五、为什么hbase的数据是可靠的?
  基于hdfs,由hdfs的可靠性保证了hbase的可靠性–即数据可以有多个备份。
  利用zookeeper实现了HA,即使某一台机器挂掉另外的机器也可以很快的替换它。
六、hbase和hive和传统的关系型数据库的比较:
  比起传统的关系型数据库,可以存储半结构化非结构化的数据,可以存储和处理更大级别的数据,提供高效的查询,对于稀疏数据的处理更好,具有更好的横向扩展性,免费开源性价比很高。但是不能支持非常好的事务特性,只支持行级的事务。只能通过行键来查询,表设计时难度更高。而mysql用来存储结构化的数据提供更好的事务控制。
  比起hive,hive只是在mapreduce上包了一层壳,本质上还是离线数据的处理的工具,实时查询性能有限,本质上是一个基于hadoop的数据仓库工具,不能支持行级别的新增修改和删除。hbase可以提供实时的数据的处理能力,适用于在线数据查询处理,本质上是一种数据库工具。
六、HBase的高级查询
  (1)实现范围查询
   如果只设置scan但是不做任何限制 则查询所有数据
    Scan scan = new Scan();
   如果设置scan并且设置scan的扫描开始和结束为止则查询范围数据 注意含头不含尾
    Scan scan = new Scan();
    scan.setStartRow(“rk2”.getBytes());
    scan.setStopRow(“rk4”.getBytes());
   (2)过滤器实现过滤查询

			在scan上提供了方法来实现过滤查询
				Scan scan = new Scan();
				Filter filter = ...
				scan.setFilter(filter)
			Hbase内置的14种过滤器
				HBase为筛选数据提供了一组过滤器,通过这个过滤器可以在HBase中的数据的多个维度(行,列,数据版本)上进行对数据的筛选操作,也就是说过滤器最终能够筛选的数据能够细化到具体的一个存储单元格上(由行键,列明,时间戳定位)。
				Filter filter = new RowFilter(CompareOp.GREATER_OR_EQUAL,new BinaryComparator("rk3".getBytes()));
				//--RowFilter配合正则过滤器 可以通过正则表达式从hbase表中筛选所有行键符合正则的数据
				!!Filter filter = new RowFilter(CompareOp.EQUAL,new RegexStringComparator("^[^x]*x[^x]*$"));
				Filter filter = new PrefixFilter("rkx".getBytes());
				Filter filter = new KeyOnlyFilter();
				Filter filter = new RandomRowFilter(0.2f);
				Filter filter = new InclusiveStopFilter("rk4".getBytes());
				Filter filter = new FirstKeyOnlyFilter();
				//--ColumnPrefixFilter可以实现按照列的前缀过滤数据
				!!Filter filter = new ColumnPrefixFilter("c2".getBytes());
				//--ValueFilter可以按照值来过滤数据
				!!Filter filter = new ValueFilter(CompareOp.EQUAL,new RegexStringComparator("^[^2]*2.*$"));
				//--SingleColumnValueFilter按照某一个指定列的值决定该行是否返回
				!!Filter filter = new SingleColumnValueFilter("cf1".getBytes(), "c1".getBytes(), CompareOp.EQUAL, new RegexStringComparator("^[^3]*3.*$"));
				//--FilterList 可以将多个过滤器的效果合并起作用
				!!Filter f1 = new RowFilter(CompareOp.EQUAL,new RegexStringComparator("^rk\\d+$"));
				!!Filter f2 = new KeyOnlyFilter();
				!!FilterList fl = new FilterList(Operator.MUST_PASS_ALL, f1,f2);
				scan.setFilter(fl);

七、HBase的表设计
  对HBase表的设计会直接影响hbase使用的效率和使用的便利性,主要是 列族的设计 和 行键的设计。
  1.列族的设计
   在设计hbase表时候,列族不宜过多,越少越好,官方推荐hbase表的列族不宜超过3个。
   经常要在一起查询的数据最好放在一个列族中,尽量的减少跨列族的数据访问。
   如果有多个列族,多个列族中的数据应该设计的比较均匀。
  2.行键的设计
   hbase表中行键是唯一标识一个表的字段,所以行键设计的好不好将会直接影响未来对hbase的查询的性能和查询的便利性,所以hbase中的行键是需要进行设计的。
   行键设计的基本原则:
    行键必须唯一:必须唯一才能唯一标识数据
    行键必须有意义:这样才能方便数据的查询
    行键最好是字符串类型:因为数值类型在不同的系统中处理的方式可能不同
    行键最好具有固定的长度:不同长度的数据可能会造成自然排序时排序的结果和预期不一致
    行键不宜过长:行键最多可以达到64KB,但是最好是在10~100字节之间,最好不要超过16字节,越短越好,最好是8字节的整数倍。
   行键的最佳实践:
    散列原则:行键的设计将会影响数据在hbase表中的排序方式,这会影响region切分后的结果,要注意,在设计行键时应该让经常要查询的数据分散在不同的region中,防止某一个或某几个regionserver成为热点。
    有序原则:行键的设计将会影响数据在hbase表中的排序方式,所以一种策略是将经常连续查询的条件作为行键最前面的数据,这样一来可以方便批量查询。
八、HBase二级索引的设计
  涉及到多个条件组合查询时,hbase就有点力不从心了,因为hbase支持的是三种方式,上面已经提到了,对于多条件组合查询来说,如果通过某个条件filter出来一部分数据,然后再一个个判断,这样比较影响性能。但又不能将
这些条件都设计到rowkey中去,这时可以考虑到用二级索引。
  二级索引的实现:设计两个列族,一个列族什么数据都不存,存放索引的key就对应这个列族,另一个列族就对应主数据,主数据的rowkey就是之前业务正常设计好的,现在通过二级索引来满足多条件组合查询。数据还是和之前不变,只是多用一些资源来存放索引的rowkey。先通过多条件找到二级索引的rowkey,然后再截取到最终查询主数据的rowkey,这样就可以实现多条件组合查询了。
  其实也可以将这些组合条件放入mysql,通过mysql找到查询主数据的rowkey,然后用这个rowkey去hbase中查询,得到最终结果。
  详情参考这篇博客:Hbase二级索引的设计
九、Hbase的缓存原理
  hbase的缓存由两部分组成,一部分是memstore,一部分是blockcache。一个regionServer对应多个region和一个blockcache,每个region对应一个memstore,写入数据的时候,是先写预写日志,上文已经说了,然后再写入memstore,当memstore达到阈值,将数据写入hfile中。读取数据的时候先到memstore中找,没有的话再去blockcache中找,最后再去hfile中读取。这里就有一个LRU算法问题,确认是blockcache是经常查询的数据。
  想去参考这篇博客:hbase缓存机制
十、Hbase调优
  1、Scan 缓存
   如果HBase的输入源是一个MapReduce Job,要确保输入的Scan的setCaching值要比默认值0要大。使用默认值就意味着map-task每一行都会去请求一下region-server。可以把这个值设为500,这样就可以一次传输500行。当然这也是需要权衡的,过大的值会同时消耗客户端和服务端很大的内存,不是越大越好。
  2、Scan 属性选择
   当Scan用来处理大量的行的时候(尤其是作为MapReduce的输入),要注意的是选择了什么字段。如果调用了 scan.addFamily,这个列族的所有属性都会返回。如果只是想过滤其中的一小部分,就指定那几个column,否则就会造成很大浪费,影响性能。
  3、关闭 ResultScanners
   这与其说是提高性能,倒不如说是避免发生性能问题。如果你忘记了关闭ResultScanners,会导致RegionServer出现问题。所以一定要把ResultScanner包含在try/catch 块中…
  4、块缓存
   Scan实例可以在RegionServer中使用块缓存,可以由setCacheBlocks方法控制。如果Scan是MapReduce的输入源,要将这个值设置为 false。对于经常读到的行,就建议使用块缓冲。
  5、行键的负载优化
   当scan一个表的时候, 如果仅仅需要行键(不需要no families, qualifiers, values 和 timestamps),在加入FilterList的时候,要使用Scanner的setFilter方法的时候,要填上MUST_PASS_ALL操作参数(译者注:相当于And操作符)。一个FilterList要包含一个 FirstKeyOnlyFilter 和一个 KeyOnlyFilter.通过这样的filter组合,就算在最坏的情况下,RegionServer只会从磁盘读一个值,同时最小化客户端的网络带宽占用。
  6、表创建: 延迟log刷写
   Puts的缺省行为使用 Write Ahead Log (WAL),会导致 HLog 编辑立即写盘。如果采用延迟刷写,WAL编辑会保留在内存中,直到刷写周期来临。好处是集中和异步写HLog,潜在问题是如果RegionServer退出,没有刷写的日志将丢失。但这也比Puts时不使用WAL安全多了。延迟log刷写可以通过 HTableDescriptor 在表上设置,hbase.regionserver.optionallogflushinterval缺省值是1000ms。
  7、HBase 客户端: 自动刷写
   当你进行大量的Put的时候,要确认你的HTable的setAutoFlush是关闭着的。否则的话,每执行一个Put就要想区域服务器发一个请求。通过 htable.add(Put) 和 htable.add( Put)来将Put添加到写缓冲中。如果 autoFlush = false,要等到写缓冲都填满的时候才会发起请求。要想显式的发起请求,可以调用flushCommits。在HTable实例上进行的close操作也会发起flushCommits

猜你喜欢

转载自blog.csdn.net/qq_38019655/article/details/84107309