
1. Flink On Yarn的部署思路与核心机制1.1 为什么选择YARN作为Flink的部署底座如果你在公司里跑过Flink任务大概率不会裸奔式地在自己电脑上启动一个Standalone集群来干活。生产环境里最常见的形态就是把Flink作业提交到已经存在的Hadoop YARN集群上让YARN统一管理资源。这套方案叫Flink On Yarn。我最早接触实时计算的时候也纠结过一个问题Flink自己不是有Standalone集群吗为什么还要跑到YARN上后来在真实业务里被资源问题折腾过几次才想明白核心原因有三点。第一资源利用率能拉满。一个公司通常已经有了一套7x24小时跑着的Hadoop集群机器资源都在那儿。如果Flink再单独搞一群机器等于在资源上重复建设。把Flink作业塞进YARN任务多的时候动态申请容器任务少的时候资源自动释放别的离线任务还能抢过来用。第二多租户管理方便。YARN本身有队列Queue机制生产、测试、不同部门之间可以划分独立的资源池。你把Flink作业交到某个队列它就只能用这个队列分配的资源不会出现一个任务吃光整个集群的情况。这对公司运维来说是硬需求。第三部署成本低。不用预先搭好一套Flink集群只需要把Flink包解压好、配置好然后通过命令向YARN提交即可。作业起来的时候Flink的进程会以YARN容器Container的形式自动拉起。注意Flink On Yarn的前提是网络环境能访问Hadoop集群的ResourceManager和NodeManager端口别忽略了集群本身的安全组和防火墙配置这个后面踩坑部分细说。1.2 三种部署模式怎么选Session、Per-Job、ApplicationFlink On Yarn按提交方式分三种很多人刚开始容易搞混。我用大白话拆一遍。Session模式会话模式这种模式下你先在YARN上启动一个常驻的Flink集群这个集群有一个JobManager和若干TaskManager。后续可以通过命令往这个常驻集群里提交多个作业。它的问题在于一个TaskManager挂了上面跑的所有作业都受影响多个作业挤在一起资源争抢也很难控制。典型的适用场景是频繁提交小作业且作业之间相互影响不大比如一些临时的数据查询任务。Per-Job模式单作业模式每次提交一个作业YARN会为这个作业单独拉起一套Flink集群作业跑完集群自动销毁。资源隔离彻底不会出现A作业把B作业挤死的情况。这个也是最经典的Flink On Yarn用法提交命令里指定-m yarn-cluster即可。Application模式应用模式这个比Per-Job更进一步把用户代码的main()方法也放到YARN容器里执行。Per-Job模式下main()是在客户端本地跑的客户端退出可能影响任务状态Application模式则把整个应用逻辑都挪到集群内部客户端提交完就能干自己的事。适合那种大作业、长周期作业也适合做平台化的统一入口。三种模式从本质上说区别在于Flink集群的生命周期由谁控制、main()方法在哪里执行、作业怎么跟YARN交互。下面拿一张表格直接对比方便你做选型。对比项SessionPer-JobApplicationFlink集群生命周期常驻手动停止随作业创建和销毁随作业创建和销毁main()执行位置客户端客户端YARN容器内资源隔离共享隔离弱完全隔离完全隔离启动速度快集群已起慢需拉起整套集群中等适合场景小作业、交互式查询独立作业大作业、平台化1.3 一次Flink On Yarn提交背后到底发生了什么理解了模式再弄懂一次提交的完整流程出了问题你就知道往哪儿查。Flink作业提交到YARN后大致流程是这样的客户端把Flink的相关依赖、配置和用户JAR包上传到HDFS临时目录里。客户端向YARN的ResourceManager申请一个容器Container用来启动ApplicationMaster。ResourceManager分配容器后NodeManager在这个容器里启动ApplicationMaster进程。ApplicationMaster里实际跑的是Flink的JobManagerJobManager启动成功后会向ApplicationMaster注册资源请求。ApplicationMaster继续向ResourceManager申请TaskManager所需的容器。容器分配下来后NodeManager负责启动TaskManager进程TaskManager启动后向JobManager注册自身Slot资源。JobManager拿到了足够的TaskManager就开始调度作业执行。如果提交后迟迟见不到任务在YARN上跑起来从第2步开始逐个排查客户端和YARN通信是否有问题、HDFS临时目录能不能写、AM容器是否因为资源不足被卡住。2. 打好地基环境准备与关键配置2.1 Flink与Hadoop版本怎么匹配才不翻车Flink版本和Hadoop版本的兼容问题是我见过新人踩得最多的坑。很多人下载Flink压缩包之后兴冲冲地配好环境变量就提交结果报错说找不到org.apache.hadoop.conf.Configuration之类的类。Flink从某个版本以后默认发行包不再捆绑Hadoop依赖。你需要根据集群里实际安装的Hadoop版本额外准备对应的依赖JAR。常见有两种做法第一种做法直接把Hadoop安装目录下的share/hadoop相关JAR包全部拷贝到Flink的lib目录下。这个最暴力但要注意版本别冲突不同版本的Hadoop客户端代码差异很大。第二种做法用Flink官方在opt目录下预编译好的flink-shaded-hadoop-uber-*.jar把这个JAR复制到lib目录即可。好处是官方帮你把依赖都理顺了坏处是这个JAR包含的Hadoop版本是固定的如果你们的Hadoop是深度定制的可能仍有兼容问题。除了依赖JAR还有一个非常重要的环境变量HADOOP_CLASSPATH。很多人在本地直接执行yarn-session.sh能启动成功但提交作业时老是提示找不到java.lang.ClassNotFoundException: org.apache.hadoop...其实就是因为HADOOP_CLASSPATH没有传给远端容器。对于Hadoop 3以上的版本我建议直接用官方推荐的方式生成export HADOOP_CLASSPATH$(hadoop classpath)然后强制在/etc/profile或Flink的conf/flink-env.sh中加入这个环境变量保证后续无论怎么调脚本都不会丢。2.2 flink-conf.yaml中值得重点关注的参数部署Flink On Yarnflink-conf.yaml里的配置不再像本地跑那样随便填。我挑几个和YARN部署强相关的参数说明一下推荐值和原因。内存配置类参数配置项推荐值说明jobmanager.memory.process.size1600mJobManager进程的完整内存含堆外和JVM开销taskmanager.memory.process.size2g或更高TaskManager进程的完整内存根据数据量调taskmanager.numberOfTaskSlots按CPU核数定通常2-4每个TaskManager能跑的并行任务数资源申请类参数yarn.application.name给YARN上的应用起个名字方便运维在YARN界面上认任务。yarn.application-attempts任务失败后最多重试几次生产环境建议设置成合理的数字比如3避免因偶发网络抖动直接失败。默认是1太小了。提交时的临时参数Flink支持在提交命令中用-yjm指定JobManager内存用-ytm指定TaskManager内存用-ys指定每个TaskManager的Slot数。比如flink run -m yarn-cluster \ -yjm 1024m \ -ytm 2048m \ -ys 2 \ -c com.example.MyJob \ ./my-job.jar这些临时参数会覆盖配置文件里的值所以实际部署时我习惯把通用的内容写进配置文件个别作业的特殊资源要求在命令行覆盖。注意YARN分配内存时还会额外加上Flink自身框架的内存开销比如TaskManager默认会多预留JVM Overhead。如果你在YARN上看到实际申请的内存比你命令里写的多不用慌这是正常的。2.3 依赖JAR包的管理技巧Flink作业的JAR包通常包含业务代码和一些第三方库但要注意部分依赖是不能打进业务JAR的否则容易产生冲突。一种常见的做法是把Flink本身的核心依赖用provided级别声明不要把它们打进去。如果你用Maven构建类似下面这样dependency groupIdorg.apache.flink/groupId artifactIdflink-streaming-java_2.11/artifactId version${flink.version}/version scopeprovided/scope /dependency dependency groupIdorg.apache.flink/groupId artifactIdflink-clients_2.11/artifactId version${flink.version}/version scopeprovided/scope /dependency另外Flink On Yarn提交时用户JAR也会被上传到HDFS。如果你经常改代码HDFS上的临时目录里会堆积很多旧JAR虽然不会立刻出问题但日积月累也占空间。我建议定期清理HDFS上的/.flink相关临时目录。3. 三种模式的实操记录与参数详解3.1 Session模式从启动yarn-session到提交作业Session模式的流程我拆成三步。第一步确保Flink的启动脚本有权限访问YARN。在Flink的conf/flink-env.sh中设置好HADOOP_HOME、HADOOP_CONF_DIR和HADOOP_CLASSPATH然后直接启动./bin/yarn-session.sh -d -nm flink-session-test -jm 1024m -tm 2048m -s 2解释一下参数-d表示分离模式客户端启动完集群后就不再占着终端-nm指定YARN上显示的应用名-jm和-tm分别指定JobManager和TaskManager的内存-s指定Slot数。启动后如果成功你会看到类似下面的日志... 2025-05-08 10:00:00,123 INFO org.apache.flink.yarn.YarnClusterDescriptor - Found Web Interface ... of JobManager ...告诉你可以通过Web UI访问Flink的监控界面了。第二步往这个常驻集群里提交作业。打开一个新终端执行./bin/flink run -d -c com.example.MyJob ./my-job.jar \ --input hdfs:///data/input.txt \ --output hdfs:///data/output.txt-d表示作业以分离模式提交即使客户端退出作业也照常运行。第三步作业跑完以后如果想释放资源可以到YARN界面上Kill掉那个Application或者执行./bin/yarn-session.sh --stopSession模式最大的坑在于多个作业共享同一个TaskManager时某个作业的CheckPoint或内存压力会把整个集群搞挂。所以我个人很少在产线长时间使用Session模式它更适合测试环境。3.2 Per-Job模式的正确提交姿势Per-Job模式在我看来才是真正符合生产习惯的模式提交一次跑完就消亡非常干净。最核心的提交命令是./bin/flink run \ -m yarn-cluster \ -yjm 1024m \ -ytm 2048m \ -ys 2 \ -yD yarn.application.namemy-per-job-demo \ -c com.example.MyJob \ ./my-job.jar \ --input hdfs:///data/input.txt-m yarn-cluster是关键表示让Flink以Per-Job模式提交到YARN。如果你没有显式指定-mFlink默认使用的是default配置那就是往本地跑或者往flink-conf.yaml里配置的地址跑。Per-Job模式下Flink会在HDFS的临时目录下创建以/.flink开头的应用专属目录。这个目录里放着JobManager运行所需的JAR包、配置和用户代码。作业结束后这些临时资源会被自动清理但如果作业失败得比较蹊跷目录可能残留需要手动清。这里要特别提醒在Per-Job模式下默认的yarn.application-attempts可能比较小。如果你的作业因为初始化太慢导致AM被YARN杀掉它会直接失败而不是重启。建议在提交命令里追加-yD yarn.application-attempts33.3 Application模式把main方法交给YARNApplication模式是近几年Flink推广度比较高的用法原因是它解决了Per-Job模式下客户端依赖太重的问题。使用Application模式提交命令不一样./bin/flink run-application \ -t yarn-application \ -Djobmanager.memory.process.size1024m \ -Dtaskmanager.memory.process.size2048m \ -Dyarn.application.namemy-app-demo \ -c com.example.MyJob \ ./my-job.jar区别在于run-application替代了run-t yarn-application指定了目标部署目标没有-m yarn-cluster这种语法。Application模式下客户端只需要把JAR包传到HDFS然后向YARN申请一个容器启动ApplicationMaster。JobManager会在AM内部运行然后从HDFS上拉取用户JAR并执行main()方法。客户端提交完就可以退出不再承担任何作业调度的职责。这意味着你在线上服务器执行完提交命令终端可以随手关掉任务不会受到任何影响。对于K8s化、平台化的任务管理系统来说这种模式非常友好。三种模式的资源配置直观对比提交之后到YARN界面上看你会看到Session模式一个长时间运行的应用里面有多个作业在并行跑Per-Job模式每次提交作业都会新冒出一个独立ApplicationApplication模式跟Per-Job在YARN界面上看起来很像但得注意ApplicationMaster的日志里能看到用户的main()方法执行过程。4. 常见问题与排查技巧实录4.1 高频问题速查表把我在实际部署里遇到的高频问题整理成一个表格方便你直接对照。现象可能原因解决思路提交时报ClassNotFoundExceptionHADOOP_CLASSPATH未设置执行export HADOOP_CLASSPATH$(hadoop classpath)提交时报Connection RefusedYARN端口不可达或RM地址配置错误核对yarn-site.xml与网络策略作业运行中TaskManager频繁挂掉内存配置超出容器限制检查taskmanager.memory.process.size与YARN容器内存上限任务一直ACCEPTED不运行队列资源不足或队列不存在确认-yD yarn.queue配置的队列存在且有余量AM启动后立刻被killAM内存不够或超时增大jobmanager.memory.process.size并检查超时参数HDFS临时目录占用暴涨大量失败提交残留定期清理/.flink相关目录4.2 结合YARN日志定位问题有一次我遇到过任务卡死现象是YARN上Application显示RUNNING但Flink作业迟迟不进入RUNNING状态。客户端一直提示等待JobManager连接。定位思路是这样的先去YARN的ResourceManager界面找到对应Application的日志入口点进Logs重点看ApplicationMaster的stdout和stderr。如果看到类似java.lang.OutOfMemoryError: Java heap space说明JobManager或某个容器内存不够如果看到org.apache.flink.runtime.entrypoint.ClusterEntrypointException说明JobManager启动失败了紧接着会看到Cause比如端口冲突、HDFS写权限问题等。如果是TaskManager出现异常可以通过Flink Web UI上的TaskManager列表找到日志查看崩溃的堆栈。排查问题最重要的一点先看日志再改配置不要凭感觉调参。很多内存问题被反复调大其实根因是某个第三方库在序列化时产生了超大对象。4.3 几个被验证过的独门避坑经验第一个经验给Flink作业在YARN上单独划分队列。不要跟离线MapReduce任务混在一个队列里实时任务对延迟和稳定性要求高资源被离线任务抢占后很容易出现背压或CheckPoint超时。第二个经验不要在生产环境用Session模式跑重要任务。我踩过一次某个作业频繁触发CheckPoint结果把共享TaskManager的堆内存挤爆连带其他作业一起失败。后来上线任务统一走Per-Job或Application。第三个经验Flink On Yarn的日志分散在YARN的各个NodeManager节点上。如果你在容器内排查问题不方便可以在提交命令里追加-yD yarn.log-aggregation-enabletrue开启日志聚合后所有日志会收集到HDFS上配合yarn logs -applicationId appId查看能省掉到处ssh登录NodeManager的麻烦。第四个经验HDFS上的临时目录清理不能忽视。一次大规模测试后我检查HDFS发现.flink目录下累积了几百GB的临时JAR和配置。这不是Flink的Bug而是很多失败任务残留没有回收。写一个定时脚本定期删除超过一定天数的/.flink下目录比较有效。4.4 资源不均衡时的调优思路有一次我们有个作业背压特别严重TaskManager CPU飚高但内存还有富余。很多人第一反应是加并行度、加机器但实际上问题可能出在KeyBy的数据倾斜。排查思路是打开Flink Web UI看各个SubTask的积压记录如果发现某个子任务积压特别多而其他子任务很闲那就是数据倾斜。这时候增加并行度是没用的还得从KEY的设计上打散。调整完业务层的KEY策略后再结合Flink On Yarn的资源参数做配套优化比如合理设置taskmanager.numberOfTaskSlots避免一台机器上启动过多线程导致CPU争抢。5. 从我自己的经验里总结出的部署建议Flink On Yarn这套方案看似简单把包解开、配几个参数、执行一条提交命令但真正要在生产环境跑得稳考验的是你对资源管理和任务生命周期的把控。我个人觉得最值得花时间的并不是去背诵各种参数而是先想清楚你的任务特点是长周期的实时ETL还是高频的临时分析是资源敏感型还是运行时长敏感型先想清楚这些再来选Session、Per-Job还是Application模式就不会错得太离谱。如果你所在的公司已经有了一套稳定的YARN集群建议从Per-Job模式起步跑熟之后再尝试Application模式和平台化封装。把Flink的包和依赖管理纳入正式发布流程比什么都重要。最后分享一个小技巧提交前养成使用-yD在命令行覆盖关键配置的习惯避免为了测试不同资源配置频繁改动配置文件。配合日志聚合功能把每次提交前的改动记录在案出了线上问题回滚也快。