IT技术博客大学习 共学习 共进步

Pora2应用中HBase高并发读写性能优化

搜索技术博客-淘宝 2014-12-03 23:58:46 浏览 2,121 次

   淘宝搜索的个性化离线实时分析系统Pora已升级至Pora2,Pora2是在基于Yarn的流式计算框架IStream基础上开发的,同时为保证数据和消息的实时处理系统中较多地使用了HBase,是一个典型的高并发读写HBase的分布式应用。

   系统在发布之初遇到了比较严重的性能问题,表现为处理速度跟不上实时日志,并且整个Hadoop/HBase集群压力大,连带其它应用受影响。经过排查发现问题主要都出现在了对HBase的使用上,现将遇到的几个典型的使用HBase的问题总结如下,希望能为其它类似应用正确使用HBase提供参考。

   HBase的Periodic Flusher

   从系统的各种统计指标分析,系统主要慢在了读写HBase的环节,观察HBase日志发现每个RegionServer都在频繁地flush和compact。分析后发现当前hbase版本里有一个Periodic Flusher的机制,memstore中的数据如果持续一段时间没有flush的话hbase会自动触发flush,这个时间间隔默认是1小时。了解了一下这是hbase 0.94.8以后引入的新feature,初衷是防止有些memstore长时间不flush,在没有开启wal且遇到region server挂掉时导致数据丢失。

   由于我们的 hbase每个region server有将近100个region,几乎每分钟都有region因为达到一小时的时间间隔触发flush,而多数情况下每次flush的文件都很小,flush次数多了之后又会引起compaction,如此频繁的flush和compaction使得region server处理速度明显变慢。在我们将这个配置调整为10小时后,可以从下图中看到hbase flush queue size和fs pread latency都有明显变小。

   altalt

   注:个人觉得hbase的这个新feature应用场景很有限,实在不应该作为一个默认开启的配置,建议可以通过配置直接禁用。

   不间断的频繁scan对region server造成较大压力

   Pora2采用了一个基于HBase实现的消息队列Hqueue,下游使用方通过读这个消息队列,第一时间获取最新的消息进行处理。

   读消息的过程相当于一次Scan,在一开始的Pora2版本中我们未对读Hqueue的频率进行控制,导致某些读HQueue的worker不停地发起新的Scan,即便Hqueue数据已经读完,仍会立刻重新创建Scan,而这个Scan会因为读不到数据很快结束之后又重新创建。这样不停地新建Scanner对Region Server端构成了不小的且是不必要的压力。

   发现这个问题后我们修改了这部分程序代码,在读完数据后sleep几秒后再重新scan。

   在修改完hbase的配置并且加上读Hqueue的scan频率控制后,Pora2情况明显好转,但处理累积数据时的速度还是不够快。

   超大并发下的hbase问题

   从统计指标上分析,系统还是慢在访问hbase上,访问hbase的日志中不时出现各种TimeOutException也可以说明这一点。跟踪日志中某些频繁报超时的regionserver发现,有些region server日志持续报以下异常:

   alt

   所在机器连接数很多,但load很低,而一旦pora2停了,这些现象就会很快消失。

   从这一现象分析判断是Pora2对HBase的并发连接数太多了,使得region server的handler不够用,server端还没来得及处理请求,client端已经到了超时时间而断开。

   为此我们大幅度减少了访问hbase的进程数以减少对hbase的并发连接,为了不降低处理能力,在进程内部使用更多的处理线程。由于线程间是共享对hbase的连接的,所以增加线程数不会增加对hbase的连接数。

   通过这一调整,很大程度缓解了hbase region server的压力。

   避免HBase访问热点

   在作了较多优化改进后发现仍有几个worker比较慢,跟踪那几个慢的worker日志发现读HBase经常超时,找到超时的region server,从HMaster UI上观察到这个server的读写请求数明显是其它server的好几倍。开始怀疑是数据有倾斜,有热点region落到了这台机器上。在HBase UI上逐个检查Pora2用到的HBase表,果然在其中的一张表上发现它的第一个region的请求数比其它region高出一两个数量级。

   按我们的设计预期,这个表的rowkey是加了hash前缀的,理论上不该有热点region,最终检查代码后才发现是生成rowkey的代码存在bug,生成前缀的代码用了 key.hashCode() % regionNum,结果有很多key的hashcode返回是负数,使得很多前缀是负数,全都落在了第一个region上。

   而对hbase来说,一旦有一个region有热点,就会导致该region所在的region server变慢,进而使得这个server上其它表的region访问也慢,从而影响了整个hbase的性能。

   Bulk load数据的Major Compaction

   调查中还发现了一个Bulk load数据未执行Major Compaction引起的问题。

   我们有一张表的数据是每天定时从HDFS中Bulk load到HBase里的,而且这张表的数据是只读的。结果几天下来后,因为没有数据写入,不会触发任何compaction,而每天都有新的HFile被Load进来,导致每个region下的HFile数越来越多,最终拖慢了这张表的读取性能。

   发现问题后我们在每天的Bulk load结束后对这个表执行一次Major Compaction,有效解决了问题。

   总结

   高并发读写HBase的应用需要尽量保证对HBase的合理使用,不合理的使用有可能会导致某一个region server甚至整个hbase集群的性能出现问题,而hbase的性能问题又反过来使得所有应用性能下降,此时如果应用选择继续加大对hbase的并发访问,甚至有可能因此陷入一个性能继续变差的恶性循环。

建议继续学习

  1. HBase集群出现NotServingRegionException问题的排查及解决方法 (阅读 17,120)
  2. HFile存储格式 (阅读 15,820)
  3. hbase运维 (阅读 14,780)
  4. hbase介绍 (阅读 12,222)
  5. HBase技术介绍 (阅读 7,941)
  6. HBase随机写以及随机读性能测试 (阅读 7,420)
  7. HBase性能优化方法总结 (阅读 6,940)
  8. HBase二级索引与Join (阅读 6,860)
  9. HBase Thrift 接口使用注意事项 (阅读 6,600)
  10. Cassandra和HBase主要设计思路对比 (阅读 4,942)