前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一次flink任务重试失败的问题分析

一次flink任务重试失败的问题分析

作者头像
陈猿解码
发布2023-02-28 15:11:09
1.4K0
发布2023-02-28 15:11:09
举报
文章被收录于专栏:陈猿解码陈猿解码

【背景】

在研究flink任务失败重试的过程中,遇到了一个问题,具体表现为:在任务重试时,出现与NN连接失败,触发新的一次重试,然后重复此流程,直到达到重试上限后,任务失败退出。

本文就总结下整个问题的分析过程,以及涉及到的相关知识点。

【问题分析过程】

首先查看了任务的日志,发现有如下关键信息:

代码语言:javascript
复制
INFO org.apache.hadoop.io.retry.RetryInvocationHandler [] - java.io.IOException: org.apache.flink.shaded.hadoop2.com.google.protobuf.ServiceException: java.lang.IllegalStateException: Trying to access closed classloader. Please check if you store classloaders directly or indirectly in static fields. If the stacktrace suggests that the leak occurs in a third party library and cannot be fixed immediately, you can disable this check with the configuration 'classloader.check-leaked-classloader'., while invoking ClientNamenodeProtocolTranslatorPB.getFileInfo over hadoop-namenode-1.hadoop-namenode.dev-env-3.svc.cluster.local/192.168.141.164:9000. Trying to failover immediately.
Caused by: java.lang.IllegalArgumentException: Failed to specify server's Kerberos principal name
  at org.apache.hadoop.security.SaslRpcClient.getServerPrincipal(SaslRpcClient.java:325) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.security.SaslRpcClient.createSaslClient(SaslRpcClient.java:231) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.security.SaslRpcClient.selectSaslClient(SaslRpcClient.java:159) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.security.SaslRpcClient.saslConnect(SaslRpcClient.java:390) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.ipc.Client$Connection.setupSaslConnection(Client.java:617) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.ipc.Client$Connection.access$2200(Client.java:423) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.ipc.Client$Connection$2.run(Client.java:823) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.ipc.Client$Connection$2.run(Client.java:819) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_342]
  at javax.security.auth.Subject.doAs(Subject.java:422) ~[?:1.8.0_342]
  at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:2012) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  at org.apache.hadoop.ipc.Client$Connection.setupIOstreams(Client.java:819) ~[flink-shaded-hadoop-2-uber-2.10.1.jar:2.10.1]
  ... 56 more

从这个日志里,可以发现有两个问题:

1)与nn连接失败是因为抛出了一个异常:无效的服务端principal。

2)存在一个IO异常的日志信息:访问已经关闭的classLoader。

对于第一个问题,根据其堆栈信息,可以快速找到其源码,并推测应该是从configurtaion类对象实例中没有正确获取到服务端的key,从而构造了一个空的principal,导致出现无效参数的异常。

再次复现问题,并进行debug跟踪了下,发现在configuration中,properties中的信息几乎为空,这也就印证了刚才的推测。

结合上图与configuration的代码来看,该configuration对象还是任务重试之前的对象(排除new一个新的没有加载配置文件的情况),且至少调用了一次reloadConfiguration,因为在该函数中会将properties置为NULL,在重新调用get时,触发懒加载,新建一个properties实例对象。

但是,有疑惑的地方是:懒加载时,不管怎样,都会将overlay中的内容重新拷贝到properties中,而实际情况却没有。

所以,问题变成为什么configuration中的properties会清空,并且没有将overlay中的数据拷贝到properties中。这个问题和访问已经关闭的classLoader抛出异常有什么关联?

再次复现问题进行分析,这次发现出现该问题时,configuration中的classLoader(实际上是flink中的SafetyNetWrapperClassLoader)中的inner为NULL。

之所以为空是因为任务失败时,最终会调用classLoader的close方法。对于配置参数"classLoader.check-leaked-classLoader"为true时,会使用一个包装类,该包装类的close方法就是将真正的classLoader置为NULL。

而在加载资源的时候会调用classLoader中的inner去获取资源,inner为NULL导致直接抛异常出去,指导最外层被捕获。这样在configuration中也就不会执行将overlay中的信息拷贝到properties的逻辑了。

至此,问题的原因已经基本清楚:就是因为任务失败,classLoader被置为空,在加载资源时直接抛异常,引起无法正确获取的服务的key并成功构建principal,导致任务失败。

那么,classLoader什么时候会被置为NULL,以及configuration又是什么时候触发调用的reloadConfiguration导致properties被清空的呢?

在刚才的问题复现过程中,其实发现了这么一个堆栈信息:

结合对应的代码来分析,发现构造YarnConfiguration时,触发了类加载的静态方法调用,以至于调用了reloadConfiguration,将properties清空。

【问题解决】

问题原因都已经分析清楚后,接下来自然而然就是如何解决或规避问题。

一种简单的处理方式是:在flink中,将配置项"classLoader.check-leaked-classLoader"置为false,这样就不会使用到包装类SafetyNetWrapperClassLoader。虽然任务失败时还是会调用classLoader的方法,但在任务重试时,在缓存文件系统对象中的conf的cloassLoader不会被清空,并且还可以继续使用,自然而然也就不会出现问题。

另外,在分析过程中发现,客户端使用的HDFS文件系统句柄是有缓存的,具体以资源名、资源的认证方式以及当前用户名构成唯一key。缓存是没有大小限制的,在没有对句柄主动调用close方法时,都会一直存在缓存中。

因此,如果业务进程是短时间使用一般不会有太大问题。而如果是常驻服务,并且是提供代理功能,那么就可能因为缓存,而出现内存泄露问题。

当然,可以通过将配置项"fs.hdfs.impl.disable.cache"设置为true,来禁用缓存。

【问题引申】

该问题为什么在配套之前的hadoop版本(2.8.5)没有出现,而到了2.10.1之后就出现了?

仔细对比了两个版本相关代码之间的区别后,发现两个版本的Master类的实现确实有所不同。老的版本不会触发加载YarnConfiguration类。因此也就不会有问题。老版本的代码如下所示(新版本的可以见前面的图)

代码语言:javascript
复制
public static String getMasterPrincipal(Configuration conf) 
    throws IOException {
    String masterHostname = getMasterAddress(conf).getHostName();
    // get kerberos principal for use as delegation token renewer
    return SecurityUtil.getServerPrincipal(getMasterUserName(conf), masterHostname);
}

【总结】

本文对flink任务失败重试,classLoader关闭后引发的问题进行了分析定位,同时也简单梳理了涉及到的hadoop配置类、文件系统句柄缓存、以及flink自身涉及的参数等内容。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陈猿解码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
大数据
全栈大数据产品,面向海量数据场景,帮助您 “智理无数,心中有数”!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档