大数据实时计算平台Flink引擎以Application模式运作在Yarn集群,在使用租户权限管理的过程中,遇到任务提交失败的异常,详细堆栈如下:
Failed to download resource { { hdfs://felixzh:9001/flink/libs/lib/log4j-core-2.17.1.jar, 1745737698195, FILE, null },pending,[(container_1740966828306_0038_01_000001)],5175757223143519,DOWNLOADING} java.io.IOException: Resource hdfs://felixzh:9001/flink/libs/lib/log4j-core-2.17.1.jar is not publicly accessible and as such cannot be part of the public cache.
排查上述问题,遂有此文。本文以上述异常为入口,结合yarn applciation作业提交流程、yarn资源文件本地化机制,排查相关源码,最后给出Flink Application提交模式与yarn资源文件本地化可见性的适配方案。
根据错误日志查找Flink源码,发现flink-table模块ResourceManager类中有类似日志,对应源码如图所示:
需要仔细辨别才能发现,虽然Failed to download resource能对应上,但是后面的异常对应不上。笔者刚开始没注意,浪费时间梳理Flink这块的代码。其实,真正的异常日志是AM container打印的,对应于Hadoop源码hadoop-yarn-server-nodemanager模块的ResourceLocalizationService资源本地化服务。对应源码如图所示:
而后半段日志is not publicly accessible…对应于hadoop-yarn-common模块FSDownload类,对应代码如图所示:
从代码可以看出问题就是:已经设置可见性为PUBLIC的资源实际使用时候发现并不是public的。
这里需要先介绍下什么是资源以及资源本地化?所谓资源就是yarn container运行所需要的文件或者jar包等。而资源本地化就是在container运行前资源文件需要提前从HDFS下载到nodemanager节点的本地目录。
每个Application能够提交运行到yarn集群的流程都要包括:yarn client将资源文件上传到HDFS共享目录、ResourceManager启动ApplicationMaster进程、ApplicationMaster分配任务、nodemanager进程下载资源文件、然后启动container运行任务。大致流程如图所示:
而资源可见性共分为如下三类:
PUBLIC:nodemanager节点所有用户共享;
PRIVATE:nodemanager节点相同用户的所有application共享;
APPLICATION:nodemanager节点单个应用程序内的Container共享。
所谓共享即同一nodemanager节点内、共享范围内只缓存一份资源文件。相应源码注释如下:
经过上述分析,解决方法分为两类:第一类适用于HDFS没有权限管理的环境,可以直接将资源文件放置到HDFS共享目录(即权限至少设置为755)。另一类适用于HDFS需要开启权限管理的环境,这种需要修改Flink源码将默认写死的可见性为PUBLIC改为可配置的PUBLIC/PRIVATE/APPLICATION。相关源码路径为:
flink-yarn/src/main/java/org/apache/flink/yarn/YarnClusterDescriptor.java
完整修改内容见FelixZh笔者的github:
https://github.com/felixzh2020/flink/commit/a3999698effe8914a75cc49e0953e2b055a664c5
通过大数据实时计算平台创建普通的测试用户user01,对应的HDFS授权HD路径设置为/user/user01。权限详情如下:
[root@felixzh bin]# ./hdfs dfs -ls /user/
Found 1 items
drwx------ - user01 supergroup 0 2025-04-28 15:34 /user/user01
[root@felixzh bin]# ./hdfs dfs -ls /user/user01
Found 1 items
drwx------ - user01 supergroup 0 2025-04-28 15:34 /user/user01/lib
由于/user/user01目录只有用户user01有读写执行权限,所以资源可见性为APPLICATION和PRIVATE均可。实际验证如下:
./flink run-application -t yarn-application -Dyarn.provided.lib.dirs=/user/user01/lib -Dyarn.provided.lib.local-resource-visibility=APPLICATION ../examples/batch/WordCount.jar
./flink run-application -t yarn-application -Dyarn.provided.lib.dirs=/user/user01/lib -Dyarn.provided.lib.local-resource-visibility=PRIVATE ../examples/batch/WordCount.jar
强调一点:APPLICATION和PRIVATE可见性的本地资源文件会随着applciation执行完成立即清理。而PUBLIC可见性的资源文件在applciation执行完成仍然存在,NodeManager会定期清理过期的缓存文件:定时yarn.nodemanager.localizer.cache.cleanup.interval-ms启动清理确保每个缓存目录容量小于yarn.nodemanager.localizer.cache.target-size-mb,如果超过该值,则采用LRU算法清除不再使用的缓存文件。