462 forbidden region 怎么解决_一次HBase目录空间占用异常的解决之旅

一次HBase目录空间占用异常的解决之旅

1. 前言

在详细描述我们此次遇到的HBase的异常之前,先来简单介绍一下我们集群的概况。当前我们使用的HBase的版本是cdh6.3.2-hbase2.1.0,由主备双集群同时为线上提供服务,但正常情况下读写都集中在主集群,只有发生超时等异常时,熔断器才会把请求切换至备集群。主备集群之间通过replication机制同步数据,主备集群开启双向同步。主集群的节点数是5,备集群的节点数是4。集群的一些核心参数如下:

hbase.regionserver.maxlogs256
hbase.hregion.max.filesize 20G  
HBase RegionServer 的 Java 堆栈大小(字节) 32G(我们的物理机内存三百多G)  
hbase.bucketcache.size 24G  

我们遇到的异常是,主备集群HBase的相关目录数据量极不正常,如下图所示:主集群d19dece2f3671c6d72717191244c75c5.png备集群bbb408db9bcfb0cd3532318aa5e54df3.png初看这样的现象时,我们有点懵,集群中所有表的数据总和也才十几个T,但总的HBase目录竟占用了HDFS一百多T的资源。曾经也尝试过直接简单粗暴地直接移走这些目录中看似无用的数据,只保留/hbase/data目录下的文件,非常自然,集群会直接宕机、region丢失。

2. HBase的目录结构

在继续往下探讨之前,还是乖乖复习一下HBase各个目录的说明和作用,此处以我们当前使用的版本为例。hdfs dfs -ls /hbase 用于查看/hbase的目录结构,hdfs dfs -du -s -h /hbase/*用于查看/hbase/*各个目录占用的大小。一个看起来还挺正常的HBase的目录结构,如下图:286acd116f58adde785fd43fc749365a.png以下内容节选自范老师的《HBase 原理与实践》第三章第四小节,/hbase/.hbase-snapshot快照文件存储目录。用户执行snapshot后,相关的snapshot元数据文件存储在该目录。/hbase/.tmp临时文件目录,主要用于HBase表的创建和删除操作。表创建时候首先会在tmp目录下执行,执行成功后再将tmp目录下的表信息移动到实际表目录下。表删除操作会将表目录移动到tmp目录下,一定时间之后再将tmp目录下的文件真正删除。/hbase/MasterProcWALs存储Master Procedure过程中的WAL文件。Master Procedure功能主要用于可恢复的分布式DDL操作。在早期HBase版本中,分布式DDL操作一旦在执行到中间某个状态发生宕机等异常的情况是没有办法回滚的,这会导致集群元数据不一致。Master Procedure功能使用WAL记录DDL执行的中间状态,在异常发生之后可以通过WAL回放明确定位到中间状态状态点,继续执行后续操作以保证整个DDL操作的完整性。/hbase/WALs存储集群中所有RegionServer的HLog日志文件。对于每一个RegionServer,日志目录中都包含一个子目录。客户端写数据到集群时,如果没有绕过写WALs,则数据先追加写入WALs LOG,再写入缓存,触发Flush之后,数据才会落盘,落盘之后这一部分WALs会标记过期,然后被删除。如果集群发生意外宕机,缓存中的数据丢失,重启后回放WALs,才能保证数据完整。/hbase/archive文件归档目录。这个目录主要用于以下几个场景

  • 所有对HFile文件的删除操作都会将待删除文件临时放在该目录。

  • 进行Snapshot或者升级时使用到的归档目录。

  • Compaction 删除HFile的时候,也会把旧的HFile移动到这里。

/hbase/corrupt存储损坏的HLog文件或者HFile文件。/hbase/data存储集群中所有Region的HFile数据。HFile文件在data目录下的完整路径如下所示:/hbase/data/namespace/tablename/f569a17359edb2250cdf07964be606a7(由region的表名+Start Key+时间戳产生的hashcode)/family/文件名除此之外,data目录下还存储了一些重要的子目录和子文件。

  • .tabledesc:表描述文件,记录对应表的基本schema信息。

  • .tmp:临时目录,主要用来存储Flush和Compaction过程中的中间结果。以flush为例,MemStore中的KV数据落盘形成HFile首先会生成.tmp目录下,一旦完成再从.tmp目录移动到对应的实际文件目录。

  • .regioninfo:Region描述文件。

  • recovered.edits:存储故障恢复时该Region需要回放的WAL日志数据。RegionServer宕机之后,该节点上还没有来得及flush到磁盘的数据需要通过WAL回放恢复,WAL文件首先需要按照Region切分,每个Region拥有对应的WAL数据片段,回放时只需要回放自己的WAL数据片段即可。

/hbase/hbase.id集群启动初始化时,创建的集群唯一id。/hbase/hbase.versionHBase软件版本文件,代码静态版本。/hbase/oldWALsWAL归档目录。一旦一个WAL文件中记录的所有KV数据确认已经从MemStore持久化到HFile,那么该WAL文件就会被移到该目录。

3. 异常排查

出现这样异常的开始时间点是之前的一次异常scan导致集群宕机,然后经过了多次惊魂重启之后,WALs、archive、oldWALs目录就越来越膨胀,不会自己释放空间了。直到现在,我们也只是知道HBase目录占用异常,跟上几次的重启有关,但其根本原因究竟是什么,依旧不知道哇。该怎么解决呢,首先来分析下主集群的目录。HBase主集群的WALs和archive俩目录占用空间贼大,先来看一下WALs目录长啥样,b885248a1e8974e0af7093c78394df9b.pngWALs目录下多了很多-splitting后缀的文件夹,且其文件名中的时间戳全是2020-05-22那天(惊魂重启的日子)再下一级目录中的文件呢,文件名中的时间戳也是那天,过期了这么久的数据没有被及时清除,一时间也想不明白这是为啥。数据没被删除,一定是哪里有引用。HBase依靠zookeeper来保持状态(姑且这样理解),所以理所当然,我们首先需要排查下zookeeper中HBase的目录,因为可能一些过期的ZK的状态清除时出现异常,没有及时清理,存在引用,导致HBase的一些文件也没有及时被清理,所以空间占用居高不下。[meta-region-server, replication, rs, backup-masters, splitWAL, table-lock, flush-table-proc, master-maintenance, online-snapshot, switch, master, running, balancer, draining, namespace, hbaseid, table]Zookeeper上这么多的目录,还真不知道该怎么看,那怎么办!只能一个一个ls看一下,再加上望文生义,大胆猜测。划重点了,zk中splitWAL这个path看着貌似跟WALs这个目录有关系呀!ls 一下,是空的!别的地方也没有找到类似相关的信息。说到这里,需要插入一个之前我们重启集群时遇到的异常。

3.1 一次诡异的HBase重启异常

当时我们在重启集群的过程中,发现Master的进程频繁退出,其日志输出如下:9f31b288487f266e84d4d62d926291db.png大概意思就是,znode /hbase/splitWAL 不可以被list,咦,这是啥意思,那我手动zk Shell下ls一下试试,果然,报错:

2017-02-20 12:08:03,999 [myid:] - WARN  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1102] - Session 0x1591b713cefd2b3 for server localhost/127.0.0.1:2181, unexpected error, closing socket connection and attempting reconnect
java.io.IOException: Packet len8854970 is out of range!
at org.apache.zookeeper.ClientCnxnSocket.readLength(ClientCnxnSocket.java:112)
at org.apache.zookeeper.ClientCnxnSocketNIO.doIO(ClientCnxnSocketNIO.java:79)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:366)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081)
WATCHER::
此处省略若干字

关键的报错点是:java.io.IOException: Packet len8854970 is out of range!就是这个znode下面的数据太多了,没办法查看。那咋整,谷歌一波,有现成的解决方案。

vim /opt/cloudera/parcels/CDH/lib/zookeeper/bin/zkCli.sh# 这是之前的#$JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \#     -cp "$CLASSPATH" $CLIENT_JVMFLAGS $JVMFLAGS \#     org.apache.zookeeper.ZooKeeperMain "$@"# 修改下 增加这个配置 -Djute.maxbuffer=41943040"$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \"-Djute.maxbuffer=41943040" \
-cp "$CLASSPATH" $CLIENT_JVMFLAGS $JVMFLAGS \
org.apache.zookeeper.ZooKeeperMain "$@"

修改完配置之后,就可以正常在zk Shell下查看这个znode了,ls一下,呼啦啦打出来一大堆文件名,指向的就是WALs splitting为后缀的文件。没有时间细想这些文件究竟有啥用,只知道它影响集群的启动,但凡有一点办法,也不会直接删除znode/hbase/splitWAL 。删除完这个znode之后,集群顺利启动了。

3.2 隐患解除

这次的目录隐患就是上次异常重启之后埋下的坑,结合这个启动异常来看,WALs的-splitting的文件夹信息原先在ZK中存在,不是由HBase自动删除,而是被我们手动删除的,所以这些文件一直存在HBase的目录中。那么,既然znode早就被干掉了,这些文件还留着干啥。这些-splitting后缀的文件被移走后,就能彻底解决WALs的目录占用问题嘛?再来看一下正常WALs的目录大小,也有好几个T,正常文件夹中的HLog也没有及时被清理。随便打开一个正常的WALs的目录,查看前几个文件hdfs dfs -ls /|head -10(后几个文件中的时间戳肯定是最近时间产生的)。果然,前几个文件中的时间戳有2020-05-22的,WALs大概从那个时间点开始就一直没被释放。WALs还跟什么有关呢?主备同步,主集群的写入请求会实时同步到备集群,设想一种场景,机器重启的过程中发生异常,replication异常或者后续replication的队列持续积压,那么主集群的WALs目录是不是一直不会被释放。HBase集群的replication的状态保持也依赖于zookeeper,所以,我们还得来看zookeeper的znode——replication。ls /hbase/replication/peers正常情况下该node路径下存储的是你的peer ID,我们集群只有一个peer,且ID为1,那么这个node下面就是1。但此时,这个路径下除了1之外,还有额外的路径。ls /hbase/replication/rs再查看下这些目录,也会找到一些异常文件的引用。这些路径的名字联系HBase WALs中过期的文件来看,被互相引用,一切貌似都能解释通了。主备同步发生了异常或积压,WALs目录中的HLog一直被ZK引用,其状态一直得不到更新,所以文件一直存在,并越积越多。我们的解决办法是,重建peer,尽量不要手动删,要让HBase自动清理这些过期的数据。

disable_peer "1"
remove_peer "1"
add_peer '1', CLUSTER_KEY => "ip1:2181,ip2:2181,ip3:2181:/hbase", SERIAL => true

静候片刻,你会发现WALs的目录被移到oldWALs目录下了,-splitting目录大小总和+oldWALs刚放进来的文件=之前WALs的目录大小。再等一会,oldWALs目录也慢慢变小。继续看archive目录,其实archive目录这么大,我们的第一时间反应也是跟集群快照有关,因为之前集群迁移时,对所有的表都进行过快照备份,且已经存在了好几个月,好几个月前的快照未删,这个目录中的旧数据肯定把这个空间撑了起来。相似的场景其实我们之前也遇到过,但之前清空所有快照后,收效甚微。但这次清空完所有快照之后,这个目录确实瘦身明显。主集群目录占用隐患顺利解决,沿着这个思路,备集群的隐患也顺势而解。重建peer,慢慢恢复正常。

4. 总结下吧

通过熟悉HBase各个目录的作用,联系之前的事故,结合Zookeeper异常目录的排查,帮助我们解决了HBase的目录隐患,操作前后集群的数据没有明显变化(region数)。但是,问题发生的根本原因,我们依旧没有捕捉到,-spliting目录到底是干啥的?-spliting目录直接删除是否会造成数据丢失?依靠peer重建来解决replication的问题,是否会造成主备集群不一致呢?(十有八九会不一致,后续可以重新同步下数据)对HBase的掌握依旧仅限于冰山一角,学习之路漫漫,心存敬畏之心。

5. 参考链接

  • https://blog.bcmeng.com/post/hbase-hdfs.html

  • HBase原理与实践

据说,关注我的人都找到了对象👇

3f4a48c67653bca2106e0bfd5abecf26.png c992904367d9c536b78e837dc556217c.png 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值