【Flink】【第四章】 运行时的相关概念


概念有点多,有点乱,还待整理

Streaming dataflow

在这里插入图片描述

  • Streaming dataflow = 一个应用程序
  • Streaming dataflow = source + transformation + sink

在这里插入图片描述
Source :

  • 流计算:可以使用来自消息队列或分布式日志(如 Apache Kafka 或 Kinesis)等流式源的实时数据。
  • 批计算:可以使用来自各种数据源的有限的历史数据。

Sink:

  • 应用程序生成的结果流可以发送到可以作为接收器连接的各种系统。

算子(Operator)

Flink 程序是并行和分布式的。

  • a stream has one or more stream partitions
  • each operator has one or more operator subtasks

The operator subtasks are independent of one another, and execute in different threads and possibly on different machines or containers.

1.算子的并行度

算子子任务的数量 = 算子并行度;

下图所示,上面的是整体视角,下面的是经过并行度拆分后的视角
在这里插入图片描述

2.数据传输模式

有了并行度的概念后,我们需要了解,数据在两个算子之间是怎样传递的?上游的算子A并行度1中的数据是去下游算子B的并行度1还是并行度2呢?

两种传输模式:

  • one-to-one (or forwarding) pattern
  • redistributing pattern

1.One-to-one
在这里插入图片描述

streams (for example between the Source and the map() operators in the figure above) preserve the partitioning and ordering of the elements. That means that subtask[1] of the map() operator will see thesame elements in the same orderas they were produced by subtask[1] of the Source operator.

2.Redistributing streams

算子的每个子任务会将数据发送到下游算子的不同子任务中,具体如何传递依赖于传输规则:

  • keyBy (which re-partitions by hashing the key)
  • broadcast (广播)
  • rebalance (which re-partitions randomly).

元素之间的顺序仅保留在每对发送subtask和接收subtask之间(例如,map() 的 subtask[1] 和 keyBy/window 的 subtask[2])

3. 并行度的设置

四种设置并行度方式的优先级

  1. 算子单独设置并行度(Operator.setParallelism())
  2. 代码全局设置(env.setParallelism)
  3. 提交job的时候设置 (或者web UI界面)
  4. 集群配置文件

算子的并行度如果没给,用全局,全局没给用命令行的,命令行也没给用配置文件的。

并行度优先级演示

Demo1:

public class Flink03_WordCount_Unbounded {
    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(4);//全局并行度4

        ParameterTool parameterTool = ParameterTool.fromArgs(args);
        String host = parameterTool.get("host");
        int port = parameterTool.getInt("port");

        //TODO 读取端口数据 无界流
        DataStream<String> inputDataStream = env.socketTextStream(host, port);

        KeyedStream<Tuple2<String, Integer>, Tuple> keyedStream = inputDataStream
                .flatMap(new Flink01_WordCount_Batch.MyFlatMapFunc()).setParallelism(3)
                .keyBy(0);

        DataStream<Tuple2<String, Integer>> wordCountDataStream = keyedStream.sum(1).setParallelism(2);
        wordCountDataStream.print("result"). setParallelism(1);
        env.execute("asd");
    }
}
  • 配置文件中并行度是1
  • Web 提交页面并行度设置:5
  • 全局并行度4
  • flatmap并行度为:3
  • Sum()并行度为:2
  • Print()并行度为1
    在这里插入图片描述

Demo2

  • 配置文件中并行度是1
  • Web 提交页面并行度设置:5
  • 全局并行度4
  • flatmat并行度为:3
  • Sum()并行度为:2
  • Print()并行度不设置

在这里插入图片描述

说明了如果算子不单独设置并行度,就会按照全局的并行度来,依次往上推。

Flink中并行度和Spark中分区的理解

  • Flink的并行度类似于Spark中的分区,不同的是flink基本所有算子都可以设置并行度,Spark只有部分算子可以设置分区数。注:flink中定义传输过程的算子是不能设置并行度的
  • 对于Spark来说,是按照有shuffle的算子来划分阶段的,没有shuffle的算子即使设置的分区个数不同,也会合并到一个stage中,而且每个阶段的并行度(分区数)只取决于该阶段最后一个算子的分区个数。
  • flink中如果算子指定了并行度不一样,那么会将这个算子单独算一个stage;所以flink的并行度是建立在算子的基础上,而Spark的分区是建立在stage的基础上。

任务链(Operator Chains)

1. 认识任务链

任务链就是将符合一定条件的算子合并成一个任务

在这里插入图片描述
在提交页面上看如下:一个蓝色框就是一个任务

一个任务就是一个Task

  • 一个任务的一个并行度就是一个subTask
  • 一个subTask就是一个线程,一个subTask占用一个slot;

下图中的示例数据流是用五个子任务执行的,因此有五个并行线程:
在这里插入图片描述
任务连减少了数据从线程到线程的切换和缓冲的开销,并在减少延迟的同时增加了总体吞吐量。

2. 算子合并成任务链的前提条件

多个算子符合如下条件可以被flink自动合并成任务链:

  1. 前后相连
  2. 并行度相同
  3. 前后关系为one to one
  4. 处在同一个共享组内

多个算子链接在一起形成一个任务,原来的算子成为任务的一部分;

链接的行为可以在编程API中进行指定:

  • .disableChaining:不允许此算子加入任务链
  • .startNewChain() 从当前算子开启任务链
  • env.disableOperatorChaining() 全局禁止任务链化

测试
在这里插入图片描述
图中任务链有3个Task

  • Task1和Task2因为并行度不同而不能合并;
  • Task2和Task3因为不是one-to-one而不能合并;

如果将filter算子并行度改为3,变为下图
在这里插入图片描述

3. Task、线程、subTask

  • 从计算逻辑上面看,最基本的计算单元就是一个算子,算子可以由其并行度拆成subTask,而一个subTask就是一个计算线程;
  • flink对Task进行了优化,将多个算子合并成一个任务,一个任务 = 一个Task,这意味着将多个计算线程合并成一个计算线程
    在这里插入图片描述

任务链和共享组的区别:

  • 共享组:多个算子共享slots
  • 任务链:将多个算子合并为一个大算子,其实是将subTask合并为一个Task

对比Spark:
Flink中的任务链相当于Spark中的Stage,Spark中的Stage的划分只需要满足OneToOne,一个stage中所有算子的并行度暴力合并,按照Stage中最后一个RDD的分区数作为当前stage中所有算子的并行度,所以spark中一般不设置算子的分区数,没屌用。

4. 任务链的优势

  • 减少线程切换
  • 减少序列化和反序列化
  • 减少数据在缓冲区的交换
  • 减少延迟提高吞吐力

缺点:

  • 可能让N个比较复杂的业务跑在一个Slot中,本来一个业务就慢,如此更慢了,可以通过startNewChanin()或者disableChaining()或者全局禁用disableOperatorChaining()给分开

5. WebUI页面查看任务

  • 在webUI页面中,一个蓝色的框表示一个任务
  • 每个任务的并行度决定了当前任务的subTask个数
    在这里插入图片描述
    本质上来说,一个subTask就是一个计算单元,因此subTask叫做Task,一个任务有多个并行度,一个并行度对应一个Task

Flink任务执行图

在这里插入图片描述
一个subTask对应一个Thread

Slot 和 Slot共享组

什么是Slot?

  • Slot是内存;
  • 假如一个TaskManager有三个slot,那么它会将其管理的内存分成三份给各个slot;

需要注意的是,这里不会涉及到CPU的隔离,slot目前仅仅用来隔离task的受管理的内存。

为什么要将内存划分为slot?

(1)内存隔离

资源slot化意味着一个subtask将不需要跟来自其他jobsubtask竞争被管理的内存

(2)Slot意味着TaskManager的并发能力

  • 一个TaskManager进程的并行能力上限由Core个数限制
  • Slot之间运行的任务是相互独立的,Slot个数 < Core,那么就是并行;
  • Slot > Core ,Slot之间的任务就是并发;

Slot 共享组

共享组决定了哪些算子可以共享Slot,决定了SubTask能否在一个slot执行;

flink提供了两个实现类,用于设置共享组:

1.SlotSharingGroup

  • 用于DataStreamAPI
  • 用来实现slot共享的类,它尽可能地让subtasks共享一个slot
  • 保证同一个group中并行度的相同的subtasks共享同一个slot
  • 算子默认的group为default(即默认一个job下的subtask都可以共享一个slot)
  • 为了防止不合理的共享,用户能通过API来强制指定operator的共享组(.slotSharingGroup(“xxx”) 指定共享组)
  • 如果算子没有设置group,则其group和上游算子相同
  • 适当设置group可以减少每个slot运行的线程数,从而整体减少机器负载

测试

测试环境

三台TaskManager;
每个TaskManager的slot个数为2,默认并行度设置为1;

Demo1

在这里插入图片描述
在这里插入图片描述
结果分析:当前job只需要一个slot,因为所有算子都属于同一个共享组(不设置,则属于默认的共享组)

Demo2

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当前job用了4个slot;因为当前job的四个算子分别属于不同的共享组,不同的共享组的算子之间的slot是不能够共享的,所以1+1+1+1=4;

一个应用需要多少个Slot

一个job的slot的数量:每个共享组中最大并行度的和
在这里插入图片描述

任务链和共享组总结

  • 一个Slot可以运行多个task
  • 为了拓扑结构更加高先运行,flink提出了Chaining,尽可能的将operators 链接在一起作为一个Task
  • 为了资源更充分利用,Flink又提出了SlotSharingGroup,尽可能让多个task共享一个slot

执行图(ExecutionGraph)

Flink 中的执行图可以分成四层:

  • StreamGraph
  • JobGraph
  • ExecutionGraph
  • 物理执行图

StreamGraph

  • client端生成;
  • 算子原封不动的流程图;
  • 表示程序的拓扑结构。

JobGraph

  • client端生成;
  • 将多个符合条件的算子合并成一个任务链从而生成了JobGraph
  • 是提交给 JobManager 的数据结构。

算子合并成任务链:可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗。

ExecutionGraph

  • JobManager端生成;
  • ExecutionGraph是JobGraph的并行化版本;是调度层最核心的数据结构。

物理执行图

JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的“图”,并不是一个具体的数据结构。
在这里插入图片描述

  1. StreamGraph:完全按照代码来,一个算子一个节点
  2. JobGraph: 根据共享组,合并算子
  3. ExecutionGraph:根据共享组内的并行度,将算子拆成多个Task
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Flink的流计算作业的运行长统计可以通过以下步骤来实现: 1. 启用Flink的Metrics系统:在Flink的配置文件中,确保已启用Metrics系统并配置适当的报告器(如Prometheus、Graphite等)。这将使Flink开始收集作业的指标数据。 2. 注册自定义的Metrics:在你的流计算作业中,你可以使用Flink提供的Metrics API来定义和注册自定义的指标。例如,你可以注册一个用于统计作业运行长的计数器。 3. 记录作业开始和结束间:在你的作业代码中,在作业启动记录开始间,作业结束记录结束间。可以使用Flink提供的`ExecutionEnvironment#getExecutionStartTime()`和`ExecutionEnvironment#getExecutionEndTime()`方法来获取作业的开始和结束间。 4. 使用Metrics数据进行统计:使用Flink的Metrics API,你可以在作业运行期间定期获取和处理指标数据。在指标数据中,你可以获取到自定义的Metrics值以及其他内置指标值。你可以根据需要,计算和统计作业的运行长。 5. 输出或展示统计结果:根据你的需求,你可以选择将统计结果输出到日志、数据库或其他外部系统中,或者将结果展示在监控工具(如Grafana)中。 以上步骤提供了一个基本的框架来实现流计算作业的运行长统计。具体实施方法可能会因为使用的Metrics报告器和版本而有所差异,请根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值