在用arthas神器来诊断hbase异常进程这篇文章中,我详细地记录了一起生产环境中使用HBase的事故,事故发生的大致起因是,一个异常scan导致CPU使用率飙升至百分之百,且巨高不下,从而导致整个集群宕机。
虽然,借助于arthas这个神器,我们很轻易地就定位到了是scan的问题。而且事后,我们在业务层面上也采取了很多的优化手段。但是对于这个罪魁祸首,却一直没有找到一个完美的解决方案,总不能让业务那边一用scan就战战兢兢,如履薄冰吧。
在上篇文章的最后,靠着匮乏的多线程功底,对于scan这个问题,我写了写自己的看法。
事故发生的最本质的原因是scan的线程持续地占用着CPU的资源,且不会被释放,我们在业务日志中甚至能看到,某些scan能持续几个小时,这就太令人匪夷所思了。
原因渐渐明晰,就可以对症下药了。HBase提供了几个请求队列相关的核心参数,主要用于设置读写线程配比和进行读写队列隔离,以及get和scan的队列隔离。初看这些个参数的解释,还真搞不明白其中,队列、队列隔离的概念是什么。
在没有看源码之前,我简单地以为HBase服务端处理客户端的读写请求的时候,就是两个线程池,分别处理读和写的请求。甚至,如果你不做读写隔离的话,那就是一个线程池,一个线程是处理所有的读写请求;如果设置了读写隔离,就是两个线程池分别工作;如果进一步设置了get和scan的隔离,那么,就是三个线程池。这三个线程池,分别处理写请求,get请求,scan请求。每种请求所占的线程池资源肯定是不一样的,例如:scan比较耗时,那么,就应该控制其核心线程数的大小,如果此类值设置的过大,耗时的scan请求肯定会占用大量CPU,尤其是发生全表扫描的情况。
在看了源码之后,虽然HBase server端用的不是线程池,但也差不多,反正用的是线程,