关于HBCK2的介绍,可以查看文章 hbck2工具使用指南这里不做太多赘述。
本系列文章主要结合线上HBase环境出现一系列问题,进行分析HBCK2工具中出现问题如何具体解决,以及其中的原理及实现进行分析。
背景介绍
我们在某项目上使用CDH版本的HBase2.1.0,某日忽然接到告警业务中断,HBase无法读写。具体原因大概是开发人员修改了个hdfs的配置,重启HDFS短期影响了业务,HDFS启动期间,又对HBase进行了重启,发生长时间不能读写了。
查看HDFS和HBase的服务状态都是正常的,HBase的HMaster和RegionServer都正常,打开HBase UI发现了1700多个Region卡在RIT的Opening状态,如下图:
查看HMaster日志出现大量日志:
[ProcExecTimeout] assignment.AssignmentManager: STUCK Region-In-Transition rit=OPENING, location=hadoop,16020,1534582878822, table=XXXXX, region=0f0f1b212133dd3640643471e5391bd
问题分析
1. RIT处理
此前在HBase1.x的时候出现这种情况直接使用hbase hbck -fix直接搞定,因为HBase2.0版本修改了Assignment Mananger2的实现方式,具体原理可以查看:
https://developer.aliyun.com/article/601096
AMV2的实现大概是优化了Region状态的缓存实现,HBase1.x版本的Master中RegionStates会保存Region的状态,Meta表中会保存region的状态,Zookeeper上也会保存region的状态,保持这三者完全同步是一件很困难的事情,因此在hbase1.x版本RIT是一种非常常见的异常,虽然大部分场景是可以通过hbase hbck修复,但还是存在非常多的bug导致无法修复。
HBase2.0版本引入了Procedure V2,所有的状态都可以持久化在Procedure中,Procedure中每次的状态变化,都能够持久化到ProcedureWAL中,因此数据不会丢失,宕机后也能恢复。同时,AMv2中region的状态扭转(OPENING,OPEN,CLOSING,CLOSE等)都会由Master记录在Meta表中,不需要Zookeeper做持久化。再者,之前的AM使用的Zookeeper watch机制通知master region状态的改变,而现在每当RegionServer Open或者close一个region后,都会直接发送RPC给master汇报,因此也不需要Zookeeper来做状态的通知。
如此看来HBase2.0版本应该很少出现RIT的问题才是,不过凡事总有例外,RIT卡在Opening状态的原因应该不是Master与meta表中状态不一致导致的,而是可能由其他原因引起。
仔细查看这些RIT的Region会发现这些assign的RegionServer与当前上线的RegionServer的时间戳并不一样,并且在RegionServer的下方出现了Dead Region Servers:
而RIT的Region所assign的RegionServer居然在Dead Region Server中,因此Region才会卡住无法上线。
由于还没来得及把社区的hbck2工具编译过来, 想到是通过hbase shell直接assign region进行解决,不过悲剧的是,assign的时候报错了“HMaster正在初始化”:
ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing
这个原因是因为刚好hbase:namespace表也没有上线导致,UI上所有表信息均无法看到,自然也就没办法重新assign了。
没办法只能编译hbck2工具了,好在使用的版本hbase2.1.0-cdh已经有对应的部分功能,包括region的assign。当时想着如果在hbase中执行assign不可用,用hbck2工具assign应该也不行,也是抱着试试看的态度尝试了下,hbck2的assign命令为:
hbase hbck -j hbck2.jar assign [RegionName]
结果还是好的,Region已经能上线了。于是把剩下的1000多Region全部assign了一遍,便都正常上线了。那么通过hbck2工具assign为何就能执行呢,原因待后续进行分析。
2. HBase UI上不显示表
界面上显示的所有RIT的Region都处理过,可是表在UI上仍然是看不到的,这个当时没有截图,大概就是现象就是TableDetails全部是空的,一张表都没有。
后来通过分析才发现是namespace表没上线导致的,并且hbase:namespace这张表没有在RIT列表,只好通过日志找到namespace表对应的region然后用hbck2工具assign一遍才进行解决。
3. Region分配不均
所有Region上线后,居然绝大部分Region都上线到其中一台RegionServer上,多次balancer后仍然无法均衡,其中RS1上上线了5000多个Region,其他RS上最多才一二百个。
这个问题百思不得其解,重启HBase也无济于事。又是折腾大半天,终于在RegionServer日志中发现了一些蛛丝马迹:
大概意思是hbase用户无法访问表Region目录下的.tmp文件夹。我们HDFS上是开了ACL权限的,其中HDFS是超级用户,.tmp目录是HDFS用户创建的,HBase无法访问。.tmp具体放啥东西得我没有查到,具体为啥是hdfs用户创建的就更不清楚了,只能推测大概影响了Region的balance。手动修改目录权限的话比较多,于是索性把HDFS的权限给关掉了。重启后Region果然能正常balancer了。
问题原因还待具体深究,不过值得思考的是,日志中每一个ERROR都不能放过,有时候就算想不清楚原因,解决了对应的ERROR,问题可能也就随之解决了。
4. RIT在Closing状态
因为在修改hdfs权限配置后,重启HDFS和Hbase。再次启动HBase后居然发现有Region卡在了RIT的closing阶段,这个过不去其他表的AssignProcedure都无法进行。
原因跟RIT的Opening差不多,同样是是在Dead RegionServer上进行的close,正常无法关掉。于是又进行了一系列的操作,包括用hbck2执行unassign和assign、删除MasterProcWALs下数据重启,都无法解决。
后来通过在WALs目录下创建一个Closing的RegionServer名对应的目录,启动的时候就会构造一个ServerCrashProcedure,尝试下能否正常关闭。
于是按照这种方式,确实会出现一个ServerCrashProcedure,但是仍然处理不掉。准备放弃的时候,再次执行hbase hbck2的assigns命令,居然这个卡住的Region可以上线了。
5. Region数过多
思考这次Region开始RIT的原因,我们猜想可能跟Region数量太多有关系。正常情况下HBase的一个RegionServer承载五六百个Region是没问题的(官网推荐20~200个,我们经验五六百是可以的),而线上的这个环境,单个RegionServer已经超过了1000多。HBase整个恢复后,便考虑减少集群Region数量,尤其是其中一张表Region已经达到1200多个。
实施人员在对Region进行Merge的时候,对不连续的Region做了强制的Merge,导致出现Region空间重叠出现很多region overlaps。
查看hbck2工具提供了fixMeta可以修复overlaps,悲催的是我们用的2.1.0版本上不支持,在2.1.6版本才有fixMeta操作。临时合入fixMeta肯定是来不及了,只能把hfile文件备出来,重新建表并预分区,然后再把hfile文件load回来。
总结
经过不断折腾,HBase总算恢复正常了。对一个Hbase小白来讲,初次在Hbase2.0版本上遇到那么多问题,实在是给吓坏了。通过这次经历,总算对Hbase2.0的基本运维有了浅显的认识,后续还需要通过源码阅读继续深入了解了。