故障经过
晚上8点多突然发现flink任务大面积挂掉重启的告警,然后打开 yarn-ui进行查看发现 ui也挂了
根据情况以及日志,初步判定RM挂了,然后查看RM 日志,发现ZK连不上,怀疑ZK有问题, 然后又登录ZK集群,查看ZK日志
##ZK日志
为了尽快恢复故障,减少故障时间,决定重启RM,但是启动失败,感觉RM启动HANG住了,仍然不可用,日志如下
发现ZK链不上,那回头看ZK,首先也是开启了重启大发,将ZK重启了一下,根据日志发现ZK正常启动,但是 仍然发现RM链不上ZK,
这时候开始手动执行zk-client去链接,链接是正常的,然后神奇的事情发生了,执行ls命令时,直接OOM异常。。。
卧槽,这到底时为什么,一脸懵逼,不过问题大概就在这了,内存不够,就先加内存起来再说,直接改ZK启动内存,然后重启
然后再用zk-client链接,再执行ls命令,OK 正常了,狂喜,以为这下搞定了
然后去重启RM,悲剧发生了,RM一直卡在那里,也不报错,就是起不来~~~
他到底在干嘛呢???为了搞清楚这个问题,我们开始jstack RM,然后发现了这个
他卡在了,加载RMState, 到底这个东西有多大,我们查看了集群配置RMState 是 存放在 zk 中的,我们又看了一下zk的监控,然后惊呆了,ZK的节点总数80万个,,,大部分都是RMSTATE下的。。。
现在终于搞明白,他为什么卡住起来不了。如果等他加载完毕,估计几个小时又过去了,为了快速恢复我们改为启动不加载,修改集群配置
yarn.resourcemanager.recovery.enabled: false
然后将RMSTATE从存储在ZK上改为存储在HDFS上,修改配置
yarn.resourcemanager.store.class
org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore(原来配置)org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore(修改后的配置)
再追加一个新配置
yarn.resourcemanager.fs.state-store.uri: /yarn/system/rmstor
然后重新RM, 集群恢复正常,
最后为了ZK的稳定性清理ZK中的大量RMSTATE数据,问题虽然解决了,但是ZK中的80万的节点是怎么来的?正常情况下一个任务下的RMSTATE文件数量也就几个,整个集群也就1000多个任务,一般也就几千个,到底是什么导致他出现了80万个?
排查文件过多的原因
我们把文件列表拉出来看了一下,有个别任务下的attempt文件非常多,这些文件是任务启动失败,然后重试之后所产生的文件,但是理论上我们已经配置了最大重试次数,为了确认,我们又去查看了一下文件,结果是
yarn.application-attempts = 10
那么为什么这个参数设置了之后并没有生效呢?他失败之后一直重启了几万次,导致生成了数万个attempts文件
我们用的是flink1.7, 对于1.7版本 设置akka timeout 时间作为这个窗口时间 默认为30s 在30s之内如果重启次数没达到max attempt 就会开启新一轮重启
flink 1.9版本的这个加入了yarn.application-attempt-failures-validity-interval 配置
PR链接:https://github.com/apache/flink/pull/8400
这个配置定义了一个错误次数累计的窗口 如果在此窗口内错误次数没有达到application-attempts 那么就会重启
public static final ConfigOption<Long> APPLICATION_ATTEMPT_FAILURE_VALIDITY_INTERVAL =
key("yarn.application-attempt-failures-validity-interval")
.defaultValue(10000L)
.withDescription(Description.builder()
.text("Time window in milliseconds which defines the number of application attempt failures when restarting the AM. " +
"Failures which fall outside of this window are not being considered. " +
"Set this value to -1 in order to count globally. " +
"See %s for more information.", link("https://hortonworks.com/blog/apache-hadoop-yarn-hdp-2-2-fault-tolerance-features-long-running-services/", "here"))
.build());
再看一下 yarn逻辑
private int getNumFailedAppAttempts() {
int completedAttempts = 0;
long endTime = this.systemClock.getTime();
// Do not count AM preemption, hardware failures or NM resync
// as attempt failure.
for (RMAppAttempt attempt : attempts.values()) {
if (attempt.shouldCountTowardsMaxAttemptRetry()) {
if (this.attemptFailuresValidityInterval <= 0
|| (attempt.getFinishTime() > endTime
- this.attemptFailuresValidityInterval)) {
completedAttempts++;
}
}
}
return completedAttempts;
}
解决办法
flink1.7 版本
可以增加akka timeout时间窗口 来统计累计attempt重启次数 但是这种修改会影响全局 目前没有太好的办法
flink1.9 将 yarn.application-attempt-failures-validity-interval 设置为-1 进行全局累加