ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DolphinScheduler调度Flink任务报8081端口冲突?完整排查与四种解法

DolphinScheduler调度Flink任务报8081端口冲突?完整排查与四种解法 先说结论这个报错跟 DolphinScheduler 本身大概率没有直接关系锅基本在 Flink 自己身上。你用 DolphinScheduler 调度 Flink 任务日志里甩出来一句Could not start the REST endpoint on any port in port range 8081意思是 Flink 的 JobManager 在启动 REST 服务时想绑定 8081 端口或者你配置的端口范围结果一个都没成功。这个报错从 Flink 1.14 到 1.18 基本没变过见过太多次了。这篇文章把完整排查链路、四种解法、以及我踩过的坑都整理出来给还在和端口搏斗的朋友们一个能直接抄作业的参考。1. 一句话先看懂8081 端口是谁在用、为什么起不来1.1 报错本身暴露了什么Flink 的 JobManager 启动时会拉起一个 RestServerEndpoint这个服务承担两件事一是给 Flink Web UI 提供页面接口二是给客户端比如flink run命令提交任务用。默认端口就是 8081。RestServerEndpoint 在启动时会去绑定端口。你看到Could not start Rest endpoint on any port in port range 8081这种日志完整堆栈通常长这样org.apache.flink.runtime.rest.RestServerException: Could not start the REST endpoint on any port in port range 8081. This usually means that the port is already occupied by another process. at org.apache.flink.runtime.rest.RestServerEndpoint.start(RestServerEndpoint.java:...)这句话翻译过来就两个信息第一8081 这个端口要么被占了要么绑定过程中出了异常第二Flink 尝试过在配置的端口范围里找替代端口但也没找到可用的于是整个 JobManager 启动失败。换句话说这不是 Flink 任务本身逻辑的问题而是运行环境的问题。1.2 DolphinScheduler 里最常见的三种触发场景我在实际运维中这类报错在 DolphinScheduler 环境里基本逃不出下面三种场景。场景一DolphinScheduler Worker 节点上有 Flink 残留进程。这是最普遍的情况。前一个 Flink 任务跑完以后由于各种原因比如被 kill -9、YARN 容器异常释放、TaskManager 没退干净JVM 进程还挂在机器上8081 端口一直没释放。下一个任务在同一台机器上启动时自然抢不到端口。场景二多个 Flink 任务在同一台机器上并发提交全部用的 local 模式。DolphinScheduler 的 Worker 并发线程数默认可以开到 10也就是说同一台机器同一时刻可能拉起好几个 Flink 任务。如果这些任务都是用本地模式local启动每个任务都会尝试在所在 Worker 节点上自己起一个 JobManager大家全盯着 8081 抢不冲突才怪。场景三机器上本来就部署了常驻的 Flink Standalone 集群。很多公司为了省机器会把 DolphinScheduler Worker 和 Flink Standalone 集群部署在同一批节点上。Standalone 集群的 JobManager 已经占了 8081DolphinScheduler 再用 local 模式起新任务必然报错。1.3 一个容易误判的点不是 DolphinScheduler 占了端口而是并发把冲突暴露了有朋友一开始会怀疑是 DolphinScheduler 自己占了 8081。这里澄清一下DolphinScheduler 各组件的默认端口不是 8081MasterServer 默认 5678WorkerServer 默认 1234ApiServer 默认 12345UI 界面默认 8888。DolphinScheduler 本身的组件基本不会去碰 8081。那为什么报错总出现在 DolphinScheduler 调度任务时因为 DolphinScheduler 是任务编排入口它会在固定的时间窗口内把大量 Flink 任务压到 Worker 节点上。任务本身没问题但调度这个动作把端口资源不足的问题暴露出来了。我在一次故障里看到过典型场景整点调度高峰时六七个 Flink 任务同时碰 8081失败率直接到 30%。单独看每个任务配置和代码都没问题问题出在资源竞争上。2. 现场排查三步走定位 8081 被谁占住2.1 用 netstat/lsof 秒查端口占用登录报错的 Worker 节点第一步永远是看端口。命令很简单netstat -tlnp | grep 8081我见过很多次类似这样的输出tcp6 0 0 :::8081 :::* LISTEN 23456/java看到LISTEN状态和java进程基本就能确定 8081 被一个 Java 进程占着。有些机器没有 netstat可以直接用 lsoflsof -i:8081输出大概是COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 23456 flink 18u IPv6 1234567 0t0 TCP *:webcache (LISTEN)注意看 PID 和启动用户。这个 PID 是你接下来定位残留进程的关键线索。2.2 用 jps -lv 揪出残留 Flink 进程拿到 PID 后别急着 kill先看看这个进程到底是谁。用jps -lv能看出 Java 进程的主类和启动参数jps -lv | grep 23456常见两种结果23456 org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint --configDir /opt/flink/conf ... 23456 org.apache.flink.runtime.taskexecutor.TaskManagerExecutor --configDir /opt/flink/conf ...第一种是 Flink Session 集群的 JobManager第二种是 TaskManager。这两种进程赖在机器上基本就是罪魁祸首。这里有个排查技巧先看进程启动时间再看它属于哪个任务。用ps -ef | grep 23456能看到更详细的信息比如启动命令里带的-Duser.home、-Dlog.file之类的参数能反推出来是哪个业务线、哪个任务残留的。如果启动时间是很久以前说明是之前手工或误操作留下的常驻进程如果启动时间就在几分钟前那大概率是上一批失败任务没退干净的 TaskManager。2.3 翻 DolphinScheduler 任务日志确认真正提交模式端口查完了还要做一步判断报错任务的提交模式是什么。DolphinScheduler 的 FLINK 任务节点底层执行的就是flink run命令。找到失败任务实例的日志拉到执行命令那一行能看到类似[INFO] Executing command: flink run -d -Dexecution.targetlocal ...重点看有没有-t yarn-application、-m yarn-cluster这类参数。如果没有并且命令行里没指定远程集群地址那 Flink 默认会以 local 模式在本机起一个 MiniCluster 来跑任务。local 模式下JobManager 和 TaskManager 都在提交命令的这台机器上启动REST 端口也绑定在这台机器的 8081 上。这一步很关键因为local 模式 DolphinScheduler 多任务并发是端口冲突的重灾区。如果确认是 local 模式后面要么改配置要么改提交方式。3. 四种解法按成本从低到高3.1 紧急止血清理残留进程的正确姿势确认 8081 被残留的 Flink 进程占着且这个进程确认没有业务在跑那就直接清理# 先正常 kill给 JVM 一点时间做资源释放 kill 23456 # 等几秒看端口是否释放 netstat -tlnp | grep 8081 # 如果还在再强杀 kill -9 23456这里我建议先用kill而不是直接kill -9。Flink 进程被正常终止时会尝试向 ResourceManager 或 ZooKeeper 上报注销能少留一些脏数据。当然在端口冲突这种紧急情况下直接kill -9也不是不行只是后续要多留个心眼确认有没有遗留的 HA 元数据或者 ZooKeeper 节点。清理完进程后到 DolphinScheduler 里手动重跑失败任务这是最快恢复业务的手段。但注意这只是止血不是根治。如果不处理后面的问题下次调度高峰还会再炸。3.2 配置层修复rest.port 与 rest.bind-port 怎么配才不打架如果你希望保留 local 模式或者想给常驻的 Flink Standalone 集群做加固那就改 Flink 配置文件flink-conf.yaml。很多人只知道rest.port其实 Flink 还提供了rest.bind-port。两者的区别是参数作用默认值rest.portREST 服务对外暴露的端口也是客户端连接的端口8081rest.bind-portREST 服务实际绑定的端口可以是一个范围比如8081-8089不配置时等于rest.port关键点来了如果rest.bind-port配置了端口范围Flink 会从这个范围里逐个尝试绑定直到找到可用端口。任务跑起来后JobManager 会把实际绑定的端口通过心跳上报给 ResourceManager 和客户端所以客户端不需要手动指定具体端口。建议在flink-conf.yaml里这样配rest.bind-port: 8081-8089这样配置后即使 8081 被某个进程占了Flink 也会自动尝试 8082、8083直到成功。这个范围不用开太大10 个端口以内足够。如果你嫌范围不够扩到8081-8091也没问题但别动不动就写一个8081-9000会让排查端口占用时非常痛苦。另一个备选项是把端口改成随机rest.port: 0rest.port: 0表示让操作系统随机分配一个可用端口。好处是彻底避免冲突坏处是任务运行时你很难从一个固定地址去访问 Flink Web UI。排障的时候还得去翻日志找实际端口比较麻烦。我一般只在测试环境用这个方案生产环境还是建议用固定范围。3.3 任务级参数DolphinScheduler 里动态指定端口范围很多时候你不想动全局配置只想让 DolphinScheduler 里某个具体任务避开端口冲突。这个可以做到。在 DolphinScheduler 的 FLINK 任务节点里有一个程序参数输入框。这里的参数会原样拼接到flink run命令后面。所以你可以这样写-d -Drest.bind-port8081-8085-D参数是 Flink 运行时读取配置的入口这里设置rest.bind-port等价于在flink-conf.yaml里配置了同名参数并且优先级更高。任务提交后JobManager 会在 8081 到 8085 这个范围内找可用端口。如果你有多个 Flink 任务要同时跑最好的方式是给每个任务规划不同的端口段。比如任务 A 用8081-8085任务 B 用8086-8090任务 C 用8091-8095。这样即使所有任务都塞在一台机器上也不会互相抢端口。从 DolphinScheduler 3.x 开始FLINK 任务节点本身还支持通过自定义参数传配置。但我实测下来最稳妥的还是直接在程序参数里写-D不依赖 DolphinScheduler 版本对参数解析的差异。3.4 根治推荐把 Flink 提交从 local 切到 YARN/K8s前面几种方案本质上还是在一个机器上多个人抢端口这个框架里打转。端口范围只是降低了冲突概率并没有消灭冲突根源。真正治本的做法是把 Flink 任务的提交模式从 local 切到资源调度模式让 YARN 或 K8s 来管理每个 Flink 集群的资源分配。这里放一个 Flink 提交模式的对比表提交模式REST 端口绑定位置冲突概率适用场景local执行命令的 Worker 节点本机高个人本地调试standalone-session常驻集群 JobManager 所在节点中高并发提交时也有风险小集群、稳定负载yarn-applicationYARN 分配的容器内低生产环境首选kubernetes-applicationK8s Pod 内低容器化平台在 DolphinScheduler 的 FLINK 任务节点中如果要切到 YARN 模式程序参数可以这样写-t yarn-application -Djobmanager.memory.process.size1024m -Dtaskmanager.memory.process.size1024m同时指定主程序类和主程序 Jar 包。任务提交到 YARN 后REST 端口绑定在 YARN 容器内部端口由容器网络管理不再和 DolphinScheduler Worker 节点上的本地端口产生冲突。就算多个任务同时提交YARN 会为每个任务启动独立的 Application Master各自占各自的容器网络互不干扰。这也是我在生产环境最推荐的做法。DolphinScheduler 负责什么时候跑YARN/K8s 负责跑在哪里、用多少资源。4. 一次真实修复实录从报错到任务恢复4.1 现场环境与报错上下文直接说一段我处理过的真实案例。环境是这样的组件版本 / 配置DolphinScheduler3.1.4三节点部署Flink1.16.2部署拓扑ds-01、ds-02、ds-03 三台机器Master 和 Worker 混部Worker 并发线程数worker.exec.threads 默认 10故障现象某天早上 10:00 的调度高峰一批 Flink 任务集中失败。DolphinScheduler 日志里大量出现Could not start the REST endpoint on any port in port range 8081失败任务全部集中在 ds-01 这台机器上。4.2 完整操作记录命令 关键输出第一步先登录 ds-01看 8081 端口netstat -tlnp | grep 8081输出tcp6 0 0 :::8081 :::* LISTEN 18455/java有个 PID 为 18455 的 Java 进程占着端口。用 jps 看身份jps -lv | grep 18455输出18455 org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint --configDir /opt/flink/conf ...确认了是 Flink Standalone Session 集群的 JobManager 进程。再查启动时间ps -o lstart -p 18455输出显示这个进程是前一天下午启动的一直挂到现在但没有对应的活动任务。这个 Session 是之前有同事手工在服务器上启动的用完忘了关8081 被它一直占着。继续翻 DolphinScheduler 失败任务的日志找到实际执行命令Executing command: flink run -d -Dexecution.targetlocal ...问题链条完整了DolphinScheduler 在 ds-01 上以 local 模式启动新 Flink 任务任务尝试绑定 8081 时发现被残留的 StandaloneSessionClusterEntrypoint 占着整个 JobManager 启动失败。第二步清理残留进程kill 18455 sleep 5 netstat -tlnp | grep 8081端口已经释放没有输出。第三步临时把失败任务重跑一遍确认业务恢复后再做配置层加固。我在 ds-01 的 Flink 配置文件flink-conf.yaml中加上rest.bind-port: 8081-8089同时在 DolphinScheduler 中给那些没有配置启动参数的 Flink 任务节点统一在程序参数里加了-d -Drest.bind-port8081-8089这样即使下次再有残留进程占住 8081Flink 也能自动落到 8082 到 8089 里的某个端口不会因为单点端口冲突直接失败。4.3 修复效果验证和遗留风险重跑失败任务后任务从 SUBMITTED 快速进入 RUNNING再观察日志确认 REST 服务启动成功Rest endpoint listening at 0.0.0.0:8082可以看到端口自动漂移到了 8082说明rest.bind-port生效了。后续再观察了一个完整的调度周期24 小时没有出现新的Could not start报错。但这个案例的遗留风险我也得提一下local 模式下的 Flink 任务每个任务都会起独立的 MiniCluster对 Worker 节点本身的内存和 CPU 消耗非常明显。端口冲突只是暴露出来的表面问题底层是资源分配过于随意。我后来推动了这批任务逐步迁移到 YARN 模式这个是真·一劳永逸端口、内存、CPU 都交给资源管理器统一调度DolphinScheduler 只负责触发。5. 常见问题速查与避坑清单5.1 附表报错现象 / 可能原因 / 解决动作现象可能原因解决动作单任务报 8081 冲突机器上有残留 Flink 进程Session 或 TaskManager清理残留进程重跑任务多个任务同一时间段一起失败Worker 并发线程数高多个 local 集群同时抢端口降低worker.exec.threads并发数或改 YARN/K8s 模式重启机器后还是报错Flink Standalone 集群开机自启先占了 8081修改rest.bind-port范围或停掉自启的 Standalone 集群8081 端口没被占用但仍然报错双栈机器上 IPv4/IPv6 绑定异常加 JVM 参数-Djava.net.preferIPv4Stacktrue再试DolphinScheduler 配置了企微告警瞬间一堆告警任务失败触发告警通知属于连锁反应先按上述流程恢复任务再考虑给告警加分组或去重策略5.2 DolphinScheduler 侧的几个隐蔽风险点风险点一Worker 并发线程数不等于你会启动的 Flink 集群数。DolphinScheduler 的worker.exec.threads控制的是 Worker 可以同时执行多少个任务和 Flink 的提交模式没有直接关系。如果这些任务都是 local 模式每个任务就是一个独立的 Flink 集群并发几个任务就是几个集群同时抢端口。这个参数不是越大越好要根据机器资源来评估。风险点二任务失败重试会放大端口冲突。DolphinScheduler 里可以设置失败重试次数。如果任务第一次因为端口冲突失败马上重试大概率还是同一台机器、同一个端口还是会失败。重试次数设太多不仅解决不了问题还会让机器上堆出一堆并发启动的 Flink 进程把负载打高。风险点三租户资源限制可能在任务外层设一道坎。DolphinScheduler 会以租户用户执行任务如果租户用户对应的操作系统账号没有对 Flink 安装目录的读写权限或者 YARN 队列资源不足任务会在更早的阶段失败。这类问题要单独排查别和端口问题混淆。5.3 一条可以直接抄的经验按我自己的排查习惯遇到这种问题只记一个顺序端口状态 → 残留进程 → 提交模式 → 端口配置。先看端口被谁占了再看进程是不是 Flink 残留然后确认 DolphinScheduler 里任务的实际提交模式最后针对性调整端口配置或者提交方式。这个顺序走一遍基本十分钟内能定位。最后补充一个细节如果你决定用rest.bind-port配端口范围记得同时确认一下 DolphinScheduler 的任务日志里能直接看到实际绑定的端口。这样以后排查任务 Web UI 访问、日志采集都能少绕弯路。我个人在实际操作中最深的体会是别指望靠清理一次进程就能解决问题把端口配置和提交模式一起改掉才是真正结束这场与 8081 的拉锯战。
返回列表