以Flink源码中自带的WordCount为例,执行的入口从用户程序的execute()函数入手,execute()的源码如下:

 public JobExecutionResult execute(String jobName) throws Exception {
StreamGraph streamGraph = getStreamGraph();
streamGraph.setJobName(jobName);
JobGraph jobGraph = streamGraph.getJobGraph();
. . . . . . .
LocalFlinkMiniCluster exec = new LocalFlinkMiniCluster(configuration, true);
try {
exec.start();
return exec.submitJobAndWait(jobGraph, getConfig().isSysoutLoggingEnabled());
}
finally {
transformations.clear();
exec.stop();
}
}

  函数内部主要有getStreamGraph()、getJobGraph()、exec.start()、exec.submitJobAndWait()等。getStreamGraph()的作用是生成StreamGraph图,getJobGraph()的作用是生成JobGraph的图,exec.start()的作用是建立Client、JobManager、TaskManager三者之间通信初始化,exec.submitJobAndWait()的作用提交job并且等待job执行后的结果,该函数提供了任务执行调度执行的入口,进入Client类中,首先执行createUserCodeClassLoader()函数,创建用户代码的加载器,然后执行jobClient.SubmitJobAndWait(),进入JobClient类,在函数内部会执行submit函数,从该函数开始进入AKKA通信阶段,首先会进入JobClientActor,会创建一个jobclientActor来对JobManager和client进行通信,当通信对象创建之后,会执行akka机制的ask函数,该函数的作用是发出一个消息,然后要求收到方给予回复。当消息发出之后,OnReceive()函数会收到actor发出的消息请求,然后调用handleMessage()方法来处理消息请求,该函数内部有connectToJobManager()方法,此方法内部的tryToSubmitJob()函数是正式提交任务的操作,主要做的工作就是uploadUserJars()上传用户程序的jar文件,接着会jobManager.tell()向JobManager发出一个submit消息请求。

  当JobManager收到Client发送的消息之后,会执行JobManager内部的submitJob方法,

 case SubmitJob(jobGraph, listeningBehaviour) =>
val client = sender() val jobInfo = new JobInfo(client, listeningBehaviour, System.currentTimeMillis(),
jobGraph.getSessionTimeout)
log.info("liuzf---开始执行JobManager的submitJob()")
submitJob(jobGraph, jobInfo)

 首先会把由client收到的job信息封装在jobinfo中,然后把jobinfo以及job的任务图jobGraph一起发送给submit()去执行,在JobManager的submit函数中处理的函数逻辑比较复杂,比较重要的函数执行过程如下:

 private def submitJob(jobGraph: JobGraph, jobInfo: JobInfo, isRecovery: Boolean = false): Unit = {
try {
libraryCacheManager.registerJob(jobGraph.getJobID, jobGraph.getUserJarBlobKeys,
jobGraph.getClasspaths)
}
val userCodeLoader = libraryCacheManager.getClassLoader(jobGraph.getJobID) }
executionGraph = ExecutionGraphBuilder.buildGraph()
try {
submittedJobGraphs.putJobGraph(new SubmittedJobGraph(jobGraph, jobInfo))
jobInfo.notifyClients(
decorateMessage(JobSubmitSuccess(jobGraph.getJobID)))
log.info(s"开始调度 job $jobId ($jobName).")
executionGraph.scheduleForExecution()

  首先执行libraryCacheManager.registerJob(),向CacheManager进行注册,请求缓存,然后执行getClassLoader()来加载用户的代码加载器,接下来会调用ExecutionGraph中的buildGraph()构造ExecutionGraph的并行化版本的执行图,当逻辑执行图构造完毕之后,这时候可以通知Client任务已经成功提交,并且提交过程结束。接下来会调用sheduleForExecution()来会整体的资源进行调度分配,主要是每个TaskManager中的slot的分配,并且当slot分配完成之后,所有的task的任务状态发生改变,由CREATEDàSCHEDULED。接下分配完之后,接下来执行depolyToSlot()函数,就要进入部署状态,同样会执行transitionState()函数,将SCHEDULED状态变为DEPOLYING状态,接着的重要函数是shumitTask()函数,该函数会通过AKKA机制,向TaskManager发出一个submitTask的消息请求,TaskManager收到消息请求后,会执行submitTask()方法,该函数的重要执行过程如下:

 public submitTask(){
val task = new Task(. . . .)
log.info(s"Received task ${task.getTaskInfo.getTaskNameWithSubtasks()}")
val execId = tdd.getExecutionAttemptId
val prevTask = runningTasks.put(execId, task)
if (prevTask != null) {
runningTasks.put(execId, prevTask)
throw new IllegalStateException("TaskM}anager already contains a task for id " + execId)
}
task.startTaskThread()
sender ! decorateMessage(Acknowledge.get())
}

  首先执行Task的构造函数,生成具体物理执行的相关组件,比如ResultPartition等,最后创建执行Task的线程,然后调用startTaskThread()来启动具体的执行线程,Task线程内部的run()方法承载了被执行的核心逻辑,该方法具体的内容为:

 public void run() {
while (true) {
ExecutionState current = this.executionState;
if (current == ExecutionState.CREATED) {
if (transitionState(ExecutionState.CREATED, ExecutionState.DEPLOYING)) {
break;
}
}
invokable = loadAndInstantiateInvokable(userCodeClassLoader, nameOfInvokableClass);
network.registerTask(this);
Environment env = new RuntimeEnvironment(. . . . );
invokable.setEnvironment(env);
// ----------------------------------------------------------------
// actual task core work
if (!transitionState(ExecutionState.DEPLOYING, ExecutionState.RUNNING)) {
}
// notify everyone that we switched to running
notifyObservers(ExecutionState.RUNNING, null);
executingThread.setContextClassLoader(userCodeClassLoader);
// run the invokable
invokable.invoke(); if (transitionState(ExecutionState.RUNNING, ExecutionState.FINISHED)) {
notifyObservers(ExecutionState.FINISHED, null);
}
Finally{
// free the network resources
network.unregisterTask(this);
// free memory resources
if (invokable != null) {
memoryManager.releaseAll(invokable);
}
libraryCache.unregisterTask(jobId, executionId);
removeCachedFiles(distributedCacheEntries, fileCache);

  首先执行transitionState()函数将TaskManager的状态由CREATED转变为DEPOLYING状态,然后调用loadAndTrantiateInvokable()对用户代码打包成jar包,并且生成用户代码加载器,然后执行network.registerTask(),执行该函数之前,会执行NetworkEnvironment的构造函数,该类是TaskManager通信的主对象,主要用于跟踪中间结果并负责所有的数据交换,在该类中会创建协助通信的关键部件,比如网络缓冲池,连接管理器,结果分区管理器,结果分区可消费通知器等。当网络对象准备完成后,创建一个运行环境,然后执行invoke.setEnvironment(env),将各种配置打包到运行环境中。

  当运行环境准备之后,接下来到了具体分析任务执行的时候,首先会调用transitionState()函数将任务状态由DEPOLYING改为RUNNING状态,然后会调用notifyObservers()通知所有的task观察者也改变状态,然后执行setContextClassLoader()将执行的类加载器设置为用户执行的加载器,然后执行invokable.invoke(),该函数是分界点,执行前用户逻辑没有被触发,执行之后说明用户逻辑已完成。当执行完成之后,调用transitionState()函数执行的RUNNING状态改成FINISHED状态。同样调用notifyObservers()来通知其他观察者改变状态,最后,释放资源。

总体的函数执行图如下:因图片太大------>>>>>

链接: https://pan.baidu.com/s/15F1rBAmTSmNrkC8I4GmKnA 密码: du23

Flink整体执行流程的更多相关文章

  1. [源码分析] 带你梳理 Flink SQL / Table API内部执行流程

    [源码分析] 带你梳理 Flink SQL / Table API内部执行流程 目录 [源码分析] 带你梳理 Flink SQL / Table API内部执行流程 0x00 摘要 0x01 Apac ...

  2. JavaScript 引擎 V8 执行流程概述

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/t__Jqzg1rbTlsCHXKMwh6A作者:赖勇高 本文主要讲解的是V8的技术,是V8的入 ...

  3. Apache Flink 进阶(六):Flink 作业执行深度解析

    本文根据 Apache Flink 系列直播课程整理而成,由 Apache Flink Contributor.网易云音乐实时计算平台研发工程师岳猛分享.主要分享内容为 Flink Job 执行作业的 ...

  4. 追源索骥:透过源码看懂Flink核心框架的执行流程

    li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt, ...

  5. 透过源码看懂Flink核心框架的执行流程

    前言 Flink是大数据处理领域最近很火的一个开源的分布式.高性能的流式处理框架,其对数据的处理可以达到毫秒级别.本文以一个来自官网的WordCount例子为引,全面阐述flink的核心架构及执行流程 ...

  6. Apache Flink 整体介绍

    前言 Flink 是一种流式计算框架,为什么我会接触到 Flink 呢?因为我目前在负责的是监控平台的告警部分,负责采集到的监控数据会直接往 kafka 里塞,然后告警这边需要从 kafka topi ...

  7. 轻量级前端MVVM框架avalon - 执行流程2

    接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...

  8. struts2 之 【struts2简介,struts2开发步骤,struts2详细配置,struts2执行流程】

    入门框架学习避免不了的问题: 1. 什么是框架? 简单的说,框架就是模板,模子,模型.就是一个可重用的半成品. 2. 如何学习框架? 学习框架其实就是学习规则,使用框架就是遵循框架的规则,框架是可变的 ...

  9. Spring Boot程序的执行流程

    Spring Boot的执行流程如下图所示:(图片来源于网络) 上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置 ...

随机推荐

  1. python多线程之threading、ThreadPoolExecutor.map

    背景: 某个应用场景需要从数据库中取出几十万的数据时,需要对每个数据进行相应的操作.逐个数据处理过慢,于是考虑对数据进行分段线程处理: 方法一:使用threading模块 代码: # -*- codi ...

  2. Ubuntu分区方案(菜鸟方案、常用方案和进阶方案)

    菜鸟方案 “/”与swap两个分区就可以应付绝大多数的应用 常用方案 分为3个区 1. 挂载点/:主分区:安装系统和软件:大小为30G:分区格式为ext4: 2. 挂载点/home:逻辑分区:相当于“ ...

  3. OneDrive高速下载链接分享

    目录 1. 下载帮助 2. 本文地址 3. 资源链接 4. 打赏&支持 5. 关于&联系我 1. 下载帮助 OneDrive下载教程,建议不了解的先看下: https://www.cn ...

  4. 有准备的面试才能拿到更好的 Offer

    http://www.sohu.com/a/331411917_181657 前几天有读者问我,工作不顺利辞职了.本来以为凭借自己的能力和工作经验可以轻松找到更好的工作,结果投了简历,约面试的很少,面 ...

  5. 【c#】ADO操作Access的mdb数据库只能读不能修改的解决方法

    在使用ACCESS数据库时连接字符串如 string strcon=@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\Access操作\简易 ...

  6. Uva 10054 欧拉回路 打印路径

    看是否有欧拉回路 有的话打印路径 欧拉回路存在的条件: 如果是有向图的话 1.底图必须是连通图 2.最多有两个点的入度不等于出度 且一个点的入度=出度+1 一个点的入度=出度-1 如果是无向图的话 1 ...

  7. iOS控件圆角与半圆角

    开发过程中难免用到圆角以及恶心的半圆角,看代码 半圆角:这是把左边的两个角切成了圆角 UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoun ...

  8. inoutfy与rsync进行实时同步

    更新阿里epel源 安装镜像源 curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo --- 扩展 ...

  9. ZROI 19.08.02 杂题选讲

    给出\(n\)个数,用最少的\(2^k\)或\(-2^{k}\),使得能拼出所有数,输出方案.\(n,|a_i|\leq 10^5\). 显然一个绝对值最多选一次.这个性质非常强. 如果所有都是偶数, ...

  10. 在UIScrollView、UICollectionView和UITableView中添加UIRefreshControl实现下拉刷新

    Apple在iOS 6中添加了UIRefreshControl,但只能在UITableViewController中使用,不能在UIScrollView和UICollectionView中使用. 从i ...