深入探讨hbase读性能优化探讨(20190308)

2019/3/8 星期五

深入探讨hbase读性能优化探讨(20190308)

hbase读性能优化归纳

深入探讨hbase读性能优化探讨(20190308)

hbase遇到的常见问题汇总:
无非是Full GC异常导致宕机问题、RIT问题、写吞吐量太低以及读延迟较大。
Full GC问题之前在一些文章里面已经讲过它的来龙去脉,主要的解决方案目前主要有两方面需要注意,
(1)一方面需要查看GC日志确认是哪种Full GC,根据Full GC类型对JVM参数进行调优,
(2)另一方面需要确认是否开启了BucketCache的offheap模式,建议使用LRUBlockCache的童鞋尽快转移到BucketCache来。
//这一部分,后面看到了,具体的讨论

RIT问题,我相信更多是因为我们对其不了解,具体原理可以戳这里,解决方案目前有两个,
(1)优先是使用官方提供的HBCK进行修复(HBCK本人一直想拿出来分享,但是目前案例还不多,等后面有更多案例的话再拿出来说),
(2)使用之后还是解决不了的话就需要手动修复文件或者元数据表。
//这一部分,后面看到了,具体的讨论

写吞吐量太低 具体看连接 HBase最佳实践-写性能优化策略 http://hbasefly.com/2016/12/10/hbase-parctice-write/

一般情况下,读请求延迟较大通常存在三种场景,分别为:

  1. 仅有某业务延迟较大,集群其他业务都正常 //客户端优化 HBase列族设计优化
  2. 整个集群所有业务都反映延迟较大 //hbase服务器端优化
  3. 某个业务起来之后集群其他部分业务延迟较大

主要分为四个方面:1、客户端优化、2、服务器端优化、3、列族设计优化以及4、HDFS相关优化,

HBase客户端优化
1、scan缓存是否设置合理 //上面是scan 缓存
小结:
数据加载到本地就缓存在scan缓存中;默认为100条数据大小
(1)一次scan会返回大量数据,并不是一下子把数据全部返回给客户端,这中间需要一个过程,scan缓存
(2)scan请求分成多次rpc请求进行加载,这样设计有2点好处:
第一点:避免一下子的大量数据请求可能会导致网络带宽严重消耗从而导致影响其他的业务
第二点:大量的数据可能会导致本地客户端的OOM
(3)需要scan缓存,加载一部分数据,然后遍历处理,在加载下一部分的数据到本地,如此反复,直到数据都加载完成。

提示:正常情况下,默认的scan环境就是可以正常工作的,但是,如果一次scan要查询几万甚至几十万的行数据的话,每一次的请求100条数据,就意味着一次scan需要几百甚至上千的prc请求,这种代价是恨到的。
可以增加scan缓存,比如设置成500或者1000
//一次scan扫描10W+数据的条件下,scan从100增加到1000的话,可以有效的降低scan请求的总延迟,延迟基本降低了25%

优化建议:大scan场景下将scan缓存从100增大到500或者1000,用以减少RPC次数
HBase 客户端扫描仪缓存
hbase.client.scanner.caching = 100
cdh解释:内存未提供数据的情况下扫描仪下次调用时所提取的行数。较高缓存值需启用较快速度的扫描仪,但这需要更多的内存且当缓存为空时某些下一次调用会运行较长时间。

2、get请求是否可以使用批量请求?
优化原理:HBase分别提供了单条get以及批量get的API接口,使用批量get接口可以减少客户端到RegionServer之间的RPC连接数,提高读取性能。另外需要注意的是,批量get请求要么成功返回所有请求数据,要么抛出异常。

优化建议:使用批量get进行读取请求

3、请求是否可以显示指定列族或者列?
优化原理:HBase是典型的列族数据库,意味着同一列族的数据存储在一起,不同列族的数据分开存储在不同的目录下。如果一个表有多个列族,只是根据Rowkey而不指定列族进行检索的话不同列族的数据需要独立进行检索,性能必然会比指定列族的查询差很多,很多情况下甚至会有2倍~3倍的性能损失。

优化建议:可以指定列族或者列进行精确查找的尽量指定查找

4、离线批量读取请求是否设置禁止缓存?
//不需要实时更新的数据,
(1)通常离线批量读取数据会进行一次性全表扫描,一方面数据量很大,另一方面请求只会执行一次。
(2)这种场景下如果使用scan默认设置,就会将数据从HDFS加载出来之后放到缓存。
(3)可想而知,大量数据进入缓存必将其他实时业务热点数据挤出,其他业务不得不从HDFS加载,进而会造成明显的读延迟毛刺
优化建议:离线批量读取请求设置禁用缓存,scan.setBlockCache(false)

HBase服务器端优化
一般服务端端问题一旦导致业务读请求延迟较大的话,通常是集群级别的,即整个集群的业务都会反映读延迟较大。
1、读请求是否均衡?
(1)也就是读的数据在一台regionserver上的某几个region上,这样会导致这台regionserver服务器严重耗尽io资源
(2)读请求不均衡会导致一个节点或者整个集群都会很差,严重的影响业务
(3)当然,写请求不均衡也会造成类似的问题,可见负载不均衡是HBase的大忌。
观察确认:观察所有RegionServer的读请求QPS曲线,确认是否存在读请求不均衡现象
优化建议:RowKey必须进行散列化处理(比如MD5散列),同时建表必须进行预分区处理

2、BlockCache读缓存是否设置合理?
(1)BlockCache作为读缓存,对于读性能来说至关重要。
(2)默认情况下BlockCache和Memstore的配置相对比较均衡(各占40%),可以根据集群业务进行修正,比如读多写少业务可以将BlockCache占比调大。
(3)BlockCache的策略选择也很重要,不同策略对读性能来说影响并不是很大,但是对GC的影响却相当显著,尤其BucketCache的offheap模式下GC表现很优越。
(4)另外,HBase 2.0对offheap的改造(HBASE-11425)将会使HBase的读性能得到2~4倍的提升,同时GC表现会更好!
观察所有RegionServer的缓存未命中率、配置文件相关配置项一级GC日志,确认BlockCache是否可以优化

优化建议:JVM内存配置量 < 20G,BlockCache策略选择LRUBlockCache;否则选择BucketCache策略的offheap模式;期待HBase 2.0的到来!
hbase.bucketcache.size = 1M
cdh解释:BucketCache 的总大小,以 MB 为单位。要配置的大小取决于可供 HBase 使用的内存量或本地 SSD 的大小。如果将 hbase.bucketcache.ioengine 设为“offheap”,则 BucketCache 会消耗 Java 的直接内存中的已配置内存量。

3、HFile文件是否太多?
(1)HBase读取数据通常首先会到Memstore和BlockCache中检索(读取最近写入数据&热点数据),如果查找不到就会到文件中检索
(2)HBase的类LSM结构会导致***每个store包含多数HFile文件,文件越多,检索所需的IO次数必然越多,读取延迟也就越高。
(3)hfile文件数量通常取决于Compaction的执行策略,一般和两个配置参数有关
hbase.hstore.compactionThreshold 表示一个store中的文件数超过多少就应该进行合并
hbase.hstore.compaction.max.size 表示参数合并的文件大小最大是多少,超过此大小的文件不能参与合并。
//这两个参数不能设置太’松’(前者不能设置太大,后者不能设置太小),导致Compaction合并文件的实际效果不明显,进而很多文件得不到合并。这样就会导致HFile文件数变多。
观察确认:观察RegionServer级别以及Region级别的storefile数,确认HFile文件是否过多

优化建议:hbase.hstore.compactionThreshold设置不能太大,默认是3个;设置需要根据Region大小确定,通常可以简单的认为hbase.hstore.compaction.max.size = RegionSize / hbase.hstore.compactionThreshold

4、Compaction是否消耗系统资源过多?
(1)Compaction是将小文件合并为大文件,提高后续业务随机读性能,但是也会带来IO放大以及带宽消耗问题(数据远程读取以及三副本写入都会消耗系统带宽)。
(2)正常配置情况下Minor Compaction并不会带来很大的系统资源消耗,除非因为配置不合理导致Minor Compaction太过频繁,或者Region设置太大情况下发生Major Compaction。
观察确认:观察系统IO资源以及带宽资源使用情况,再观察Compaction队列长度,确认是否由于Compaction导致系统资源消耗过多
优化建议:

(1)Minor Compaction设置:hbase.hstore.compactionThreshold设置不能太小,又不能设置太大,因此建议设置为5~6;hbase.hstore.compaction.max.size = RegionSize / hbase.hstore.compactionThreshold
(2)Major Compaction设置:大Region读延迟敏感业务( 100G以上)通常不建议开启自动Major Compaction,手动低峰期触发。小Region或者延迟不敏感业务可以开启Major Compaction,但建议限制流量;
(3)期待更多的优秀Compaction策略,类似于stripe-compaction尽早提供稳定服务

HBase列族设计优化
HBase列族设计对读性能影响也至关重要,其特点是只影响单个业务,并不会对整个集群产生太大影响。列族设计主要从两个方面检查:
1、 Bloomfilter是否设置?是否设置合理?
(1)Bloomfilter主要用来过滤不存在待检索RowKey或者Row-Col的HFile文件,避免无用的IO操作。
(2)它会告诉你在这个HFile文件中是否可能存在待检索的KV,如果不存在,就可以不用消耗IO打开文件进行seek。很显然,通过设置Bloomfilter可以提升随机读写的性能。

Bloomfilter取值有两个,row以及rowcol,需要根据业务来确定具体使用哪种。
(1)如果业务大多数随机查询仅仅使用row作为查询条件,Bloomfilter一定要设置为row,
(2)否则如果大多数随机查询使用row+cf作为查询条件,Bloomfilter需要设置为rowcol。
(3)如果不确定业务查询类型,设置为row。
//小结,也就是你查询的需要是经常用指定rk查询 还是用rk+列族(cf)查询

优化建议:任何业务都应该设置Bloomfilter,通常设置为row就可以,除非确认业务随机查询类型为row+cf,可以设置为rowcol

如何使用 Bloom Filter:https://www.cnblogs.com/uncledata/p/9950462.html
//Google Guava library为我们提供了Bloom Filter的实现,直接用就可以啦:com.google.common.hash.BloomFilter
代码部分实现

HDFS相关优化
(1)HDFS作为HBase最终数据存储系统,通常会使用三副本策略存储HBase数据文件以及日志文件。
(2)从HDFS的角度望上层看,HBase即是它的客户端,HBase通过调用它的客户端进行数据读写操作,因此HDFS的相关优化也会影响HBase的读写性能。这里主要关注如下三个方面:
1、 Short-Circuit Local Read功能是否开启?
(1)当前HDFS读取数据都需要经过DataNode,客户端会向DataNode发送读取数据的请求,DataNode接受到请求之后从硬盘中将文件读出来,再通过TPC发送给客户端。Short Circuit策略允许客户端绕过DataNode直接读取本地数据。(具体原理参考此处)
https://blog.cloudera.com/blog/2013/08/how-improved-short-circuit-local-reads-bring-better-performance-and-security-to-hadoop/

优化建议:开启Short Circuit Local Read功能,具体配置戳这里
https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-hdfs/ShortCircuitLocalReads.html

在cdh中配置如下
//启用 HDFS 快速读取
dfs.client.read.shortcircuit
启用 HDFS 快速读取。该选项允许与 DataNode 同地协作的客户端直接读取 HDFS 文件块,从而提升意识到本地化的分布式客户端的性能。

2、Hedged Read功能是否开启?
(1)HBase数据在HDFS中一般都会存储三份,而且优先会通过Short-Circuit Local Read功能尝试本地读。
(2)但是在某些特殊情况下,有可能会出现因为磁盘问题或者网络问题引起的短时间本地读取失败,为了应对这类问题,社区开发者提出了补偿重试机制 – Hedged Read。
//该机制基本工作原理为:客户端发起一个本地读,一旦一段时间之后还没有返回,客户端将会向其他DataNode发送相同数据的请求。哪一个请求先返回,另一个就会被丢弃。

优化建议:开启Hedged Read功能,具体配置参考这里 https://issues.apache.org/jira/browse/HDFS-5776
//这一部分在代码段实现

(3)数据本地率是否太低?
例子:
数据本地率:HDFS数据通常存储三份,假如当前RegionA处于Node1上,数据a写入的时候三副本为(Node1,Node2,Node3),数据b写入三副本是(Node1,Node4,Node5),数据c写入三副本(Node1,Node3,Node5),可以看出来所有数据写入本地Node1肯定会写一份,数据都在本地可以读到,因此数据本地率是100%。现在假设RegionA被迁移到了Node2上,只有数据a在该节点上,其他数据(b和c)读取只能远程跨节点读,本地率就为33%(假设a,b和c的数据大小相同)。

优化原理:数据本地率太低很显然会产生大量的跨网络IO请求,必然会导致读请求延迟较高,因此提高数据本地率可以有效优化随机读性能。数据本地率低的原因一般是因为Region迁移(自动balance开启、RegionServer宕机迁移、手动迁移等),因此一方面可以通过避免Region无故迁移来保持数据本地率,另一方面如果数据本地率很低,也可以通过执行major_compact提升数据本地率到100%。

优化建议:避免Region无故迁移,比如关闭自动balance、RS宕机及时拉起并迁回飘走的Region等;在业务低峰期执行major_compact提升数据本地率

参考链接:
HBase最佳实践-读性能优化策略 http://hbasefly.com/2016/11/11/hbase%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5%ef%bc%8d%e8%af%bb%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96%e7%ad%96%e7%95%a5/
如何使用 Bloom Filter:https://www.cnblogs.com/uncledata/p/9950462.html

猜你喜欢

转载自blog.51cto.com/12445535/2360206