背景:
线上通过webui监控发现,几乎所有的 regionserver 都宕机了,而且时间上是连续的。通过查看所有regionserver上的日志发现,有过 gc 时间超长的(20多秒),也有 zk 连接超时的,还有在 major compaction 时宕机的。到这就很为难了。
措施:
查看HBase现在状态以及配置,看看配置是否合理
发现整个集群30台左右rs,每台机器分配了 20G 内存,写缓存比是 0.4,读缓存比是 0.4,region大小是10g,major compact 是 7天自动执行,最大WAL 数未配置,即默认为32(32是一个策略算出来的,未配置就通过默认的策略算), 整个集群所有region数大概在10000 左右。
按照这种配置,每天集群写缓存只有8G。然后每台机器有大约300个region,活跃在用的region大概有270左右。也就是说每个region的 memstore 大小达到3M左右就需要flush,加上写入并发在十几万,推断是因为flush太过频繁,导致 minor compact 频繁。另外,region 大小只有10G,很容易达到分裂要求,也是对集群稳定性的一大考验。
初步解决方案:修改配置,重启集群。
读写缓存比调整,因为写需求大于读需求,因此读写分别调整为 0.3 和 0.5(两者之和不能超过0.8);
region 大小调整,10G 调整为 100G,降低 region 分裂频率;
禁止自动 major compact,设置为0即禁止。major 操作会使RS几乎不可用,禁止自动,需要周期手动
修改 maxLogs 大小,因为 region 数太多,WAL数量修改为64或128 (这次好像未改动)
修改完后进行重启。
该配置只是将未来的做了打算,比如 region不会再分裂,不会再自动 major ,等等,但是现有的问题还是存在,region数太多,导致 memStore 经常flush,RS压力还是很大。故还需要先进行region 合并操作,先将region数量减少一般再说。
合并操作代码如下:
1 | package hbase; |
合并后检查 region数,降低了一半。
然后重启写入任务,发现了另外一个问题,有一个region A 处于分裂状态,但是有数据需要写到那个region,然后异常了,一直写不进去,异常信息大概是定位到了写入的region,但是region正在分裂,需要等待…,谁知道等待了一天也不行,后面仔细想了想,正常的话,region的split应该是一个一两秒的过程,不至于会出现这个问题,那么这个region肯定不正常。后面去 hbase:meta表查看了一下该region的元数据信息,反正确实一直处于split 状态,并且两个子region的信息也有。然后分别去HDFS上查看父region和两个子region的数据信息,发现其中一个子region目录下还有父region的数据链接文件,另外一个region目录信息正常,但是元数据查不到该子region的信息,万万没想到这个坑了我一下(下线的region的元数据信息不会在meta表)。所以第一个神操作来了,把无元数据信息的region的目录删除。我以为该region已经没用了,所以执行 hbase hbck能检查出问题,没想到的是,问题出来了,不是父region的问题,是这个子region已经分裂,但是它分裂的子region还有数据链接文件(即数据未迁移),然后就报错了。接着赶紧把 子region 恢复,然后基本判断了。是另外一个子region子出了问题,但是其下又有新的数据文件,所以将 父region下的数据文件全部手动迁移至该region下,并且将对应的数据链接文件进行删除。然后再执行 hbck ,问题解决,写入异常也没了。
接着再看 写入不稳定问题,几乎每个十来分钟,消费写入程序都会进行 rebalance,苦不堪言。然后大概评估了一下原因,还是region太多,memstore不够用。但是再次合并发现,不能再合并了,想了想,合并和分裂应该是相反的操作,也不会立马迁移数据,需要时间。在这期间应该时不能再合并了(好像执行了major 也不管用,也不会立马迁移数据)。那么只能从kafka consumer端解决了。看代码发现,max.poll.interval.ms 这个参数仍然是默认的 300 s。看来就是这个了,因为写HBase会经常卡住一会,然后就把 这个值设置为 1小时了。通常情况下不建议设置这么大,都需要参考处理每批 poll 数据的时间来进行设置,稍长一点即可。但是因为现在经常抖动,也不知道具体的处理时间,因此直接设置为1小时。后果就是再次发生rebanlance时比较难办,因为rebanlance的超时时间其实好像也是这个值,所以,这个值设置千万要慎重。
当改为这一切之后,终于算是正常了。差不多没隔十来分钟左右会停止写入数据,然后程序等待,等待2-5分钟,恢复写入。最起码不会因为rebanlance而导致程序一直 rebanlance 了。