JobManager作为actor,

  case SubmitJob(jobGraph, listeningBehaviour) =>
val client = sender() val jobInfo = new JobInfo(client, listeningBehaviour, System.currentTimeMillis(),
jobGraph.getSessionTimeout) submitJob(jobGraph, jobInfo)

 

submitJob,做3件事、

根据JobGraph生成ExecuteGraph

恢复状态CheckpointedState,或者Savepoint

提交ExecuteGraph给Scheduler进行调度

 

ExecuteGraph

executionGraph = ExecutionGraphBuilder.buildGraph(
executionGraph, //currentJobs.get(jobGraph.getJobID),对应的jobid是否有现存的ExecuteGraph
jobGraph,
flinkConfiguration, //配置
futureExecutor, //Executors.newFixedThreadPool(numberProcessors, new NamedThreadFactory("jobmanager-future-", "-thread-")),根据cpu核数创建的线程池
ioExecutor, // Executors.newFixedThreadPool(numberProcessors, new NamedThreadFactory("jobmanager-io-", "-thread-"))
userCodeLoader, //libraryCacheManager.getClassLoader(jobGraph.getJobID),从jar中加载
checkpointRecoveryFactory, //用于createCheckpointStore和createCheckpointIDCounter,standalone和zk两种
Time.of(timeout.length, timeout.unit),
restartStrategy, //job重启策略
jobMetrics,
numSlots, //scheduler.getTotalNumberOfSlots(),注册到该JM上的instances一共有多少slots
log.logger)

 

ExecutionGraphBuilder.buildGraph

 

New

        // create a new execution graph, if none exists so far
final ExecutionGraph executionGraph; try {
executionGraph = (prior != null) ? prior :
new ExecutionGraph(
futureExecutor,
ioExecutor,
jobId,
jobName,
jobGraph.getJobConfiguration(),
jobGraph.getSerializedExecutionConfig(),
timeout,
restartStrategy,
jobGraph.getUserJarBlobKeys(),
jobGraph.getClasspaths(),
classLoader,
metrics);
} catch (IOException e) {
throw new JobException("Could not create the execution graph.", e);
}

 

attachJobGraph,生成Graph的节点和边

        // topologically sort the job vertices and attach the graph to the existing one
List<JobVertex> sortedTopology = jobGraph.getVerticesSortedTopologicallyFromSources();
executionGraph.attachJobGraph(sortedTopology);

 

ExecutionGraph.attachJobGraph

       for (JobVertex jobVertex : topologiallySorted) {

            // create the execution job vertex and attach it to the graph
ExecutionJobVertex ejv =
new ExecutionJobVertex(this, jobVertex, 1, timeout, createTimestamp);
ejv.connectToPredecessors(this.intermediateResults); //All job vertices that are part of this graph, ConcurrentHashMap<JobVertexID, ExecutionJobVertex> tasks
ExecutionJobVertex previousTask = this.tasks.putIfAbsent(jobVertex.getID(), ejv); for (IntermediateResult res : ejv.getProducedDataSets()) {
//All intermediate results that are part of this graph
//ConcurrentHashMap<IntermediateDataSetID, IntermediateResult> intermediateResults
IntermediateResult previousDataSet = this.intermediateResults.putIfAbsent(res.getId(), res);
} //All vertices, in the order in which they were created
//List<ExecutionJobVertex> verticesInCreationOrder
this.verticesInCreationOrder.add(ejv);
}

将JobVertex封装成ExecutionJobVertex

会依次创建出ExecutionJobVertex,ExecutionVertex, Execution; IntermediateResult, IntermediateResultPartition

 

ExecutionJobVertex

public ExecutionJobVertex(
ExecutionGraph graph,
JobVertex jobVertex,
int defaultParallelism,
Time timeout,
long createTimestamp) throws JobException { if (graph == null || jobVertex == null) {
throw new NullPointerException();
} //并发度,决定有多少ExecutionVertex
int vertexParallelism = jobVertex.getParallelism();
int numTaskVertices = vertexParallelism > 0 ? vertexParallelism : defaultParallelism; //产生ExecutionVertex
this.taskVertices = new ExecutionVertex[numTaskVertices]; this.inputs = new ArrayList<>(jobVertex.getInputs().size()); // take the sharing group
this.slotSharingGroup = jobVertex.getSlotSharingGroup();
this.coLocationGroup = jobVertex.getCoLocationGroup(); // create the intermediate results
this.producedDataSets = new IntermediateResult[jobVertex.getNumberOfProducedIntermediateDataSets()]; //创建用于存放中间结果的IntermediateResult for (int i = 0; i < jobVertex.getProducedDataSets().size(); i++) {
final IntermediateDataSet result = jobVertex.getProducedDataSets().get(i); this.producedDataSets[i] = new IntermediateResult( //将JobGraph中的IntermediateDataSet封装成IntermediateResult
result.getId(),
this,
numTaskVertices,
result.getResultType());
} // create all task vertices
for (int i = 0; i < numTaskVertices; i++) {
ExecutionVertex vertex = new ExecutionVertex( //初始化ExecutionVertex
this, i, this.producedDataSets, timeout, createTimestamp, maxPriorAttemptsHistoryLength); this.taskVertices[i] = vertex; //
} finishedSubtasks = new boolean[parallelism];
}

 

ExecutionVertex

      public ExecutionVertex(
ExecutionJobVertex jobVertex,
int subTaskIndex, //第几个task,task和ExecutionVertex对应
IntermediateResult[] producedDataSets,
Time timeout,
long createTimestamp,
int maxPriorExecutionHistoryLength) { this.jobVertex = jobVertex;
this.subTaskIndex = subTaskIndex;
this.taskNameWithSubtask = String.format("%s (%d/%d)",
jobVertex.getJobVertex().getName(), subTaskIndex + 1, jobVertex.getParallelism()); this.resultPartitions = new LinkedHashMap<IntermediateResultPartitionID, IntermediateResultPartition>(producedDataSets.length, 1); //用于记录IntermediateResultPartition for (IntermediateResult result : producedDataSets) {
IntermediateResultPartition irp = new IntermediateResultPartition(result, this, subTaskIndex); //初始化IntermediateResultPartition
result.setPartition(subTaskIndex, irp); resultPartitions.put(irp.getPartitionId(), irp);
} this.inputEdges = new ExecutionEdge[jobVertex.getJobVertex().getInputs().size()][]; this.priorExecutions = new EvictingBoundedList<>(maxPriorExecutionHistoryLength); this.currentExecution = new Execution( //创建Execution
getExecutionGraph().getFutureExecutor(),
this,
0,
createTimestamp,
timeout); this.timeout = timeout;
}

 

connectToPredecessors,把节点用edge相连

    public void connectToPredecessors(Map<IntermediateDataSetID, IntermediateResult> intermediateDataSets) throws JobException {

        List<JobEdge> inputs = jobVertex.getInputs(); //JobVertex的输入

        for (int num = 0; num < inputs.size(); num++) {
JobEdge edge = inputs.get(num); //对应的JobEdge IntermediateResult ires = intermediateDataSets.get(edge.getSourceId()); //取出JobEdge的source IntermediateResult this.inputs.add(ires); //List<IntermediateResult> inputs; int consumerIndex = ires.registerConsumer(); //将当前vertex作为consumer注册到IntermediateResult的每个IntermediateResultPartition for (int i = 0; i < parallelism; i++) {
ExecutionVertex ev = taskVertices[i];
ev.connectSource(num, ires, edge, consumerIndex); //为每个ExecutionVertex建立到具体IntermediateResultPartition的ExecutionEdge
}
}
}

connectSource

public void connectSource(int inputNumber, IntermediateResult source, JobEdge edge, int consumerNumber) {

    final DistributionPattern pattern = edge.getDistributionPattern(); // 获取edge的distribution pattern
final IntermediateResultPartition[] sourcePartitions = source.getPartitions(); // 获取souce的partitions ExecutionEdge[] edges; switch (pattern) {
case POINTWISE:
edges = connectPointwise(sourcePartitions, inputNumber);
break; case ALL_TO_ALL:
edges = connectAllToAll(sourcePartitions, inputNumber);
break; default:
throw new RuntimeException("Unrecognized distribution pattern."); } this.inputEdges[inputNumber] = edges; // add the consumers to the source
// for now (until the receiver initiated handshake is in place), we need to register the
// edges as the execution graph
for (ExecutionEdge ee : edges) {
ee.getSource().addConsumer(ee, consumerNumber);
}
}

看下connectPointwise

private ExecutionEdge[] connectPointwise(IntermediateResultPartition[] sourcePartitions, int inputNumber) {
final int numSources = sourcePartitions.length; //Partitions的个数
final int parallelism = getTotalNumberOfParallelSubtasks(); //subTasks的并发度 // simple case same number of sources as targets
if (numSources == parallelism) { //如果1比1,简单
return new ExecutionEdge[] { new ExecutionEdge(sourcePartitions[subTaskIndex], this, inputNumber) }; //取sourcePartitions中和subTaskIndex对应的那个partition
}
else if (numSources < parallelism) { //如果subTasks的并发度高,那一个source会对应于多个task int sourcePartition; // check if the pattern is regular or irregular
// we use int arithmetics for regular, and floating point with rounding for irregular
if (parallelism % numSources == 0) { //整除的情况下,比如2个source,6个task,那么第3个task应该对应于第一个source
// same number of targets per source
int factor = parallelism / numSources;
sourcePartition = subTaskIndex / factor;
}
else {
// different number of targets per source
float factor = ((float) parallelism) / numSources;
sourcePartition = (int) (subTaskIndex / factor);
} return new ExecutionEdge[] { new ExecutionEdge(sourcePartitions[sourcePartition], this, inputNumber) };
}
else {
//......
}
}

 

配置checkpoint

                executionGraph.enableSnapshotCheckpointing(
snapshotSettings.getCheckpointInterval(),
snapshotSettings.getCheckpointTimeout(),
snapshotSettings.getMinPauseBetweenCheckpoints(),
snapshotSettings.getMaxConcurrentCheckpoints(),
snapshotSettings.getExternalizedCheckpointSettings(),
triggerVertices,
ackVertices,
confirmVertices,
checkpointIdCounter,
completedCheckpoints,
externalizedCheckpointsDir,
checkpointStatsTracker);

启动CheckpointCoordinator,参考专门讨论Checkpoint机制的blog

 

Scheduler

下面看看如何将生成好的ExecutionGraph进行调度

     future { //异步
try {
submittedJobGraphs.putJobGraph(new SubmittedJobGraph(jobGraph, jobInfo)) //放入submittedJobGraphs
} catch {
//
}
} jobInfo.notifyClients(
decorateMessage(JobSubmitSuccess(jobGraph.getJobID))) //通知用户提交成功 if (leaderElectionService.hasLeadership) {
executionGraph.scheduleForExecution(scheduler) //调度
}
} catch {
//
}
}(context.dispatcher)
}

executionGraph.scheduleForExecution

    public void scheduleForExecution(SlotProvider slotProvider) throws JobException {

        switch (scheduleMode) {

            case LAZY_FROM_SOURCES:
// simply take the vertices without inputs.
for (ExecutionJobVertex ejv : this.tasks.values()) { //ConcurrentHashMap<JobVertexID, ExecutionJobVertex> tasks,这个tasks的命名不科学
if (ejv.getJobVertex().isInputVertex()) {
ejv.scheduleAll(slotProvider, allowQueuedScheduling);
}
}
break; case EAGER:
for (ExecutionJobVertex ejv : getVerticesTopologically()) {
ejv.scheduleAll(slotProvider, allowQueuedScheduling);
}
break; default:
throw new JobException("Schedule mode is invalid.");
}
}

对于流默认是EAGER,

public JobGraph createJobGraph() {

        jobGraph = new JobGraph(streamGraph.getJobName());

        // make sure that all vertices start immediately
jobGraph.setScheduleMode(ScheduleMode.EAGER);

 

ExecutionJobVertex.scheduleAll

    public void scheduleAll(SlotProvider slotProvider, boolean queued) throws NoResourceAvailableException {
ExecutionVertex[] vertices = this.taskVertices; // kick off the tasks
for (ExecutionVertex ev : vertices) {
ev.scheduleForExecution(slotProvider, queued);
}
}

ExecutionVertex.scheduleForExecution

//The current or latest execution attempt of this vertex's task
public boolean scheduleForExecution(SlotProvider slotProvider, boolean queued) throws NoResourceAvailableException {
return this.currentExecution.scheduleForExecution(slotProvider, queued);
}

Execution.scheduleForExecution

    public boolean scheduleForExecution(SlotProvider slotProvider, boolean queued) throws NoResourceAvailableException {

        final SlotSharingGroup sharingGroup = vertex.getJobVertex().getSlotSharingGroup();
final CoLocationConstraint locationConstraint = vertex.getLocationConstraint(); if (transitionState(CREATED, SCHEDULED)) { ScheduledUnit toSchedule = locationConstraint == null ? //生成ScheduledUnit
new ScheduledUnit(this, sharingGroup) :
new ScheduledUnit(this, sharingGroup, locationConstraint); final Future<SimpleSlot> slotAllocationFuture = slotProvider.allocateSlot(toSchedule, queued); //从slotProvider获取slot final Future<Void> deploymentFuture = slotAllocationFuture.handle(new BiFunction<SimpleSlot, Throwable, Void>() {
@Override
public Void apply(SimpleSlot simpleSlot, Throwable throwable) {
if (simpleSlot != null) { //slot分配成功
try {
deployToSlot(simpleSlot); //deploy
} catch (Throwable t) {
try {
simpleSlot.releaseSlot();
} finally {
markFailed(t);
}
}
}
else {
markFailed(throwable);
}
return null;
}
}); }

slotProvider,参考Flink - Scheduler

 

deployToSlot,核心就是往TaskManager提交submitTask请求

    public void deployToSlot(final SimpleSlot slot) throws JobException {

        ExecutionState previous = this.state;
if (previous == SCHEDULED || previous == CREATED) {
if (!transitionState(previous, DEPLOYING)) { //状态迁移成Deploying
throw new IllegalStateException("Cannot deploy task: Concurrent deployment call race.");
}
} try {
// good, we are allowed to deploy
if (!slot.setExecutedVertex(this)) { //设置slot和ExecuteVertex关系
throw new JobException("Could not assign the ExecutionVertex to the slot " + slot);
}
this.assignedResource = slot; final TaskDeploymentDescriptor deployment = vertex.createDeploymentDescriptor( //创建DeploymentDescriptor
attemptId,
slot,
taskState,
attemptNumber); // register this execution at the execution graph, to receive call backs
vertex.getExecutionGraph().registerExecution(this); final TaskManagerGateway taskManagerGateway = slot.getTaskManagerGateway(); final Future<Acknowledge> submitResultFuture = taskManagerGateway.submitTask(deployment, timeout); //向TaskMananger的Actor发送请求 submitResultFuture.exceptionallyAsync(new ApplyFunction<Throwable, Void>() {......} }

Flink – JobManager.submitJob的更多相关文章

  1. Flink 源码解析 —— Flink JobManager 有什么作用?

    JobManager 的作用 https://t.zsxq.com/2VRrbuf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...

  2. Flink JobManager 和 TaskManager 原理

    转自:https://www.cnblogs.com/nicekk/p/11561836.html 一.概述 Flink 整个系统主要由两个组件组成,分别为 JobManager 和 TaskMana ...

  3. Flink JobManager HA模式部署(基于Standalone)

    参考文章:https://ci.apache.org/projects/flink/flink-docs-release-1.3/setup/jobmanager_high_availability. ...

  4. 搭建高可用的flink JobManager HA

    JobManager协调每个flink应用的部署,它负责执行定时任务和资源管理. 每一个Flink集群都有一个jobManager, 如果jobManager出现问题之后,将不能提交新的任务和运行新任 ...

  5. Apache Flink jobmanager/logs路径遍历CVE-2020-17519

    影响版本 1.11.0 1.11.1 1.11.2 poc http://192.168.49.2:8081/jobmanager/logs/..%252f..%252f..%252f..%252f. ...

  6. Flink 源码解析 —— JobManager 处理 SubmitJob 的过程

    JobManager 处理 SubmitJob https://t.zsxq.com/3JQJMzZ 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1 ...

  7. Flink 源码解析 —— TaskManager 处理 SubmitJob 的过程

    TaskManager 处理 SubmitJob 的过程 https://t.zsxq.com/eu7mQZj 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink ...

  8. Flink on yarn以及实现jobManager 高可用(HA)

    on yarn https://ci.apache.org/projects/flink/flink-docs-release-1.8/ops/deployment/yarn_setup.html f ...

  9. Flink - Checkpoint

    Flink在流上最大的特点,就是引入全局snapshot,   CheckpointCoordinator 做snapshot的核心组件为, CheckpointCoordinator /** * T ...

随机推荐

  1. 物联网架构成长之路(15)-Jenkins部署SpringBoot

    1.前言 现在慢慢也在负责一些工作了.这段时间有空,就多了解了解软件多人开发的一些知识.以前项目都是我一个人做的,从数据库设计到后端再到前端,全部放在一个war包丢到tomcat里面然后运行,利用to ...

  2. HTML5学习笔记(二十八):跨域

    在跨域安全性方面,有多个地方会有限制,主要是XMLHttpRequest对象的跨域限制和iFrame的跨域限制,下面我们分别来看一下. Ajax跨域(CORS) CORS是一个W3C标准,全称是&qu ...

  3. Cublas矩阵加速运算

    前言 编写 CUDA 程序真心不是个简单的事儿,调试也不方便,很费时.那么有没有一些现成的 CUDA 库来调用呢? 答案是有的,如 CUBLAS 就是 CUDA 专门用来解决线性代数运算的库. 本文将 ...

  4. elasticsearch中 refresh 和flush区别【转】

    elasticsearch中有两个比较重要的操作:refresh 和 flush refresh操作 当我们向ES发送请求的时候,我们发现es貌似可以在我们发请求的同时进行搜索.而这个实时建索引并可以 ...

  5. mxnet:基础知识和一个简单的示例

    NDArray与NumPy的多维数组类似,但NDArray提供了更多的功能:GPU和CPU的异步计算:自动求导.这使得NDArray能更好地支持机器学习. 初始化 from mxnet import ...

  6. Android Launcher分析和修改7——AllApp全部应用列表(AppsCustomizeTabHost)

    今天主要是分析一下Launcher里面的所有应用列表.Android4.0 Launcher的所有应用列表跟2.X比较大的区别就是多了Widget的显示.下面会详细分析Launcher里面有关所有应用 ...

  7. 业界常用的和不常用cad快捷键

    AutoCAD 是目前世界各国工程设计人员的首选设计软件,简便易学.精确无误是AutoCAD成功的两个重要原因.AutoCAD提供的命令有很多,绘图时最常用的命令只有其中的百分之二十. 在CAD软件操 ...

  8. java中的数据加密2 对称加密

    对称加密 也叫私钥加密.   采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密. 需要对加密和解密使用相同密钥的加密算法.由于其速度快,对 ...

  9. vue.js在visual studio 2017下的安装

    1.打开"工具"菜单->"NuGet 包管理器"->"管理解决方案 Nuget 的程序包": 在红色标识的地方输入vue: 2. ...

  10. 在VSCode中成功安装Go相关插件问题:tools failed to install.

    一.介绍 目的:本文将主要介绍在windows使用VSCode配置Go语言环境 软件:VSCode 二.安装出现的问题 完整信息如下 Installing tools at D:\GoPath\bin ...