Flink相关API开发及运行架构和实现原理详解

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
简介: Flink相关API开发及运行架构和实现原理详解

一、Flink相关API说明

flinkAPI官网:Apache Flink 1.12 Documentation: Flink DataStream API Programming Guide


Flink提供了多个层次的API供开发者使用,越往上抽象程度越高,使用起来越方便;越往下越底层,使用起来难度越大



注意:我自己使用的是flink 1.7.2版本,但是在Flink1.12时支持流批一体,DataSetAPI已经不推荐使用了,大家最好优先使用DataStream流式API,既支持无界数据处理/流处理,也支持有界数据处理/批处理!



二、Flink运行架构

1、flink的编程模型

Flink程序主要包含三部分:Source/Transformation/Sink(源/转换操作/输出)




2、创建工程,maven依赖准备

properties

    <properties>
        <encoding>UTF-8</encoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java.version>1.8</java.version>
        <!-- Flink的架构中使用了 Akka 来实现底层的分布式通信,而 Akka 是用 Scala 开发的。我们用到的 Scala 版本为 2.12。-->
        <scala.version>2.12</scala.version>
        <flink.version>1.12.0</flink.version>
    </properties>

 

dependencies


build

 <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <!--<encoding>${project.build.sourceEncoding}</encoding>-->
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
                <configuration>
                    <useFile>false</useFile>
                    <disableXmlReport>true</disableXmlReport>
                    <includes>
                        <include>**/*Test.*</include>
                        <include>**/*Suite.*</include>
                    </includes>
                </configuration>
            </plugin>
            <!-- 打包插件(会包含所有依赖) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <!--
                                        zip -d learn_spark.jar META-INF/*.RSA META-INF/*.DSA META-INF/*.SF -->
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <!-- 设置jar包的入口类(可选) -->
                                     <mainClass>com.tjcu.TestDataStreamYarn</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>

3、需求

4、编码步骤

编码步骤参考官网:https://ci.apache.org/projects/flink/flink-docs-release-1.12/dev/datastream_api.html



1.准备环境-env
2.准备数据-source
3.处理数据-transformation
4.输出结果-sink
5.触发执行-execute

其中创建环境参考官网:


getExecutionEnvironment() //推荐使用
createLocalEnvironment()
createRemoteEnvironment(String host, int port, String... jarFiles)

5、代码实现

(1)DataSet(了解)

package com.tjcu;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.AggregateOperator;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.operators.FlatMapOperator;
import org.apache.flink.api.java.operators.UnsortedGrouping;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.util.Collector;
/**
 * @author :王恒杰
 * @date :Created in 2022/4/20 15:37
 * @description:使用Flink完成WordCount-DataSet
 * 编码步骤
 *  1.准备环境-env
 *  2.准备数据-source
 *  3.处理数据-transformation
 *  4.输出结果-sink
 *  5.触发执行-execute//如果有print,DataSet不需要调用execute,DataStream需要调用execute
 */
public class TestDataSet {
    public static void main(String[] args) throws Exception {
     //老版本的API如下,目前不推荐使用了
        //1.准备环境 env
        ExecutionEnvironment executionEnvironment = ExecutionEnvironment.getExecutionEnvironment();
        //2.准备数据-source
        DataSource<String> stringDataSource = executionEnvironment.fromElements("whj hadoop spark", "whj hadoop spark", "whj hadoop spark");
        //3.处理数据-transformation
        //3.1每一行数据按照空格切分成一个个的单词组成一个集合
        FlatMapOperator<String, String> wordsDS = stringDataSource.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public void flatMap(String value, Collector<String> out) throws Exception {
                //value就是一行行的数据
                String[] words = value.split(" ");
                for (String word : words) {
                    out.collect(word);//将切割处理的一个个的单词收集起来并返回
                }
            }
        });
        DataSet<Tuple2<String, Integer>> wordAndOne = wordsDS.map(new MapFunction<String, Tuple2<String, Integer>>() {
            @Override
            public Tuple2<String, Integer> map(String value) throws Exception {
                //value就是每一个单词
                return Tuple2.of(value, 1);
            }
        });
        //分组
        UnsortedGrouping<Tuple2<String, Integer>> grouped = wordAndOne.groupBy(0);
        //聚合
        AggregateOperator<Tuple2<String, Integer>> result = grouped.sum(1);
        //输出结果-sink
        result.print();
    }
}



(2)基于DataStream(匿名内部类-处理流)

package com.tjcu;
import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.operators.FlatMapOperator;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;;
/**
 * @author :王恒杰
 * @date :Created in 2022/4/20 16:07
 * @description:需求:使用Flink完成WordCount-DataStream 批处理
 *  * 编码步骤
 *  * 1.准备环境-env
 *  * 2.准备数据-source
 *  * 3.处理数据-transformation
 *  * 4.输出结果-sink
 *  * 5.触发执行-execute//如果有print,DataSet不需要调用execute,DataStream需要调用execute
 */
public class TestDataStream {
    public static void main(String[] args) throws Exception {
        //新版本的流批统一API,既支持流处理也支持批处理
        //1.准备环境 env
        StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
//         executionEnvironment.setRuntimeMode(RuntimeExecutionMode.BATCH);//注意:使用DataStream实现批处理
        executionEnvironment.setRuntimeMode(RuntimeExecutionMode.STREAMING);//注意:使用DataStream实现流处理
        //executionEnvironment.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);//注意:使用DataStream根据数据源自动选择使用流还是批
        //2.准备数据-source
        DataStreamSource<String> stringDataStreamSource = executionEnvironment.fromElements("whj hadoop spark", "whj spark", "whj");
        //3.处理数据-transformation
        //3.1每一行数据按照空格切分成一个个的单词组成一个集合
        DataStream<String> words = stringDataStreamSource.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public void flatMap(String value, Collector<String> out) throws Exception {
                //value就是每一行数据
                String[] arr = value.split(" ");
                for (String word : arr) {
                    out.collect(word);
                }
            }
        });
        DataStream<Tuple2<String, Integer>> wordAndOne = words.map(new MapFunction<String, Tuple2<String, Integer>>() {
            @Override
            public Tuple2<String, Integer> map(String value) throws Exception {
                //value就是一个个单词
                return Tuple2.of(value, 1);
            }
        });
        //分组:注意DataSet中分组是groupBy,DataStream分组是keyBy
        KeyedStream<Tuple2<String, Integer>, String> grouped = wordAndOne.keyBy(t -> t.f0);
        //聚合
        SingleOutputStreamOperator<Tuple2<String, Integer>> result = grouped.sum(1);
        //TODO 3.sink
        result.print();
        //启动并等待程序结束
        executionEnvironment.execute();
    }
}



注意:在Flink1.12中DataStream既支持流处理也支持批处理,如何区分?


env.setRuntimeMode(RuntimeExecutionMode.BATCH);//注意:使用DataStream实现批处理
env.setRuntimeMode(RuntimeExecutionMode.STREAMING);//注意:使用DataStream实现流处理
env.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);//注意:使用DataStream根据数据源自动选择使用流还是批

(3)代码实现-DataStream-Lambda

package com.tjcu;
import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;;import java.util.Arrays;
/**
 * @author :王恒杰
 * @date :Created in 2022/4/20 16:07
 * @description:需求:使用Flink完成WordCount-DataStream 批处理
 *  * 编码步骤
 *  * 1.准备环境-env
 *  * 2.准备数据-source
 *  * 3.处理数据-transformation
 *  * 4.输出结果-sink
 *  * 5.触发执行-execute//如果有print,DataSet不需要调用execute,DataStream需要调用execute
 */
public class TestDataStream {
    public static void main(String[] args) throws Exception {
        //新版本的流批统一API,既支持流处理也支持批处理
        //1.准备环境 env
        StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
//         executionEnvironment.setRuntimeMode(RuntimeExecutionMode.BATCH);//注意:使用DataStream实现批处理
        executionEnvironment.setRuntimeMode(RuntimeExecutionMode.STREAMING);//注意:使用DataStream实现流处理
        //executionEnvironment.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);//注意:使用DataStream根据数据源自动选择使用流还是批
        //2.准备数据-source
        DataStreamSource<String> stringDataStreamSource = executionEnvironment.fromElements("whj hadoop spark", "whj spark", "whj");
        //3.处理数据-transformation
        //3.1每一行数据按照空格切分成一个个的单词组成一个集合
        SingleOutputStreamOperator<String> words = stringDataStreamSource.flatMap(
                (String value, Collector<String> out) -> Arrays.stream(value.split(" ")).forEach(out::collect)
        ).returns(Types.STRING);
        DataStream<Tuple2<String, Integer>> wordAndOne = words.map(
                (String value) -> Tuple2.of(value, 1)
        ).returns(Types.TUPLE(Types.STRING,Types.INT));
        //分组:注意DataSet中分组是groupBy,DataStream分组是keyBy
        KeyedStream<Tuple2<String, Integer>, String> grouped = wordAndOne.keyBy(t -> t.f0);
        //聚合
        SingleOutputStreamOperator<Tuple2<String, Integer>> result = grouped.sum(1);
        //TODO 3.sink
        result.print();
        //启动并等待程序结束
        executionEnvironment.execute();
    }
}



(4)On-Yarn-掌握


  • 注意:写入HDFS如果存在权限问题,进行如下设置:
hadoop fs -chmod -R 777  /

并在代码中添加:

System.setProperty("HADOOP_USER_NAME", "root")

代码实现:


package com.tjcu;
import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;
import java.util.Arrays;
/**
 * @author :王恒杰
 * @date :Created in 2022/4/20 16:28
 * @description:使用Flink完成WordCount-DataStream--使用lambda表达式--修改代码使适合在Yarn上运行 编码步骤
 * * 1.准备环境-env
 * * 2.准备数据-source
 * * 3.处理数据-transformation
 * * 4.输出结果-sink
 * * 5.触发执行-execute//批处理不需要调用!流处理需要
 */
public class TestDataStreamYarn {
    public static void main(String[] args) throws Exception {
        //获取参数
        ParameterTool params = ParameterTool.fromArgs(args);
        String output = null;
        if (params.has("output")) {
            output = params.get("output");
        } else {
            output = "hdfs://node1:8020/wordcount/output_" + System.currentTimeMillis();
        }
        //1.准备环境-env
        StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
        executionEnvironment.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);
        //2.准备数据源-source
        DataStream<String> linesDS = executionEnvironment.fromElements("whj hadoop spark", "whj hadoop spark", "whj hadoop", "whj");
        //3.处理数据-transformation
        DataStream<Tuple2<String, Integer>> result = linesDS
                .flatMap(
                        (String value, Collector<String> out) -> Arrays.stream(value.split(" ")).forEach(out::collect)
                ).returns(Types.STRING)
                .map(
                        (String value) -> Tuple2.of(value, 1)
                ).returns(Types.TUPLE(Types.STRING, Types.INT))
                //.keyBy(0);
                .keyBy((KeySelector<Tuple2<String, Integer>, String>) t -> t.f0)
                .sum(1);
        //4.输出结果-sink
        result.print();
        //如果执行报hdfs权限相关错误,可以执行 hadoop fs -chmod -R 777  /
        System.setProperty("HADOOP_USER_NAME", "root");//设置用户名
        //result.writeAsText("hdfs://node1:8020/wordcount/output_"+System.currentTimeMillis()).setParallelism(1);
        result.writeAsText(output).setParallelism(1);
        //5.触发执行-execute
        executionEnvironment.execute();
    }
}

打包




上传



提交执行


/usr/apps/flink/bin/flink run -Dexecution.runtime-mode=BATCH -m yarn-cluster -yjm 1024 -ytm 1024 
 /usr/apps/words.jar --output hdfs://node1:8020/wordcount/output_xx


在Web页面可以观察到提交的程序:


http://node1:8088/cluster或者http://node1:50070/explorer.html#/



输出结果:http://192.168.43.129:50070/explorer.html#/wordcount



三、Flink原理

1、Flink角色分工

在实际生产中,Flink 都是以集群在运行,在运行的过程中包含了两类进程。


#1. JobManager
   他扮演的是集群管理者的角色,负责调度任务,协调checkpoints、协调故障恢复、
   收集 Job 的状态信息,并管理 Flink 集群中的从节点 TaskManager。
#2.TaskManager
   实际负责执行计算的 Worker,在其上执行 Flink Job 的一组 Task;
   TaskManager 还是所在节点的管理员,
   它负责把该节点上的服务器信息比如内存、磁盘、任务运行情况等向 JobManager 汇报。
#3.Client:
用户在提交编写好的 Flink 工程时,会先创建一个客户端再进行提交,这个客户端就是 Client

上面个案例的运行就是从节点执行的



角色分工



2、Flink执行流程


用户首先提交Flink程序到JobClient,经过JobClient的处理、解析、优化提交到JobManager,最后由TaskManager运行task。



(1)Standalone版本



(2)On Yarn版本实现原理



1. Client向HDFS上传Flink的Jar包和配置
2. Client向Yarn ResourceManager提交任务并申请资源
3. ResourceManager分配Container资源并启动ApplicationMaster,
  然后AppMaster加载Flink的Jar包和配置构建环境,启动JobManager
4. ApplicationMaster向ResourceManager申请工作资源,
  NodeManager加载Flink的Jar包和配置构建环境并启动TaskManager
5. TaskManager启动后向JobManager发送心跳包,并等待JobManager向其分配任务

3、Flink Streaming Dataflow


(1)Dataflow、Operator、Partition、SubTask、Parallelism


1. Dataflow:Flink程序在执行的时候会被映射成一个数据流模型
2. Operator:数据流模型中的每一个操作被称作Operator,Operator分为:Source/Transform/Sink
          准备数据-Source
          处理数据-Transformation
          输出结果-Sink
3. Partition:数据流模型是分布式的和并行的,执行中会形成1~n个分区
4. Subtask:多个分区任务可以并行,每一个都是独立运行在一个线程中的,也就是一个Subtask子任务
5. Parallelism:并行度,就是可以同时真正执行的子任务数/分区数


(2) Operator传递模式


数据在两个operator(算子)之间传递的时候有两种模式:


One to One模式:


两个operator用此模式传递的时候,会保持数据的分区数和数据的排序;如上图中的Source1到Map1,它就保留的Source的分区特性,以及分区元素处理的有序性。--类似于Spark中的窄依赖


Redistributing 模式:


这种模式会改变数据的分区数;每个一个operator subtask会根据选择transformation把数据发送到不同的目标subtasks,比如keyBy()会通过hashcode重新分区,broadcast()和rebalance()方法会随机重新分区。--类似于Spark中的宽依赖


(3)Operator Chain(算子链)


客户端在提交任务的时候会对Operator进行优化操作,能进行合并的Operator会被合并为一个Operator,合并后的Operator称为Operator chain,实际上就是一个执行链,每个执行链会在TaskManager上一个独立的线程中执行--就是SubTask。



(4)TaskSlot(任务槽) And Slot Sharing(槽共享)


任务槽(TaskSlot)


每个TaskManager是一个JVM的进程, 为了控制一个TaskManager(worker)能接收多少个task,Flink通过Task Slot来进行控制。TaskSlot数量是用来限制一个TaskManager工作进程中可以同时运行多少个工作线程,TaskSlot 是一个 TaskManager 中的最小资源分配单位,一个 TaskManager 中有多少个 TaskSlot 就意味着能支持多少并发的Task处理。


Flink将进程的内存进行了划分到多个slot中,内存被划分到不同的slot之后可以获得如下好处:


1.  TaskManager最多能同时并发执行的子任务数是可以通过TaskSolt数量来控制的
2.  TaskSolt有独占的内存空间,这样在一个TaskManager中可以运行多个不同的作业,作业之间不受影响。



槽共享(Slot Sharing)



Flink允许子任务共享插槽,即使它们是不同任务(阶段)的子任务(subTask),只要它们来自同一个作业。比如图左下角中的map和keyBy和sink 在一个 TaskSlot 里执行以达到资源共享的目的。


允许插槽共享有两个主要好处:

1. 1. 资源分配更加公平,如果有比较空闲的slot可以将更多的任务分配给它。
2. 2. 有了任务槽共享,可以提高资源的利用率。

注意:


slot是静态的概念,是指taskmanager具有的并发执行能力


parallelism(平行)是动态的概念,是指程序运行时实际使用的并发能力


(5)运行时组件


Flink运行时架构主要包括四个不同的组件,它们会在运行流处理应用程序时协同工作:


作业资源管理器(JobManager): 分配任务、调度checkpoint做快照


任务管理器(TaskManager):主要干活的


资源管理器(ResourceManager):管理分配资源


分发器(Dispatcher):方便递交任务的接口,WebUI


因为Flink是用Java和Scala实现的,所以所有组件都会运行在Java虚拟机上。每个组件的职责如下:


作业管理器(JobManager)


1. 控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的JobManager 所控制执行。
2. JobManager 会先接收到要执行的应用程序,这个应用程序会包括:
   作业图(JobGraph)、逻辑数据流图(logical dataflow graph)和打包了所有的类、库和其它资源的JAR包。
3. JobManager 会把JobGraph转换成一个物理层面的数据流图,这个图被叫做“执行图”(ExecutionGraph),
    包含了所有可以并发执行的任务。
4. JobManager 会向资源管理器(ResourceManager)请求执行任务必要的资源,
  也就是任务管理器(TaskManager)上的插槽(slot)。
  一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上。
  而在运行过程中,JobManager会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调。

任务管理器(TaskManager)


1. Flink中的工作进程。通常在Flink中会有多个TaskManager运行,
   每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量。
2. 启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,
   TaskManager就会将一个或者多个插槽提供给JobManager调用。JobManager就可以向插槽分配任务(tasks)来执行了。
3. 在执行过程中,一个TaskManager可以跟其它运行同一应用程序的TaskManager交换数据。

资源管理器(ResourceManager)


1. 主要负责管理任务管理器(TaskManager)的插槽(slot),TaskManger 插槽是Flink中定义的处理资源单元。
2. Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN、Mesos、K8s,以及standalone部署。
3. 当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager。
  如果ResourceManager没有足够的插槽来满足JobManager的请求,
  它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。

分发器(Dispatcher)

1. 可以跨作业运行,它为应用提交提供了REST接口。
2. 当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager。
3. Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行的信息。
4. Dispatcher在架构中可能并不是必需的,这取决于应用提交运行的方式。

(6)Flink执行图(ExecutionGraph)


由Flink程序直接映射成的数据流图是StreamGraph,也被称为逻辑流图,因为它们表示的是计算逻辑的高级视图。为了执行一个流处理程序,Flink需要将逻辑流图转换为物理数据流图(也叫执行图),详细说明程序的执行方式。


Flink 中的执行图可以分成四层:StreamGraph(逻辑流图) -> JobGraph -> ExecutionGraph -> 物理执行图。

1. StreamGraph:是根据用户通过 Stream API 编写的代码生成的最初的图。用来表示程序的拓扑 [tuò pū] 结构。
2. JobGraph:StreamGraph经过优化后生成了 JobGraph,提交给 JobManager 的数据结构。
             主要的优化为,将多个符合条件的节点 chain 在一起作为一个节点,这样可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗。
3. ExecutionGraph:JobManager 根据 JobGraph 生成ExecutionGraph。方便调度和监控和跟踪各个 tasks 的状态。
                    ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。
4. 物理执行图:JobManager 根据 ExecutionGraph 对 Job 进行调度后,
             在各个TaskManager 上部署 Task 后形成的“图”,并不是一个具体的数据结构。

Flink执行executor会自动根据程序代码生成DAG数据流图


简单理解:


1. StreamGraph:最初的程序执行逻辑流程,也就是算子之间的前后顺序--在Client上生成
2. JobGraph:将OneToOne的Operator合并为OperatorChain--在Client上生成
3. ExecutionGraph:将JobGraph根据代码中设置的并行度和请求的资源进行并行化规划!--在JobManager上生成
4. 物理执行图:将ExecutionGraph的并行计划,落实到具体的TaskManager上,将具体的SubTask落实到具体的TaskSlot内进行运行。


相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
相关文章
|
3天前
|
运维 监控 API
后端开发中的微服务架构:优势与挑战
【8月更文挑战第16天】在软件开发的世界中,微服务架构已经成为一种流行和强大的设计模式。它通过将应用程序分解为一组小型、独立的服务来促进敏捷开发和快速迭代。本文旨在深入探讨微服务架构的核心优势以及实施过程中可能遇到的挑战,帮助读者更好地理解这一现代软件设计方法。
|
1天前
|
存储 缓存 Java
实时计算 Flink版操作报错合集之怎么处理在运行作业时遇到报错::ClassCastException
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
6天前
|
编解码 安全 Linux
基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究
这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。
|
7天前
|
消息中间件 设计模式 API
后端开发中的微服务架构设计原则
【8月更文挑战第13天】在软件工程的世界中,微服务架构已经成为一种流行的设计模式,它通过将复杂的应用程序分解成一组小的服务来简化开发和部署。本文探讨了微服务背后的设计理念,以及如何在后端开发实践中应用这些原则来构建可扩展、灵活且易于维护的系统。我们将深入讨论服务的划分、通信协议的选择、数据一致性的保障以及容错性策略的实施,旨在为后端开发人员提供一套实用的微服务架构设计指导。
18 1
|
7天前
|
负载均衡 监控 API
构建高效微服务架构:后端开发的新趋势
【7月更文挑战第43天】 在当今软件开发领域,微服务架构已成为推动技术创新与实现业务敏捷性的一股不可忽视的力量。本文旨在深入剖析构建高效微服务架构的核心原则、关键技术和实践挑战,为后端开发者提供一套行之有效的解决方案。通过精心设计的模块化服务、智能的服务发现机制、弹性的负载均衡策略以及持续的性能优化实践,我们能够确保系统的可扩展性、稳定性及快速响应市场变化的能力。文章将详细探讨如何通过容器化技术、服务网格、API网关等现代工具和框架,来构建和维护一个高效的微服务系统。
|
2天前
|
运维 监控 数据库
后端开发中的微服务架构:优势与挑战
【8月更文挑战第17天】在软件开发领域,微服务架构已成为构建复杂系统的重要方法。它通过将应用程序拆分成小型、独立的服务,提高了系统的可维护性、可扩展性和灵活性。然而,这种架构风格也带来了新的挑战,如服务间的通信、数据一致性和运维复杂性等。本文将深入探讨微服务架构的优势和面临的主要问题,并分析如何在实际应用中平衡这些利弊。
|
4天前
|
存储 缓存 Java
Eureka原理与实践:深入探索微服务架构的核心组件
在微服务架构日益盛行的今天,服务之间的注册与发现成为了保证系统高可用性和灵活性的关键。Eureka,作为Netflix开源的服务注册与发现框架,凭借其简单、健壮的特性,在微服务领域占据了举足轻重的地位。本文将深入剖析Eureka的原理,并通过实践案例展示其在实际项目中的应用,以期为开发者提供一个高端、深入的视角。
11 0
|
5天前
|
消息中间件 缓存 Kafka
图解Kafka:架构设计、消息可靠、数据持久、高性能背后的底层原理
【8月更文挑战第15天】在构建高吞吐量和高可靠性的消息系统时,Apache Kafka 成为了众多开发者和企业的首选。其独特的架构设计、消息可靠传输机制、数据持久化策略以及高性能实现方式,使得 Kafka 能够在分布式系统中大放异彩。本文将通过图解的方式,深入解析 Kafka 的这些核心特性,帮助读者更好地理解和应用这一强大的消息中间件。
20 0
|
7天前
|
消息中间件 缓存 NoSQL
探索后端开发:从基础到架构设计
在数字化浪潮的推动下,后端开发作为软件工程的核心领域,承载着数据处理、业务逻辑实现和系统性能优化的重要任务。本文旨在为初学者提供一个深入浅出的指南,从理解后端开发的基础知识出发,逐步引导至高级主题如服务端架构设计和性能优化。通过实际案例分析,我们将揭示如何将理论应用于实践,以及如何利用现代工具和技术提升开发效率和产品质量。无论你是初涉后端领域的新手,还是寻求进阶知识的开发者,这篇文章都将为你的职业成长之路提供宝贵的指导和灵感。
21 0
|
2天前
|
监控 负载均衡 API
从单体到微服务:架构转型之道
【8月更文挑战第17天】从单体架构到微服务架构的转型是一项复杂而系统的工程,需要综合考虑技术、团队、文化等多个方面的因素。通过合理的规划和实施策略,可以克服转型过程中的挑战,实现系统架构的升级和优化。微服务架构以其高度的模块化、可扩展性和灵活性,为业务的持续发展和创新提供了坚实的技术保障。