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. ios开发:一个音乐播放器的设计与实现

    github地址:https://github.com/wzpziyi1/MusicPlauer 这个Demo,关于歌曲播放的主要功能都实现了的.下一曲.上一曲,暂停,根据歌曲的播放进度动态滚动歌词, ...

  2. Unity读取Excel文件(附源代码)

    今天想弄个Unity读取Excel的功能的,发现网上有许多方法,采用其中一种方法:加入库文件 Excel.dll 和ICSharpCode.SharpZipLib.dll库文件,(还有System.D ...

  3. (转载)完成端口(Completion Port, I/OCP)详解

    http://www.cnblogs.com/lancidie/archive/2011/12/19/2293773.html 手把手叫你玩转网络编程系列之三    完成端口(Completion P ...

  4. Django 源码小剖: Django 中的 WSGI

    Django 其内部已经自带了一个方便本地测试的小服务器, 所以在刚开始学习 Django 的时候并不需搭建 apache 或者 nginx 服务器. Django 自带的服务器基于 python w ...

  5. 用panels 制作drupal首页

    1.下载zen主题 路径:https://www.drupal.org/project/zen2.“启用并设为默认”3.基于zen制作子主题 把zen目录下STARTERKIT文件夹,复制到sites ...

  6. Android美丽的对话框项目sweet-alert-dialog

    美丽的对话框 sweet-alert-dialog 项目地址: https://github.com/pedant/sweet-alert-dialog android原生的dialog太生硬了,之前 ...

  7. Java知多少(63)线程间通信

    上述例题无条件的阻塞了其他线程异步访问某个方法.Java对象中隐式管程的应用是很强大的,但是你可以通过进程间通信达到更微妙的境界.这在Java中是尤为简单的. 像前面所讨论过的,多线程通过把任务分成离 ...

  8. Best Practices in Asynchronous Programming

    http://blog.stephencleary.com/ http://blogs.msdn.com/b/pfxteam/

  9. yum常用命令大全

    yum命令是在Fedora和RedHat以及SUSE中基于rpm的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理RPM软件包,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性 ...

  10. SQL中in参数在存储过程中传递及使用的方法

    背景: 1.使用存储过程 2.存储过程中有in 3.in括号里面的内容作为参数传递 解决方案: 1.直接拼接sql 可在存储过程中拼接字符串,然后执行此字符串,类似于js中的eval PROCEDUR ...