Flink – JobManager.submitJob
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的更多相关文章
- Flink 源码解析 —— Flink JobManager 有什么作用?
JobManager 的作用 https://t.zsxq.com/2VRrbuf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...
- Flink JobManager 和 TaskManager 原理
转自:https://www.cnblogs.com/nicekk/p/11561836.html 一.概述 Flink 整个系统主要由两个组件组成,分别为 JobManager 和 TaskMana ...
- Flink JobManager HA模式部署(基于Standalone)
参考文章:https://ci.apache.org/projects/flink/flink-docs-release-1.3/setup/jobmanager_high_availability. ...
- 搭建高可用的flink JobManager HA
JobManager协调每个flink应用的部署,它负责执行定时任务和资源管理. 每一个Flink集群都有一个jobManager, 如果jobManager出现问题之后,将不能提交新的任务和运行新任 ...
- 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. ...
- Flink 源码解析 —— JobManager 处理 SubmitJob 的过程
JobManager 处理 SubmitJob https://t.zsxq.com/3JQJMzZ 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1 ...
- Flink 源码解析 —— TaskManager 处理 SubmitJob 的过程
TaskManager 处理 SubmitJob 的过程 https://t.zsxq.com/eu7mQZj 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink ...
- Flink on yarn以及实现jobManager 高可用(HA)
on yarn https://ci.apache.org/projects/flink/flink-docs-release-1.8/ops/deployment/yarn_setup.html f ...
- Flink - Checkpoint
Flink在流上最大的特点,就是引入全局snapshot, CheckpointCoordinator 做snapshot的核心组件为, CheckpointCoordinator /** * T ...
随机推荐
- 物联网架构成长之路(15)-Jenkins部署SpringBoot
1.前言 现在慢慢也在负责一些工作了.这段时间有空,就多了解了解软件多人开发的一些知识.以前项目都是我一个人做的,从数据库设计到后端再到前端,全部放在一个war包丢到tomcat里面然后运行,利用to ...
- HTML5学习笔记(二十八):跨域
在跨域安全性方面,有多个地方会有限制,主要是XMLHttpRequest对象的跨域限制和iFrame的跨域限制,下面我们分别来看一下. Ajax跨域(CORS) CORS是一个W3C标准,全称是&qu ...
- Cublas矩阵加速运算
前言 编写 CUDA 程序真心不是个简单的事儿,调试也不方便,很费时.那么有没有一些现成的 CUDA 库来调用呢? 答案是有的,如 CUBLAS 就是 CUDA 专门用来解决线性代数运算的库. 本文将 ...
- elasticsearch中 refresh 和flush区别【转】
elasticsearch中有两个比较重要的操作:refresh 和 flush refresh操作 当我们向ES发送请求的时候,我们发现es貌似可以在我们发请求的同时进行搜索.而这个实时建索引并可以 ...
- mxnet:基础知识和一个简单的示例
NDArray与NumPy的多维数组类似,但NDArray提供了更多的功能:GPU和CPU的异步计算:自动求导.这使得NDArray能更好地支持机器学习. 初始化 from mxnet import ...
- Android Launcher分析和修改7——AllApp全部应用列表(AppsCustomizeTabHost)
今天主要是分析一下Launcher里面的所有应用列表.Android4.0 Launcher的所有应用列表跟2.X比较大的区别就是多了Widget的显示.下面会详细分析Launcher里面有关所有应用 ...
- 业界常用的和不常用cad快捷键
AutoCAD 是目前世界各国工程设计人员的首选设计软件,简便易学.精确无误是AutoCAD成功的两个重要原因.AutoCAD提供的命令有很多,绘图时最常用的命令只有其中的百分之二十. 在CAD软件操 ...
- java中的数据加密2 对称加密
对称加密 也叫私钥加密. 采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密. 需要对加密和解密使用相同密钥的加密算法.由于其速度快,对 ...
- vue.js在visual studio 2017下的安装
1.打开"工具"菜单->"NuGet 包管理器"->"管理解决方案 Nuget 的程序包": 在红色标识的地方输入vue: 2. ...
- 在VSCode中成功安装Go相关插件问题:tools failed to install.
一.介绍 目的:本文将主要介绍在windows使用VSCode配置Go语言环境 软件:VSCode 二.安装出现的问题 完整信息如下 Installing tools at D:\GoPath\bin ...