一、背景
公司一个比较火的app量级上来了,需要接入推荐和搜索功能,为了快速提供支持,我们把用户、物品的特征直接用hbase存储,而没有接入到基于redis的特征平台(来不及改造)。上线一段时间之后,hbase突然报了慢请求(>400ms),我们介入排查...
- 涉及到3张表,A,B,C,只有A表数据量大小超过2G,B、C 2张表只有几M而已。情景:1次用户请求查询,A表1次get,B、C表1次200个id的批量rowkey查询(mget)。
- hbase集群总共10台机,10个regionserver,监控大盘看请求handler、queue等都比较正常(此时忽略了Read Request较大,埋下伏笔)。由于某些原因,监控无法准确看到每个regionserver的GC STW情况。我们怀疑是mget场景,有个别regionserver STW导致整体请求慢。
附一张hbase get请求架构图:
注:client从缓存获取到table对应的regionserver列表之后,执行mget请求,如果查询的数据没有全部在block cache(我们是bucket cache)和memcache命中,则会去磁盘查找(HFileBlockIndex索引查找最多3次IO,有可能没有IO,总之还算快)。
二、行动&故障
为了验证是某个regionserver gc STW引起慢请求的猜想,我们手动merge B、C表的10个region到2个(即落在2个regionserver),因为B、C两个表数据量很小,却未留意Read Request这个指标。merge操作执行完后不久,某个regionserver请求量暴增,之前9/10流量跑到这里,约1分钟1000多W Read Request(20W QPS),接着STW居高不下,jstat观察,所有时间都在young gc,JVM无法处理用户请求,JVM瘫痪。
接着服务大面积出现cat报警,好在服务我们都做了熔断,不会直接影响用户访问。
三、处理&总结
我们留意到merge后的regionserver QPS暴增,自动熔断后,我们接着快速重启regionserver,并重新split到10个regionserver分担请求,同时增加redis缓存(后续使用RocksDB封装的本地化存储)。
原因:只考虑表数据量小,就觉得merge region影响不大,实际上几M的hbase表,请求量有20W QPS,大量请求导致regionserver持续young gc,无法处理用户请求。
解决:使用“本地化”存储,将RocksDB作为kv引擎,load hive数据到本地查询,替换查询hbase。
反思:
- hbase region不能随意merge,如果要merge,需要考虑table数据量大的同时,还要考虑读写QPS大的问题。
- hbase虽然是比较好的大数据DB,但QPS非常大的时候,还是要做缓存。hbase write性能>read性能,很可能要走磁盘查找,尤其mget和scan操作,虽然有缓存和索引,查找也不像hbase纯内存读那么快。