0、环境

写作时间:2023.07.07

Flink:1.16

IDE:IntelliJ IDEA 2019.3

1、问题描述

        客户要求使用Flink框架,而且使用的是批处理,中间需要用到数据量的统计,数据的整合,所以我选用了DataSet模式进行处理。

        在本地测试的时候都没有什么问题,但是在打包上传到Flink的Web页面提交任务时,启动报错了,报错内容如下:

Job was submitted in detached mode. Results of job execution, such as accumulators, runtime, etc. are not available. Please make sure your program doesn't call an eager execution function [collect, print, printToErr, count]. 
org.apache.flink.api.common.InvalidProgramException: Job was submitted in detached mode. Results of job execution, such as accumulators, runtime, etc. are not available. Please make sure your program doesn't call an eager execution function [collect, print, printToErr, count]. 
	at org.apache.flink.core.execution.DetachedJobExecutionResult.getAccumulatorResult(DetachedJobExecutionResult.java:56)
	at org.apache.flink.api.java.DataSet.collect(DataSet.java:419)

2、问题分析

       Flink Client提交任务有两种模式,根据提交作业后是否有控制台(stdout)信息打印,提交模式可以分为Detached模式Attached模式

        Detached模式下,Flink Client提交任务之后,将是后台运行的方式,不会在控制台打印输出信息。Detached模式主要是在 Flink的Web页面提交任务 和 使用Rest api的方式提交作业。

bin/flink run

        程序是在 Detached 模式使用了 collect, print, printToErr, count 这些热函数导致的报错。禁止使用 collect, print, printToErr, count 这些热函数,是为了避免数据量大的时候,将数据集中到一台机器导致内存溢出,是Flink底层写死的东西。所以在Detached模式下,要避免报错,只能避免使用那些热函数,必须使用的话,只能使用Attached模式提交任务。

3、解决方式

        我的程序中必须使用 collect 操作符,所以只能使用Attached模式来提交任务,所以只能是使用命令行的方式来提交。命令行的方式提交会在控制台打印信息,因为是批处理,在程序运行完就会自动退出而不会阻塞进程。

        这里我使用了Java远程连接Linux服务器执行shell指令的方式来提交代码,这里可以参考别人的代码:Java远程连接Linux服务器执行shell指令_java连接linux服务器执行命令_猴头蘑菇的博客

         但是不能直接使用下面的方式提交远程服务器上的任务

$ ssh 192.168.xx.xx "bin/flink run -m hadoop102:8081 -c com.xiaoyugan.wc.StreamWordCount -p 2 ./FlinkTutorial-1.0-SNAPSHOT.jar"

        这种方式提交任务,不会有任何反应,Flink程序不会运行也没有日志打印。

        最后使用将打印输出控制台的部分放到了日志文件中,来规避必须打印输出的问题

nohup bin/flink run -m hadoop102:8081 -c com.xiaoyugan.wc.StreamWordCount -p 2 ./FlinkTutorial-1.0-SNAPSHOT.jar > ./log.out 2>&1 &

        将启动命令放在shell脚本 /data/flink-1.16.0/flinkrun.sh,需要用到 source /etc/profile 来获取运行环境,不然也会运行没有反应。添加执行权限 chmod +x flinkrun.sh

#!/bin/bash

echo "start"

source /etc/profile

nohup bin/flink run -m hadoop102:8081 -c com.xiaoyugan.wc.StreamWordCount -p 2 ./FlinkTutorial-1.0-SNAPSHOT.jar > /data/flink-1.16.0/log.out 2>&1 &

echo "end"

        然后就可以使用Java远程连接Linux服务器执行shell指令来调用

public static void main(String[] args) {
        String s = null;
        try {
            //  /data/flink-1.16.0/bin/flink run -h
            s = CommandUtil.remoteExec("/data/flink-1.16.0/flinkrun.sh",
                    "192.168.xx.xx",
                    "root",
                    "123456");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(s);
    }

4、建议

        Flink虽然号称流批一体,但是对于批处理的支持真的不太好,就算使用了DataSet也是有提交任务上的限制,所以个人还是建议,做流式处理时使用Flink,但是做批式处理的时候,最好还是使用Spark,或者直接使用Java后端来写。

        最后,觉得有帮助或者有点收获的话,帮忙点个赞吧!