HDFS HA的脑裂问题:IPC’s epoch [X] is less than the last promised epoch [X+1]

内容纲要

概要描述


Hadoop2.X提供了对HDFS的高可用实现,即两台Namenode做热备,保持元数据一致,通过ZK实现故障迁移。但在HA的具体实现中,有时会出现脑裂的问题。

详细说明


问题现象

Active NameNode出现异常,任务中断,NameNode日志中报错:IPC’s epoch [X] is less than the last promised epoch [X+1];
HDFS出现短期的双Active,后续自动恢复。

问题原因

该问题属于HDFS HA对于脑裂的异常保护;

脑裂,即在分布式系统中出现的双主现象,在实际中,NameNode 可能会出现这种情况,NameNode 在垃圾回收(GC)或网络通信异常的情况下,可能会在长时间内整个系统无响应,因此,也就无法向 ZK 写入心跳信息,这样的话可能会导致临时节点掉线,备 NameNode 会切换到 Active 状态,这种情况,可能会导致集群同时有两个 Active NameNode,出现冲突,且无法保证数据的一致性。

具体信息也可以参考hadoop官方文档

ZKFC日志如下:

2022-05-25 18:23:21,822 WARN org.apache.hadoop.ha.HealthMonitor: Transport-level exception trying to monitor health of NameNode at tg-namenode01/10.33.25.8:8020: java.net.ConnectException:Connection refused Call From tg-namenode01/10.33.25.8 to tg-namenode01/10.33.25.8:8020 failed on connection exception: java.net.ConnectException:Connection refused; For more details see: http://wiki.apache.org/hadoop/SocketTimeout
2022-05-25 18:25:12,825 WARN org.apache.hadoop.ha.FailoverController: Unable to gracefully make NameNode at tg-namenode02/10.33.25.9:8020 standby (unable to connect)
java.io.IOException: Failed on local exception:java.io.IOException: java.net.SocketTimeoutException: 5000 millis timeout while waiting for channel to be ready for read. ch : java.nio.channels.SocketChannel[connected local=/10.33.25.8:53810 remote=namenode02/10.33.25.9:8020]; For more details see:  http://wiki.apache.org/hadoop/SocketTimeout

Namenode报错:IPC’s epoch [X] is less than the last promised epoch [X+1],则是因为:

1、ZKFC对NameNode1(Active)进行健康检查,因为长时间监控不到NN1的回复,认为该NameNode1不健康,但是Active NameNode又没有挂(因为zkfc与NameNode1连接异常,不能将其shutdown);

2、ZKFC然后去选取StandbyNameNode为Active,同时会更新JN中的epoch使其+1;

3、原来的Active NameNode压力缓解了,发现自己不是主节点,再次去操作JournalNode的editlog时发现自己的epoch比JN的epoch小1,随即报错;

Namenode日志如下:

2022-05-25 18:20:57,666 WARN org.apache.hadoop.hdfs.qjournal.client.QuorumJournalManager: Remote jounal 10.33.25.9:8485 failed to write txns 2464561626-2464561626. Will try to write to this JN again after the next log roll.
org.apache.hadoop.ipc.RemoteException(java.io.IOException): IPC's epoch 29 is less than the last promised epoch 30

解决方案

关于这个问题,HDFS自带的解决方案是隔离(Fencing),主要是在以下三处采用隔离措施:

1、共享存储隔离:同一时间只允许一个Namenode向JournalNodes写入editlog数据。

2、客户端隔离:同一时间只允许一个Namenode响应客户端的请求。

3、Datanode隔离:同一时间只允许一个Namenode向Datanode下发名字节点指令,例如删除、复制数据块指令等等。

在进行 fencing 的时候,会执行以下的操作:

1、首先尝试调用这个旧 Active NameNode 的 HAServiceProtocol RPC 接口的 transitionToStandby 方法,看能不能把它转换为 Standby 状态;

2、如果 transitionToStandby 方法调用失败,那么就执行 Hadoop 配置文件之中预定义的隔离措施。

Hadoop 目前主要提供两种隔离措施:

sshfence:通过 SSH 登录到目标机器上,执行命令 fuser 将对应的进程杀死;

shellfence:执行一个用户自定义的 shell 脚本来将对应的进程隔离。

只有在成功地执行完成 fencing 之后,选主成功的 ActiveStandbyElector 才会回调 ZKFailoverController 的 becomeActive 方法将对应的 NameNode 转换为 Active 状态,开始对外提供服务。

目前TDH中采用的是shellfence机制,即执行shell 脚本来将对应的进程隔离。

这里的shell脚本定义在core-site.xml中:

file

在ZKFC日志中我们可以看到fencing的过程:

2022-05-25 19:02:19,936 INFO org.apache.hadoop.ha.NodeFencer: ====== Beginning Service Fencing Process… ======
2022-05-25 19:02:19,936 INFO org.apache.hadoop.ha.Nodefencer: Trying method 1/1: org.apache.hadoop.ha.ShellComnandFencer(/bin/true)
2022-05-25 19:02:10.939 INFO org.apache.hadoop.ha.ShellCommandFencer: Launched fencing command ‘/bin/true’ with pid 149
2022-05-25 19:02:19,946 INFO org.apache.hadoop.ha.Nodefencer: ====== Fencing Successful by method org.apache.hadoop.ha.ShellComnandFencer(/bin/true) ======
2022-05-25 19:02:10.947 INFO org.apache.hadoop.ha.ActiveStandbyElector: Writing Znode /hdfs1-ha/nameservice1/ActiveBreadCrumb to indicate that the local node is the most recent active..
2022-05-25 19:02:10.949 INFO org.apache.hadoop.ha.ZKFailoverController: Trying to make Namenode at tg-namenode1/10.33.25.8:8020 active… 
2022-05-25 19:02:28,844 INFO org.apache.hadoop.ha.ZKFailoverController: Successfullytransitioned NameNode at tg-namenode1/10.33.25.8:8020 to active state

file

后续排查思路及优化

脑裂发生通常是因为网络延迟、通信故障、或Namenode发生FGC等。所以在出现此类问题时,可以按照如下思路排查:

1、 检查网络通信,如节点间通信是否正常,端口是否开通,是否有丢包,SELINUX和防火墙是否关闭等;

2、 检查Namenode是否有CPU或内存不足的情况,导致rpc超时;

3、 检查Namenode是否压力过大,触发了FGC(比如小文件过多导致NN内存占用过多?);

4、 基于ZKFC在收到active Namenode端故障通知时,对于standby Namenode的状态切换存在超时时间, HealthMonitor都会定期的检查NameNode是否健康,当集群变大的时候,我们可以适当的设置这个监控的超时时间,让ZKFC的HealthMonitor没那么“敏感”。
涉及到的参数如下(定义在core-site.xml配置文件中):

HA功能的健康监控间隔时间,默认1000ms
ha.health-monitor.check-interval.ms = 2000

HA功能健康监控的超时时间,默认45000毫秒
ha.health-monitor.rpc-timeout.ms = 180000

弊端:会带来切换过程时间增长,Inceptor等依赖应用无响应甚至任务失败的。

这篇文章对您有帮助吗?

平均评分 0 / 5. 次数: 0

尚无评价,您可以第一个评哦!

非常抱歉,这篇文章对您没有帮助.

烦请您告诉我们您的建议与意见,以便我们改进,谢谢您。