HBase最佳实践-写性能优化策略

本篇文章来讲道说道如何诊断HBase写数据的异常问题以及优化写性能。和读相比,HBase写数据流程却是显得很简单:数据先顺序写入HLog,再写入对应的缓存Memstore,当Memstore中数据大小达到必定阈值(128M)以后,系统会异步将Memstore中数据flush到HDFS造成小文件。java

开发者盛宴来袭!7月28日51CTO首届开发者大赛决赛带来技术创新分享

本篇文章来讲道说道如何诊断HBase写数据的异常问题以及优化写性能。和读相比,HBase写数据流程却是显得很简单:数据先顺序写入HLog,再写入对应的缓存Memstore,当Memstore中数据大小达到必定阈值(128M)以后,系统会异步将Memstore中数据flush到HDFS造成小文件。算法

HBase数据写入一般会遇到两类问题,一类是写性能较差,另外一类是数据根本写不进去。这两类问题的切入点也不尽相同,以下图所示:apache

写性能优化切入点缓存

1. 是否须要写WAL?WAL是否须要同步写入?性能优化

优化原理:数据写入流程能够理解为一次顺序写WAL+一次写缓存,一般状况下写缓存延迟很低,所以提高写性能就只能从WAL入手。WAL机制一方面是为了确保数据即便写入缓存丢失也能够恢复,另外一方面是为了集群之间异步复制。默认WAL机制开启且使用同步机制写入WAL。首先考虑业务是否须要写WAL,一般状况下大多数业务都会开启WAL机制(默认),可是对于部分业务可能并不特别关心异常状况下部分数据的丢失,而更关心数据写入吞吐量,好比某些推荐业务,这类业务即便丢失一部分用户行为数据可能对推荐结果并不构成很大影响,可是对于写入吞吐量要求很高,不能形成数据队列阻塞。这种场景下能够考虑关闭WAL写入,写入吞吐量能够提高2x~3x。退而求其次,有些业务不能接受不写WAL,但能够接受WAL异步写入,也是能够考虑优化的,一般也会带来1x~2x的性能提高。服务器

优化推荐:根据业务关注点在WAL机制与写入吞吐量之间作出选择并发

其余注意点:对于使用Increment操做的业务,WAL能够设置关闭,也能够设置异步写入,方法同Put相似。相信大多数Increment操做业务对WAL可能都不是那么敏感~异步

2. Put是否能够同步批量提交?分布式

优化原理:HBase分别提供了单条put以及批量put的API接口,使用批量put接口能够减小客户端到RegionServer之间的RPC链接数,提升写入性能。另外须要注意的是,批量put请求要么所有成功返回,要么抛出异常。性能

优化建议:使用批量put进行写入请求

3. Put是否能够异步批量提交?

优化原理:业务若是能够接受异常状况下少许数据丢失的话,还可使用异步批量提交的方式提交请求。提交分为两阶段执行:用户提交写请求以后,数据会写入客户端缓存,并返回用户写入成功;当客户端缓存达到阈值(默认2M)以后批量提交给RegionServer。须要注意的是,在某些状况下客户端异常的状况下缓存数据有可能丢失。

优化建议:在业务能够接受的状况下开启异步批量提交

使用方式:setAutoFlush(false)

4. Region是否太少?

优化原理:当前集群中表的Region个数若是小于RegionServer个数,即Num(Region of Table) < Num(RegionServer),能够考虑切分Region并尽量分布到不一样RegionServer来提升系统请求并发度,若是Num(Region of Table) > Num(RegionServer),再增长Region个数效果并不明显。

优化建议:在Num(Region of Table) < Num(RegionServer)的场景下切分部分请求负载高的Region并迁移到其余RegionServer;

5. 写入请求是否不均衡?

优化原理:另外一个须要考虑的问题是写入请求是否均衡,若是不均衡,一方面会致使系统并发度较低,另外一方面也有可能形成部分节点负载很高,进而影响其余业务。分布式系统中特别惧怕一个节点负载很高的状况,一个节点负载很高可能会拖慢整个集群,这是由于不少业务会使用Mutli批量提交读写请求,一旦其中一部分请求落到该节点没法获得及时响应,就会致使整个批量请求超时。所以不怕节点宕掉,就怕节点奄奄一息!

优化建议:检查RowKey设计以及预分区策略,保证写入请求均衡。

6. 写入KeyValue数据是否太大?

KeyValue大小对写入性能的影响巨大,一旦遇到写入性能比较差的状况,须要考虑是否因为写入KeyValue数据太大致使。KeyValue大小对写入性能影响曲线图以下:

图中横坐标是写入的一行数据(每行数据10列)大小,左纵坐标是写入吞吐量,右坐标是写入平均延迟(ms)。能够看出随着单行数据大小不断变大,写入吞吐量急剧降低,写入延迟在100K以后急剧增大。

说到这里,有必要和你们分享两起在生产线环境由于业务KeyValue较大致使的严重问题,一块儿是由于大字段业务写入致使其余业务吞吐量急剧降低,另外一起是由于大字段业务scan致使RegionServer宕机。

案件一:大字段写入致使其余业务吞吐量急剧降低

部分业务反馈集群写入突然变慢、数据开始堆积的状况,查看集群表级别的数据读写QPS监控,发现问题的第一个关键点:业务A开始写入以后整个集群其余部分业务写入QPS都几乎断崖式下跌,初步怀疑黑手就是业务A。

下图是当时业务A的写入QPS(过后发现脑残忘了截取其余表QPS断崖式下跌的惨象),可是第一感受是QPS并不高啊,凭什么去影响别人!

因而就继续查看其余监控信息,首先确认系统资源(主要是IO)并无到达瓶颈,其次确认了写入的均衡性,直至看到下图,才追踪到影响其余业务写入的第二个关键点:RegionServer的handler(配置150)被残暴耗尽:

对比上面两张图,是否是发现出奇的一致,那就能够基本确认是因为该业务写入致使这台RegionServer的handler被耗尽,进而其余业务拿不到handler,天然写不进去。那问题来了,为何会这样?正常状况下handler在处理完客户端请求以后会立马释放,惟一的解释是这些请求的延迟实在太大。

试想,咱们去汉堡店排队买汉堡,有150个窗口服务,正常状况下你们买一个很快,这样150个窗口可能只须要50个服务。假设突然来了一批大汉,要定制超大汉堡,好了,全部的窗口都工做起来,并且由于大汉堡很差制做致使服务很慢,这样必然会致使其余排队的用户长时间等待,直至超时。

可回头一想这但是写请求啊,怎么会有这么大的请求延迟!和业务方沟通以后确认该表主要存储语料库文档信息,都是平均100K左右的数据,是否是已经猜到告终果,没错,就是由于这个业务KeyValue太大致使。KeyValue太大会致使HLog文件写入频繁切换、flush以及compaction频繁触发,写入性能急剧降低。

目前针对这种较大KeyValue写入性能较差的问题尚未直接的解决方案,好在社区已经意识到这个问题,在接下来即将发布的下一个大版本HBase 2.0.0版本会针对该问题进行深刻优化,详见 HBase MOB ,优化后用户使用HBase存储文档、图片等二进制数据都会有极佳的性能体验。

案件二:大字段scan致使RegionServer宕机

案件现场:有段时间有个0.98集群的RegionServer常常频繁宕机,查看日志是因为”java.lang.OutOfMemoryError: Requested array size exceeds VM limit”,以下图所示:

缘由分析:经过查看源码以及相关文档,确认该异常发生在scan结果数据回传给客户端时因为数据量太大致使申请的array大小超过JVM规定的最大值( Interge.Max_Value-2)。形成该异常的两种最多见缘由分别是:

表列太宽(几十万列或者上百万列),而且scan返回没有对列数量作任何限制,致使一行数据就可能由于包含大量列而数据超过array大小阈值

KeyValue太大,而且scan返回没有对返回结果大小作任何限制,致使返回数据结果大小超过array大小阈值

有的童鞋就要提问啦,说若是已经对返回结果大小作了限制,在表列太宽的状况下是否是就能够不对列数量作限制呢。这里须要澄清一下,若是不对列数据作限制,数据老是一行一行返回的,即便一行数据大小大于设置的返回结果限制大小,也会返回完整的一行数据。在这种状况下,若是这一行数据已经超过array大小阈值,也会触发OOM异常。

解决方案:目前针对该异常有两种解决方案,其一是升级集群到1.0,问题都解决了。其二是要求客户端访问的时候对返回结果大小作限制(scan.setMaxResultSize(2*1024*1024))、而且对列数量作限制(scan.setBatch(100)),固然,0.98.13版本之后也能够对返回结果大小在服务器端进行限制,设置参数hbase.server.scanner.max.result.size便可

写异常问题检查点

上述几点主要针对写性能优化进行了介绍,除此以外,在一些状况下还会出现写异常,一旦发生须要考虑下面两种状况(GC引发的不作介绍):

Memstore设置是否会触发Region级别或者RegionServer级别flush操做?

问题解析:以RegionServer级别flush进行解析,HBase设定一旦整个RegionServer上全部Memstore占用内存大小总和大于配置文件中upperlimit时,系统就会执行RegionServer级别flush,flush算法会首先按照Region大小进行排序,再按照该顺序依次进行flush,直至总Memstore大小低至lowerlimit。这种flush一般会block较长时间,在日志中会发现“ Memstore is above high water mark and block 7452 ms”,表示此次flush将会阻塞7s左右。

问题检查点:

Region规模与Memstore总大小设置是否合理?若是RegionServer上Region较多,而Memstore总大小设置的很小(JVM设置较小或者upper.limit设置较小),就会触发RegionServer级别flush。集群规划相关内容能够参考文章《》

列族是否设置过多,一般状况下表列族建议设置在1~3个之间,最好一个。若是设置过多,会致使一个Region中包含不少Memstore,致使更容易触到高水位upperlimit

Store中HFile数量是否大于配置参数blockingStoreFile?

问题解析:对于数据写入很快的集群,还须要特别关注一个参数:hbase.hstore.blockingStoreFiles,此参数表示若是当前hstore中文件数大于该值,系统将会强制执行compaction操做进行文件合并,合并的过程会阻塞整个hstore的写入。一般状况下该场景发生在数据写入很快的状况下,在日志中能够发现” Waited 3722ms on a compaction to clean up ‘too many store files “

问题检查点:

参数设置是否合理? hbase.hstore.compactionThreshold表示启动compaction的最低阈值,该值不能太大,不然会积累太多文件,通常建议设置为5~8左右。 hbase.hstore.blockingStoreFiles默认设置为7,能够适当调大一些。

写性能还能再提升么?

上文已经从写性能优化以及写异常诊断两个方面对HBase中数据写入可能的问题进行了详细的解释,相信在0.98版本的基础上对写入来讲已是最好的解决方案了。可是有些业务可能依然以为不够快,毕竟”更快”是全部存储系统活着的动力,那还有提升空间吗?固然,接下来简单介绍HBase以后版本对写性能优化的两点核心改进:

Utilize Flash storage for WAL(HBASE-12848)

这个特性意味着能够将WAL单独置于SSD上,这样即便在默认状况下(WALSync),写性能也会有很大的提高。须要注意的是,该特性创建在HDFS 2.6.0+的基础上,HDFS之前版本不支持该特性。具体能够参考官方jira: https://issues.apache.org/jira/browse/HBASE-12848

Multiple WALs(HBASE-14457)

该特性也是对WAL进行改造,当前WAL设计为一个RegionServer上全部Region共享一个WAL,能够想象在写入吞吐量较高的时候必然存在资源竞争,下降总体性能。针对这个问题,社区小伙伴(阿里巴巴大神)提出Multiple WALs机制,管理员能够为每一个Namespace下的全部表设置一个共享WAL,经过这种方式,写性能大约能够提高20%~40%左右。具体能够参考官方jira: https://issues.apache.org/jira/browse/HBASE-14457

好了,这篇文章和你们一块儿分享了我的对HBase写入性能优化以及写入异常问题的一些理解,若有纰漏,还望指正!另外,若是你们有任何关于此话题的案例也很欢迎一块儿讨论~

相关文章
相关标签/搜索