f基础入门1-- 基础架构的了解

flink入门

二、快速上手

1、pom文件中添加的东西

1、里面有两个依赖,一个就是flink-scala,我们要用的是scala语言进行写代码。还有一个就是flink-streaming-scala,也就是流的问题。
– !! 上面那两个依赖的记忆方式: 用Scala写flink代码、用Scala的流式写flink代码。
2、还有一个打包插件,就是关于Scala代码进行打包,注意里面的版本问题导致的代码运行失败的话,那么就修改版本。

   <dependencies>

            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-scala_2.12</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-streaming-scala_2.12</artifactId>
                <version>1.10.1</version>
            </dependency>

    </dependencies>

 <!-- 下面是打包插件 -->
    <build>

        <plugins>

            <!-- 该插件用于将Scala 代码编译成class 文件 -->

            <plugin>

                <groupId>net.alchim31.maven</groupId>

                <artifactId>scala-maven-plugin</artifactId>
                <version>3.2.2</version>

                <executions>

                    <execution>

                        <!-- 声明绑定到maven 的compile 阶段 -->

                        <goals>

                            <goal>compile</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-assembly-plugin</artifactId>

                <version>3.0.0</version>

                <configuration>

                    <descriptorRefs>

                        <descriptorRef>jar-with-dependencies</descriptorRef>

                    </descriptorRefs>

                </configuration>

                <executions>

                    <execution>

                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>

                            <goal>single</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

        </plugins>

    </build>

2、 添加scala文件夹

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标记为源文件目录
在这里插入图片描述
然后就可以在下面创建对应的Scala的class。
在这里插入图片描述
如果要创建一个可执行的程序的话,那么不要创建类,创建一个单例对象。
在这里插入图片描述

在这里插入图片描述

3、批处理代码

批处理的话,需要一个提前准备好的文件,从这个文件中读取数据,也就是需要一个数据文件。
在这里插入图片描述
创建一个文本文件。在这里插入图片描述

在这里插入图片描述
文本中添加内容

hello
thanks
yes ok
shanghai
beijing
hello
shanghai
shanghai
yes ok

代码

把scala下面的对应的隐式转换引入。
import org.apache.flink.api.scala._ //把这个放到代码上面。


package com.atguigu.wc

import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.api.scala._


object wordcount {
  def main(args: Array[String]): Unit = {

    //创建一个批处理
    //创建执行环境,因为当前是分布式处理,并不是一个单机的程序,直接读进来。现在是分布式的环境。所以必须创建执行环境,也就是类似于上下文。

        val env =  ExecutionEnvironment.getExecutionEnvironment

  // 从文件中读取数据。将本地文件的地址作为一个字符串变量。
       val inpath = "D:\\code_put\\flink_tuturial\\src\\main\\resources\\hello.txt"

//当前是批处理,那么定义一个dataset,基于当前的执行环境调用一个方法。要进行读文件。
 //输入的变量是代表本地文件地址的变量。
     val inputDataSet = env.readTextFile(inpath)

   //对数据进行转换处理统计
   //先分词,然后按照Word进行分组,最后进行聚合统计。
   val resultDataSet = inputDataSet
     .flatMap(_.split(" "))
     .map((_, 1))
     .groupBy(0)
     .sum(1)
    
     //打印输出
      resultDataSet.print()
    
  }

}

Scala的风格,就是先写变量然后写方法名,也就是变量.方法名,然后得到一个新的变量。
inputDataSet就理解为类似于set,文本文件作为一个string类型的变量,作为dataset类型肯定是里面只有一个元素,也就是初始的文本。
用flatmap进行改变结构。然后进行切割之后,于是就有了很多的元素,也就是一个存放string类型的集合,里面多了一些元素。
对集合中的每个元素都变成子集合,也就是(xxx,1),这种形式。也就是此时的dataset[(string,int)]就是 ( (xxx,1),(xxx,1),(xxx,1),(xxx,1)…(xxx,1) )。

在这里插入图片描述

flatMap = map + flatten
就按照上面的例子,inputDataSet代表的是一个string类型的字符串,如果用map 进行切割操作的话,将会得到的是 ((xxx),(xxx),(xxx),…(xxx)),也就是集合里面包含了一个一个小的集合,这就是map得到的隐射结果。接着flat的话,就会成为一个大的集合,里面的小的集合就拼接在一起了,就是进行一个拼接。(xxx,xxx,xxx,xxx…xxx)
如果是用flatMap 的话,就是直接转换成 (xxx,xxx,xxx,xxx…xxx)。

4、流处理代码

流处理的特点: 有头没尾,源源不断的进行处理,来一个处理一个,低延迟,实时处理结果。

还是在上面相同的包下面,创建一个新的class,用来演示流处理。

package com.atguigu.wc

import org.apache.flink.streaming.api.scala._
//注意这里是流的,隐式转换也要有streaming。

object StreamWordCount {

  def main(args: Array[String]): Unit = {

    //创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

   //创建一个socket文本流
   val inputStream   =  env.socketTextStream("hadoop102", 7777)


    val value = inputStream.flatMap(_.split(" ")).filter(_.nonEmpty).map((_, 1)).keyBy(0).sum(1)

     value.print()

     //启动任务
    env.execute("12345")   //可以给当前的作业起一个名字,是一个字符串的形式。
  }

}

开启hadoop102这个虚拟机,然后用xshell连接,然后输入 nc -lk 7777
在这里插入图片描述

然后就立刻就会出现这个计算结果。
在这里插入图片描述

并行子任务&&并行度的设置

前面的小数子的含义是:flink本身是一个分布式的架构,当前执行的时候,默认是可以做并行执行的。这里的数字表示在哪个并行的子任务上,也就是并行子任务的序号。这个默认的数字就是当前机器的默认核数。hadoop102这个虚拟机设置的核数的时候就是8,那么会出现1、2、3、4、5、6、7、8这八个数字。

针对当前的执行环境,然后可以设置一个并行度,也就是设置配置并行的线程。

  val env = StreamExecutionEnvironment.getExecutionEnvironment
  env.setParallelism(2)      //紧跟着环境的位置。这里是属于全局设置。

那么每个对应的输出执行在哪个线程上呢??

按照当前Word的hash值去做分配。

可以观察到,同一个单词,肯定是在同一个线程中的,线程编号都是同一个。
在这里插入图片描述
其实主要是出在keyby上,代码中做了keyby处理。进行做分组,在并行试架构中是怎么做分组的呢?
map处理完,后面并行的也有很多个sum,要进行分组,也就是每个map出来的数据要分发到哪个sum中呢?那么keyby是怎么分组的呢??
同一个key的话,就让它放到同一个sum任务中进行做统计。也就是上游同一个key的不同任务发送到下游的同一个任务中去。这个过程就是相当于一个数据重分区的过程。是基于当前key的hashcode,但是并不完全是以hashcode作为分区号,我们知道求hash的那个值很大的,提供的并行任务就是那么几个,自己设置的就是8个。最后有一个类似取余的过程。最后就得到一个并行子任务的编号。
同一个key的数据来了之后,经过hash运算,然后经过取模,总会分配到同一个子任务中去。不同的key也可能分发到同一个子任务中,毕竟可能hash值相同。

在这里插入图片描述

算子设置并行度

每个算子每个任务都是可以认为是独立的。

    val value = inputStream.
           flatMap(_.split(" ")).        //默认是8个并行度
           filter(_.nonEmpty).
           map((_, 1)).setParallelism(3).       // 这里map设置的并行度是3
           keyBy(0).
           sum(1).setParallelism(2)    //这里sum设置的并行度是2

在这里插入图片描述

动态设置端口的参数

点击 —编辑配置。
在这里插入图片描述
在这个位置进行输入

–host hadoop102 --port 7777
注意的是–与host和port之间不能有间隔。

在这里插入图片描述
如下所示,然后点击apply,点击OK。
在这里插入图片描述
代码部分

package com.atguigu.wc

import org.apache.flink.api.java.utils.ParameterTool
import org.apache.flink.streaming.api.scala._
//注意这里是流的,隐式转换也要有streaming。

object StreamWordCount {

  def main(args: Array[String]): Unit = {
  
    //创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    val parameter = ParameterTool.fromArgs(args)
    val host = parameter.get("host")
    val port = parameter.getInt("port")

   //创建一个socket文本流
   val inputStream   =  env.socketTextStream(host,port)
   
    val value = inputStream.
           flatMap(_.split(" ")).        
           filter(_.nonEmpty).
           map((_, 1)).
           keyBy(0).
           sum(1)

     value.print()

     //启动任务
    env.execute()
  }

}

打印时设置并行度为1

因为是并行的,所以是几乎同时进入当前这个系统中,后面进行传输的过程中,到达不同子任务对应的分区,然后就会导致乱序。
分布式架构带来的数据乱序,哈哈,可能说全局并行度设置为1(也就是在执行环境之后,立马设置全局并行度),所有的都是一条线,那肯定是有序的,但是这对于高吞吐的分布式架构,有什么意义呢??没意义。高并发和高吞吐就做不了了。

在这里插入图片描述

代码

package com.atguigu.wc

import org.apache.flink.api.java.utils.ParameterTool
import org.apache.flink.streaming.api.scala._
//注意这里是流的,隐式转换也要有streaming。

object StreamWordCount {

  def main(args: Array[String]): Unit = {


    //创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    val parameter = ParameterTool.fromArgs(args)
    val host = parameter.get("host")
    val port = parameter.getInt("port")

   //创建一个socket文本流
   val inputStream   =  env.socketTextStream(host,port)


    val value = inputStream.
           flatMap(_.split(" ")).
           filter(_.nonEmpty).
           map((_, 1)).
           keyBy(0).
           sum(1)

     value.print().setParallelism(1)

     //启动任务
    env.execute()
  }
}

发现前面的子任务的编号没有了,因为最后打印这一步的并行度是1,也就是最后一步只有一个线程。
有一些需要外部文件写入的操作,最后也得设置并行度是1,往同一个文件写入,防止发生错误。
在这里插入图片描述

三、flink架构的部署

1、flink的安装与修改配置文件

一)、提前准备好的flink的压缩包

在这里插入图片描述
进入到software文件夹中,然后将这压缩包拖进去。
在这里插入图片描述

然后进行解压缩,将解压后的文件放到module文件夹中。

[atguigu@hadoop102 software]$ tar -zxvf flink-1.10.1-bin-scala_2.12.tgz -C /opt/module/

然后 进入到module中

[atguigu@hadoop102 opt]$ cd software/
[atguigu@hadoop102 software]$ cd …/module/
[atguigu@hadoop102 module]$ ll

解压后的文件
在这里插入图片描述

然后进入flink-1.10.1的bin目录下

[atguigu@hadoop102 module]$ cd flink-1.10.1/
[atguigu@hadoop102flink-1.10.1]$ cd bin
[atguigu@hadoop102 bin]$ ll
在这里插入图片描述

二)、修改conf中yaml的参数,设置jobmanager是哪个节点

然后进入flink-1.10.1的conf目录下
[atguigu@hadoop102 bin]$ cd …/conf
[atguigu@hadoop102 conf]$ ll
打印日志有两种格式
在这里插入图片描述

我们需要把yaml文件进行修改。

在这里插入图片描述

在这里插入图片描述

jobmanager.rpc.address: hadoop102 //配置jobmanager
taskmanager.numberOfTaskSlots: 2 //生产环境中根据资源进行修改。

然后进行关闭。

三)、修改conf中slaves的参数,填写所有的节点名称
   也就是哪些节点参与分布式架构之中。

在这里插入图片描述
把机器的节点输入进去。
在这里插入图片描述

四)、将flink的文件夹分发到集群其他的节点

[atguigu@hadoop102 conf]$ cd …/
[atguigu@hadoop102 flink-1.10.1]$ cd …/
[atguigu@hadoop102 module]$ xsync flink-1.10.1/

2、standalone模式

1)、启动

在flink的目录下,进行启动

[atguigu@hadoop102 flink-1.10.1]$ bin/start-cluster.sh

在这里插入图片描述
启动起来以后,就可以在网页上输入了。

hadoop102:8081

在这里插入图片描述

这里我们可以看到之前我们设置的东西
taskmanager的个数是3,也就是之前在slaves中设置的3台机器节点,也就是flink集群中有几个节点。
total task slots的个数是6,因为我们设置单个的taskmanager的slot的个数是2,集群中有3个节点,所以个数是6个。
Available Task Slots的个数是6,因为现在还没有运行任务,处于闲置状态,所以是6个。

点开里面就有各个节点的信息。jobmanager的,以及taskmanager的节点信息。
在这里插入图片描述

2)、页面提交job

编译
在这里插入图片描述
打包
在这里插入图片描述

这个jar包是我们要的。复制到桌面上,然后上传的时候直接在桌面上进行上传该jar包。
在这里插入图片描述

上传jar包

在这里插入图片描述

点击这个jar包
在这里插入图片描述

复制一下包名加类名
在这里插入图片描述

在这里插入图片描述

点开执行计划,可以看一下。
在这里插入图片描述

读取数据源的并行度默认就是1,这个算子默认的并行度就是1。这个是算子级别的并行度设置,只不过是默认的设置。
最后一个位置sink的并行度也是1,因为我们在代码中进行设置了。
在代码中,其他位置我们没有设置并行度,那么就以提交job页面的那个设置的并行度为主。如果提交页面也没有,那么就以配置文件中的设置为主。(因为这是运行环境,并不是开发环境,如果是开发环境的话,默认的话就是CPU核数。)

在这里插入图片描述

其实关于并行度的问题
算子的并行度 > 环境设置的并行度(代码中全局设置) > 提交job页面设置的并行度 > 配置文件中的并行度
解释:环境设置并行度,这里设置的是代码中每个算子的默认并行度。

关于环境设置的并行度
开发环境中: 默认的话是cpu核心数 。
生产集群运行环境中: 如果每个算子没有单独设置并行度,而且代码的全局也没有设置并行度,那么就以提交job的时候,设置的并行度为准。

在提交之前先把端口打开,然后再在job提交页面进行submit。
在这里插入图片描述
然后输入一些数据
在这里插入图片描述
因为是在taskmanager中进行计算的(main代码中的每一步是如何定义的,是在jobmanager中做的,数据来了真正执行是在taskmanager中执行的),所以我们要点开taskmanager进行观察。

在这里插入图片描述
点开进去之后,然后点开stdout,然后就可以看见数据了。
在这里插入图片描述

3)、命令行提交job

将jar包放到一个地方中,然后写上这个路径。

[atguigu@hadoop102 bin]$ ./flink run -c com.atguigu.wc.StreamWordCount -p 2 /opt/module/save_jars/flink_tutiorial-1.0-SNAPSHOT-jar-with-dependencies.jar
–host hadoop102 --port 7777

在这里插入图片描述
在端口中输入数据。
在这里插入图片描述

然后看到一个任务在运行。
在这里插入图片描述
数据所在的节点(就是free slots比all slots要少,说明正任务正在这个节点中进行运行)
在这里插入图片描述
看到了数据。
在这里插入图片描述

命令行的常见命令
查看正在运行的任务id

先进入到flink的bin目录下,显示的那一串数字夹带字母的就是任务id
[atguigu@hadoop102 bin]$ ./flink list
Waiting for response…
------------------ Running/Restarting Jobs -------------------
08.09.2021 17:30:51 : fff1b437f0026f72d65d99941b9ebe9c : Flink Streaming Job (RUNNING)
-------------------------------------------------------------- No scheduled jobs.

停掉正在运行的任务

先进入到flink的bin目录下,然后执行命令,cancel后面是任务id。
[atguigu@hadoop102 bin]$ ./flink cancel fff1b437f0026f72d65d99941b9ebe9c

在这里插入图片描述

看已经运行完的、失败的、正在运行的任务

> [atguigu@hadoop102 bin]$  ./flink list -a 
> Waiting for response... No
> running jobs. No scheduled jobs.
> ---------------------- Terminated Jobs -----------------------
> 08.09.2021 15:47:08 : 8499b0037fff99110b710301954aed9e : Flink Streaming Job (CANCELED)
> 08.09.2021 17:30:51 : fff1b437f0026f72d65d99941b9ebe9c : Flink Streaming Job (CANCELED)
> --------------------------------------------------------------

关闭掉集群
taskmanager和jobmanager都关掉了。

[atguigu@hadoop102 bin]$ ./stop-cluster.sh
Stopping taskexecutor daemon (pid: 2639) on host hadoop102.
Stopping taskexecutor daemon (pid: 2176) on host hadoop103.
Stopping taskexecutor daemon (pid:2167) on host hadoop104.
Stopping standalonesession daemon (pid: 2256) on host hadoop102.

在这里插入图片描述

3、Yarn模式(生产环境中常见)

yarn的这种模式,是属于容器化的资源管理平台。

以 Yarn 模式部署 Flink 任务时, 要求 Flink 是有 Hadoop 支持的版本, Hadoop 环境需要保证版本在 2.2 以上, 并且集群中安装有 HDFS 服务。

之前standalone模式的话,需要直接需要bin/start-cluster.sh。部署在yarn上的话,那么这个flink集群就是由yarn来启动。

Session-cluster模式

Session-cluster模式,也叫会话模式。
先在yarn上创建一个yarn-session,然后通过yarn-session先启动一个flink集群。然后就在这个集群里面提交作业。提交在一个yarn-session里面的job,特点就是资源是共享的,适合规模比较小的,执行时间有限的作业。
这种就是相当于一堆job放在一个集群上面去运行,有点类似于standalone模式。

准备工作
将下面这个jar包,扔到 /opt/module/flink-1.10.1/lib 里面。

在这里插入图片描述
如果缺少这个包的话,会有如下的错误爆出。
在这里插入图片描述

启动

1、启动hadoop集群
2、启动 yarn-session (相当于此时启动一个flink集群)

[atguigu@hadoop102 module]$ cd flink-1.10.1/
[atguigu@hadoop102flink-1.10.1]$ cd bin
[atguigu@hadoop102 bin]$ ll

在这里插入图片描述

 ./yarn-session.sh      -s   4      -jm 1024     -tm 1024     -nm test    -d

然后就是跳出一个web网址。这个网址是打开flink的web页面。

在这里插入图片描述

其中:
-jm: JobManager 的内存( 单位 MB)。
-tm: 每个 taskmanager 的内存( 单位 MB)。
-nm: yarn 的 appName(现在 yarn 的 ui 上的名字)。
-d: 后台执行。

提交命令行的优先级是高于配置文件中的设置,显然这里是起作用了。

都是动态的。在提交任务之前都是0。
在这里插入图片描述

3、提交job
就按照之前命令行提交job的方式一模一样。

./flink run -c com.atguigu.wc.StreamWordCount
/opt/module/save_jars/flinkTutorial-1.0-SNAPSHOT-jar-with-dependencies.jar --host hadoop102 --port 7777

提交之后就看到任务的id。
在这里插入图片描述

提交之后就动态的提供了slots数目和taskmanager的数目。
在这里插入图片描述

也可以在web页面中看到任务id。
在这里插入图片描述

在这里插入图片描述

4、去yarn 控制台查看任务状态
hadoop103:8088

就可以看到任务id

application_1632635957937_0001
在这里插入图片描述

在开启yarn-session的时候,就能看到对应的任id。
在这里插入图片描述

5、取消yarn-session

yarn application --kill application_1632635957937_0001

这样的话,就是关闭了yarn-session。变成了history,也就是成为了历史,也就是关闭了。
在这里插入图片描述

per-job模式

这种模式并不会一开始就创建集群,而是yarn中等待提交job。job提交完之后,然后按照当前的每一个job,去创建一个flink集群。这个过程就是相当于每个job独占一个flink集群。不同的job之间彼此互不影响,都是独占的,只要yarn有资源,等待yarn的分配,然后拿过来就用。
单独一个作业,一个集群。适合长时间运行不结束的作业。

启动

1、启动hadoop集群
2、直接启动job

./flink run –m yarn-cluster
-c com.atguigu.wc.StreamWordCountFlinkTutorial-1.0-SNAPSHOT-jar-with-dependencies.jar --host hadoop102 --port 7777

./flink run                   表示要进行启动
–m   yarn-cluster             根据yarn给当前的job起一个集群,也就是per-job模式。
-c    com.atguigu.wc.StreamWordCountFlinkTutorial-1.0-SNAPSHOT-jar-with-dependencies.jar             打包的类名
--host hadoop102  --port 7777      机器号以及端口号

四、Flink 运行架构

1、Flink 运行时的组件

jobmanager

jobmanager就是作业管理器,接受提交上来的打包好的代码jar包。然后分析里面的处理流程。然后生成一个最后可以执行的执行图。然后将作业分成每个可以执行的task,然后分发给taskmanager。
还会负责协调做检查点,checkpoint。

taskmanager

taskmanager就是任务管理器,具体干活的就是taskmanager,要进行计算。
每一个taskmanager里面的计算资源,主要是内存和CPU,划分的时候,CPU是没有办法隔离的。
所以对于taskmanager划分资源,主要是对内存进行一个隔离处理,每一部分就叫做一个slot,slot是taskmanager里面最小化的资源单位。

resourcemanager

resourcemanager就是资源管理器,主要是管理整个集群的资源,集群里面的资源就是slot。
资源管理器其实就是资源的调度,资源就是taskmanager,一个job任务,需要多少个TaskManager中的slot,然后就去资源管理器去申请,看看剩余空闲的slot数目能不能满足此时的job。
我们知道flink可以同时启动多个任务,也就是此时机器中的slot不一定有空闲。
所以jobmanager就要去资源管理器去看看taskmanager有没有空闲的slot,来支持这个job的进行。
那么这里提一下slot,taskmanager中设置几个slot比较好呢?
核数0.33,也就是本台机器是8核的话,设置为80.33 向上取整为3,也就是本台机器的slot数目为3个。

2、Flink 任务提交流程

在这里插入图片描述

3 、Flink 任务调度原理

taskmanager与slot

首先,我们要知道的是,一个算子就是一个task。所谓的subtask是因为这个算子的并行度并不是1,并行的子任务就是subtask。
每个taskmanager都是一个jvm进程,那么就是会独立的进行执行一个或者是多个subtask。
taskmanager含有一定的资源,这个资源就是slot。资源slot化意味着内存的隔离,没必要不同job之间的slot的竞争。
那么一个taskmanager设置几个slot呢?
这个有人说是 至少是: 核数033,也就是机器是8核的话,那么80.33向上取整得到3个slot。
这个设置几个是需要实践,就好比打个比方: 在门的总宽度 (内存)一样的前提下,一栋楼是开一扇大门(少量的slot),还是开多个小门(较多的slot),才能使人流流动的比较快呢?这显然是不能直接判断的,这个是需要实践之后才能判断的。

默认情况下, Flink 允许子任务共享 slot, 即使它们是不同任务的子任务( 前提是它们来自同一个 job)。 这样的结果是, 一个 slot 可以保存作业的整个管道。
task slot是静态的概念,是指的是taskmanager具有的并发执行的能力。

在这里插入图片描述

slot的数量其实是taskmanager内存划分的个数,划分成多少个,这就相当于决定了一个taskmanager同时可以并行的执行多少个task。也就是通过slot的数量可以控制当前taskmanager并行处理的能力。
这是一个静态的能力。

slot与并行度

在执行过程中, 一个流( stream) 包含一个或多个分区( stream partition), 而每一个算子( operator) 可以包含一个或多个子任务( operator subtask), 这些子任务在不同的线程、不同的物理机或不同的容器中彼此互不依赖地执行。
一个特定算子的子任务( subtask) 的个数被称之为其并行度( parallelism) 。一般情况下, 一个流程序的并行度, 可以认为就是其所有算子中最大的并行度。一个程序中, 不同的算子可能具有不同的并行度。
其中最大的算子的并行度就是这个流的并行度,也就是最后至少要用几个slot,是这里决定的。
如图,这个里面的算子中最大的并行度是2,所以任务的运行需求的slot至少是2个,任务才能进行。

在这里插入图片描述

设置并行度

第一个虚线上面: 当前资源的数量。推荐的配置是: 该台机器的CPU核数=该台机器的slot的数目。
第二个虚线上面: 默认情况下,啥并行度都不设置(代码以及提交的时候也没有),那么就是集群配置文件里面的定义的默认并行度。默认是1。这种就是大多数的资源没有利用起来,效率低。
第三个虚线上面: 更改配置文件里面的默认并行度 ; 或者是提交job的时候, - p这个参数设置为2 ; 或者是在web UI的界面上,是一样的原理;还有就是在代码中设置,全局设置并行度 或者 是每一个算子单独设置并行度。
优先级是: 范围越小,优先级越高;代码中设置的话,会覆盖掉所有的默认配置。
次之,就是提交任务时候的 -p 参数,次之,(生产环境)用集群的配置文件中的配置 (开发环境下,idea执行的时候,啥也不设置的时候,默认并行度就是,当前的运行机器的CPU核数)。


第一个虚线上面: 代码中全局设置为9,所有的slot里面,满满的排满每一个任务。因为是全局并行度是9.
第二个虚线上面: 适合文件输出,sink并行度设置为1比较安全。因为在并行的执行写出操作的时候,有可能有写入冲突的问题。sink只在一个slot中出现。
所有的任务做完sink之前的那一步,其他的taskmanager最后都要传到taskmanager3的slot中的sink任务,让它做输出操作。

数据传输形式

Stream 在算子之间传输数据的形式可以是 one-to-one(forwarding)的模式也可以是 redistributing 的模式, 具体是哪一种形式, 取决于算子的种类。
One-to-one:stream(比如在 source 和 map operator 之间)维护着分区以及元素的顺序。那意味着 map 算子的子任务看到的元素的个数以及顺序跟 source 算子的子任务生产的元素的个数、顺序相同, map、fliter、flatMap 等算子都是 one-to-one 的对应关系。
类似于 spark 中的窄依赖
Redistributing: stream(map()跟 keyBy/window 之间或者 keyBy/window 跟 sink 之间)的分区会发生改变。每一个算子的子任务依据所选择的 transformation 发送数据到不同的目标任务。例如,keyBy() 基于 hashCode 重分区、broadcast 和 rebalance 会随机重新分区,这些算子都会引起 redistribute 过程,而 redistribute 过程就类似于Spark 中的 shuffle 过程。
类似于 spark 中的宽依赖

在这里插入图片描述
图中,算子出现几次,说明并行度就是几。

1、source到flatmap的时候,并行度发生了变化,因此不能合并。
2、flatmap到agg,虽然并行度都是2,但是有key by,基于hashcode进行了重分区,这里不是one to one的操作,所以不能合并。
3、agg、sink的并行度都是2,且没有发生重分区的操作,因此是可以合并任务的。

并行子任务如何做分配?

在这里插入图片描述
根据执行计划图,算子A的并行度是4,那么分配4个slot中;算子B的并行度是4,那么分配4个slot中;算子C的并行度是2,那么分配2个slot中;算子D的并行度是4,那么分配4个slot中;算子E的并行度是2,那么分配2个slot中。
默认分配在哪个taskmanager中是随机的。

1、怎么实现并行计算??
代码中每一个算子调用,后面都可以直接设置一个并行度。设置并行度之后,就说明当前的算子可以并行执行。

2、流处理中需要多少个slot??
因为slot共享机制的存在,就是以算子中最大的并行度作为标准就可以了。把最大算子的并行度作为流处理的并行度,也就是至少要分配的slot数量。

3、job中的task数目和 job需要的slot个数的关系??

代码中的算子的task数目之和和slot的个数没有关系。
代码中每一个(task)算子中的最大并行度和slot的数目有关系,二者是因为前者需要那么多,所以后者提供那么多,也就是二者是相等的关系。

程序与数据流

所有的 Flink 程序都是由三部分组成的:Source 、Transformation 和 Sink。
Source 负责读取数据源, Transformation 利用各种算子进行处理加工, Sink 负责输出。
在运行时,Flink 上运行的程序会被映射成“ 逻辑数据流”( dataflows),它包含了这三部分。每一个 dataflow 以一个或多个 sources 开始以一个或多个 sinks 结束。dataflow 类似于任意的有向无环图( DAG)。在大部分情况下, 程序中的转换运算( transformations) 跟 dataflow 中的算子( operator) 是一 一对应的关系, 但有时候, 一个 transformation 可能对应多个 operator。

执行图

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

StreamGraph : 是根据用户通过 Stream API 编写的代码生成的最初的图。用来表示程序的拓扑结构。 (这里是最初的,根据代码,直接生成的一个算子一个task,也就是想象成流中一个算子指向下一个算子。)

JobGraph:StreamGraph 经过优化后生成了 JobGraph,提交给 JobManager 的数据结构。主要的优化为,将多个符合条件的节点 chain 在一起作为一个节点,这样可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗。
(在客户端提交之前,对代码做一些合并优化,然后去进行提交。)

ExecutionGraph : JobManager 根 据 JobGraph 生 成 ExecutionGraph 。
ExecutionGraph 是 JobGraph 的并行化版本, 是调度层最核心的数据结构。
(在jobmanager中,按照我们定义的并行度,然后把每一个任务进行拆开,任务之间的传输方式定义清楚,相当于现在是一个真正的可执行的任务,从哪个任务来到哪个任务去。)

物理执行图: JobManager 根据 ExecutionGraph 对 Job 进行调度后, 在各个
TaskManager 上部署 Task 后形成的“ 图”, 并不是一个具体的数据结构。
(jobmanager中的图分发发给各个taskmanager,taskmanager按照jobmanager中的图,进行执行。)

在这里插入图片描述

任务链

在这里插入图片描述

相同并行度的 one to one 操作,Flink相连的算子(task),链接在一起形成一个 task,原来的算子成为里面的一部分。将算子链接成 task 是非常有效的优化: 它能减少线程之间的切换、减少基于缓存区的数据交换 (上下游算子传递数据的时候,序列化与反序列化的开销), 在减少时延的同时提升吞吐量。链接的行为可以在编程 API 中进行指定,也就是在代码中进行指定。

在这里插入图片描述

全局禁止任务的合并

全局禁止任务链的合并,也就是一个task就是一个任务,不会再进行任务的合并。
在这里插入图片描述

某个任务合并的任务链都断开

当前的算子直接摘出来,禁止与前后的算子进行合并任务链。也就是前面也要断开,后面也要断开。
在这里插入图片描述

执行图的效果。不参与任务链的合并,前后都得断开。这样的话,任务数目就变多了。
在这里插入图片描述

某个任务合并的任务链从某个算子位置断开

任务链前后可以合并,中间拆开。想把一个任务断开成两个任务。

想在filter和map之间断开。
在这里插入图片描述

这样就开启一个新的任务链。
在这里插入图片描述

就是这个样子。从这个位置断开,成为两个任务。
在这里插入图片描述

某个算子单独使用一个slot

----- 某个算子开始属于不同的共享组

从某个算子之后都是一个共享组a,这个算子之前的是一个共享组。在同一个共享组之内的所有操作,他们可以共享slot。不同共享组之间的任务一定是分配在不同的slot中。
在这里插入图片描述

------ 某一个算子单独属于一个共享组,前后的算子还是属于一个共享组。

如果某个算子,想单独使用一个slot的话,也就是slot不进行共享,那么这个算子的前后算子的共享组是同一个就是。这种方式会导致需要使用的slot数目,这种就是:
每个共享组中的slot数目之和,就是启动任务所需要的slot数目。
在这里插入图片描述

总之,一个任务是不是能启动起来,就是看代码里面的算子中最大的并行度与可以利用的slot的数目的比较,如果是小于等于可以利用的slot的数目,那么是可以启动起来这个任务的;如果不是的话,那么就启动不起来。

flink任务调度原理

在这里插入图片描述

Flink program
根据代码(program code ),生成一个逻辑上的数据流图(datagflow graph),然后利用一个客户端,将这些东西发送出去。客户端可能是命令行也可能是web UI,反正是有这样一个接口,进行发送。
在发送的时候,将数据流图(datagflow graph)做一个简单的调整,有一些可以合并的操作,然后就合并在一起。所以在提交job之后,在运行的时候,会发现有一些任务是合并在一起的。
客户端将jar包,以及数据流图等。提交给jobmanager。

Jobmanager

jobmanager分析数据流图,分析并行度是几,每个任务有几个并行的子任务。然后把它拆开,然后就可以知道当前有多少个任务,然后判断有多少个slot,然后怎么分配。去resourcemanager申请资源,申请到资源之后。在图中,有两个taskmanager可以提供资源,每个taskmanager本身是有3个slot,这是一个静态的能力,也就是最多可以提供3个slot,来执行并行的任务。
图中需要4个slot去执行任务,jobmanager做了一个调度,分配了两个worker,上的两个slot。jobmanager给taskmanager传的是部署,取消操作。这些是由jobmanager发出指令到taskmanager,另外会做checkpoint存盘的机制。

taskmanager
与jobmanager实时返回心跳信息,做实际的任务计算。

疑问: 啥是开发环境? 啥是生产环境?
那个开发环境是idea连上了虚拟机的某一个节点。生产环境是打包上传到集群上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值