Jobmanager的submitJob逻辑,

/**
* Submits a job to the job manager. The job is registered at the libraryCacheManager which
* creates the job's class loader. The job graph is appended to the corresponding execution
* graph and the execution vertices are queued for scheduling.
*
* @param jobGraph representing the Flink job
* @param jobInfo the job info
* @param isRecovery Flag indicating whether this is a recovery or initial submission
*/
private def submitJob(jobGraph: JobGraph, jobInfo: JobInfo, isRecovery: Boolean = false): Unit = {
if (jobGraph == null) {
jobInfo.notifyClients(
decorateMessage(JobResultFailure(
new SerializedThrowable(
new JobSubmissionException(null, "JobGraph must not be null.")))))
}
else {
val jobId = jobGraph.getJobID
val jobName = jobGraph.getName
var executionGraph: ExecutionGraph = null try {
// Important: We need to make sure that the library registration is the first action,
// because this makes sure that the uploaded jar files are removed in case of
// unsuccessful
try {
libraryCacheManager.registerJob(jobGraph.getJobID, jobGraph.getUserJarBlobKeys,
jobGraph.getClasspaths)
}
var userCodeLoader = libraryCacheManager.getClassLoader(jobGraph.getJobID) //加载Jar val restartStrategy = //加载重启策略
Option(jobGraph.getSerializedExecutionConfig()
.deserializeValue(userCodeLoader)
.getRestartStrategy())
.map(RestartStrategyFactory.createRestartStrategy)
.filter(p => p != null) match {
case Some(strategy) => strategy
case None => restartStrategyFactory.createRestartStrategy()
} val jobMetrics = jobManagerMetricGroup match { //生成job manager metric group
case Some(group) =>
group.addJob(jobGraph) match {
case (jobGroup:Any) => jobGroup
case null => new UnregisteredMetricsGroup()
}
case None =>
new UnregisteredMetricsGroup()
} val numSlots = scheduler.getTotalNumberOfSlots() //现有的slots数目 // see if there already exists an ExecutionGraph for the corresponding job ID
val registerNewGraph = currentJobs.get(jobGraph.getJobID) match {
case Some((graph, currentJobInfo)) =>
executionGraph = graph
currentJobInfo.setLastActive()
false
case None =>
true
} executionGraph = ExecutionGraphBuilder.buildGraph( //build ExecutionGraph
executionGraph,
jobGraph,
flinkConfiguration,
futureExecutor,
ioExecutor,
userCodeLoader,
checkpointRecoveryFactory,
Time.of(timeout.length, timeout.unit),
restartStrategy,
jobMetrics,
numSlots,
log.logger) if (registerNewGraph) { //如果是新的JobGraph,注册到currentJobs
currentJobs.put(jobGraph.getJobID, (executionGraph, jobInfo))
} // get notified about job status changes
executionGraph.registerJobStatusListener( //jobmananger加到通知listeners
new StatusListenerMessenger(self, leaderSessionID.orNull)) jobInfo.clients foreach { //client加到通知listeners
// the sender wants to be notified about state changes
case (client, ListeningBehaviour.EXECUTION_RESULT_AND_STATE_CHANGES) =>
val listener = new StatusListenerMessenger(client, leaderSessionID.orNull)
executionGraph.registerExecutionListener(listener)
executionGraph.registerJobStatusListener(listener)
case _ => // do nothing
} } catch { //失败
case t: Throwable =>
log.error(s"Failed to submit job $jobId ($jobName)", t) libraryCacheManager.unregisterJob(jobId)
currentJobs.remove(jobId) if (executionGraph != null) {
executionGraph.fail(t) //fail executionGraph
} val rt: Throwable = if (t.isInstanceOf[JobExecutionException]) {
t
} else {
new JobExecutionException(jobId, s"Failed to submit job $jobId ($jobName)", t)
} jobInfo.notifyClients(
decorateMessage(JobResultFailure(new SerializedThrowable(rt)))) //通知提交失败
return
} //上面是准备executionGraph,下面是异步提交
// execute the recovery/writing the jobGraph into the SubmittedJobGraphStore asynchronously
// because it is a blocking operation
future {
try {
if (isRecovery) {
// this is a recovery of a master failure (this master takes over)
executionGraph.restoreLatestCheckpointedState(false, false) //加载checkpoint状态
}
else {
// load a savepoint only if this is not starting from a newer checkpoint
// as part of an master failure recovery
val savepointSettings = jobGraph.getSavepointRestoreSettings
if (savepointSettings.restoreSavepoint()) { //处理savePoint
try {
val savepointPath = savepointSettings.getRestorePath()
val allowNonRestored = savepointSettings.allowNonRestoredState() log.info(s"Starting job from savepoint '$savepointPath'" +
(if (allowNonRestored) " (allowing non restored state)" else "") + ".") // load the savepoint as a checkpoint into the system
val savepoint: CompletedCheckpoint = SavepointLoader.loadAndValidateSavepoint(
jobId,
executionGraph.getAllVertices,
savepointPath,
executionGraph.getUserClassLoader,
allowNonRestored) executionGraph.getCheckpointCoordinator.getCheckpointStore
.addCheckpoint(savepoint) // Reset the checkpoint ID counter
val nextCheckpointId: Long = savepoint.getCheckpointID + 1
log.info(s"Reset the checkpoint ID to $nextCheckpointId")
executionGraph.getCheckpointCoordinator.getCheckpointIdCounter
.setCount(nextCheckpointId) executionGraph.restoreLatestCheckpointedState(true, allowNonRestored)
} catch {
case e: Exception =>
jobInfo.notifyClients(
decorateMessage(JobResultFailure(new SerializedThrowable(e))))
throw new SuppressRestartsException(e)
}
} try {
submittedJobGraphs.putJobGraph(new SubmittedJobGraph(jobGraph, jobInfo)) //存储该JobGraph到zk,ZooKeeperSubmittedJobGraphStore
} catch {
case t: Throwable =>
// Don't restart the execution if this fails. Otherwise, the
// job graph will skip ZooKeeper in case of HA.
jobInfo.notifyClients(
decorateMessage(JobResultFailure(new SerializedThrowable(t))))
throw new SuppressRestartsException(t)
}
} jobInfo.notifyClients(
decorateMessage(JobSubmitSuccess(jobGraph.getJobID))) //通知clients提交成功 if (leaderElectionService.hasLeadership) {
// There is a small chance that multiple job managers schedule the same job after if
// they try to recover at the same time. This will eventually be noticed, but can not be
// ruled out from the beginning. // NOTE: Scheduling the job for execution is a separate action from the job submission.
// The success of submitting the job must be independent from the success of scheduling
// the job.
log.info(s"Scheduling job $jobId ($jobName).") executionGraph.scheduleForExecution(scheduler) //开始调度
} else {
// Remove the job graph. Otherwise it will be lingering around and possibly removed from
// ZooKeeper by this JM.
self ! decorateMessage(RemoveJob(jobId, removeJobFromStateBackend = false)) log.warn(s"Submitted job $jobId, but not leader. The other leader needs to recover " +
"this. I am not scheduling the job for execution.")
}
} catch {
case t: Throwable => try {
executionGraph.fail(t)
} catch {
case tt: Throwable =>
log.error("Error while marking ExecutionGraph as failed.", tt)
}
}
}(context.dispatcher)
}
}

可以看到executionGraph在调度前就已经通知用户提交成功

 

当job发生问题,需要调用到tryRestartOrFail

private boolean tryRestartOrFail() {
JobStatus currentState = state; if (currentState == JobStatus.FAILING || currentState == JobStatus.RESTARTING) {
synchronized (progressLock) { //锁 final boolean isFailureCauseAllowingRestart = !(failureCause instanceof SuppressRestartsException);
final boolean isRestartStrategyAllowingRestart = restartStrategy.canRestart(); //重启策略是否允许重启
boolean isRestartable = isFailureCauseAllowingRestart && isRestartStrategyAllowingRestart; if (isRestartable && transitionState(currentState, JobStatus.RESTARTING)) {
restartStrategy.restart(this); return true;
} else if (!isRestartable && transitionState(currentState, JobStatus.FAILED, failureCause)) { //如果不允许重启,就failed
final List<String> reasonsForNoRestart = new ArrayList<>(2);
if (!isFailureCauseAllowingRestart) {
reasonsForNoRestart.add("a type of SuppressRestartsException was thrown");
}
if (!isRestartStrategyAllowingRestart) {
reasonsForNoRestart.add("the restart strategy prevented it");
} LOG.info("Could not restart the job {} ({}) because {}.", getJobName(), getJobID(),
StringUtils.join(reasonsForNoRestart, " and "), failureCause);
postRunCleanup(); return true;
} else {
// we must have changed the state concurrently, thus we cannot complete this operation
return false;
}
}
} else {
// this operation is only allowed in the state FAILING or RESTARTING
return false;
}
}

 

有两处会调用到tryRestartOrFail

1. ExecutionGraph.jobVertexInFinalState

void jobVertexInFinalState() {
synchronized (progressLock) {
if (numFinishedJobVertices >= verticesInCreationOrder.size()) {
throw new IllegalStateException("All vertices are already finished, cannot transition vertex to finished.");
} numFinishedJobVertices++; if (numFinishedJobVertices == verticesInCreationOrder.size()) { //当所有的vertices都已经finished // we are done, transition to the final state
JobStatus current;
while (true) {
current = this.state; if (current == JobStatus.RUNNING) {
if (transitionState(current, JobStatus.FINISHED)) {
postRunCleanup();
break;
}
}
else if (current == JobStatus.CANCELLING) {
if (transitionState(current, JobStatus.CANCELED)) {
postRunCleanup();
break;
}
}
else if (current == JobStatus.FAILING) {
if (tryRestartOrFail()) { //如果failing,调用tryRestartOrFail
break;
}
// concurrent job status change, let's check again
}

2. 显式的调用到ExecutionGraph.fail

} else if (current == JobStatus.RESTARTING) {
this.failureCause = t; if (tryRestartOrFail()) {
return;
}
// concurrent job status change, let's check again
}

 

上面调用到restartStrategy.restart(this);

restartStrategy有很多种,我们先看看

FixedDelayRestartStrategy

 

@Override
public void restart(final ExecutionGraph executionGraph) {
currentRestartAttempt++;
FlinkFuture.supplyAsync(ExecutionGraphRestarter.restartWithDelay(executionGraph, delayBetweenRestartAttempts), executionGraph.getFutureExecutor());
}

异步的调用,ExecutionGraphRestarter.restartWithDelay

最终调用到

executionGraph.restart();
public void restart() {
try {
synchronized (progressLock) {
this.currentExecutions.clear(); Collection<CoLocationGroup> colGroups = new HashSet<>(); for (ExecutionJobVertex jv : this.verticesInCreationOrder) { CoLocationGroup cgroup = jv.getCoLocationGroup();
if(cgroup != null && !colGroups.contains(cgroup)){
cgroup.resetConstraints();
colGroups.add(cgroup);
} jv.resetForNewExecution();
} for (int i = 0; i < stateTimestamps.length; i++) {
if (i != JobStatus.RESTARTING.ordinal()) {
// Only clear the non restarting state in order to preserve when the job was
// restarted. This is needed for the restarting time gauge
stateTimestamps[i] = 0;
}
}
numFinishedJobVertices = 0;
transitionState(JobStatus.RESTARTING, JobStatus.CREATED); // if we have checkpointed state, reload it into the executions
if (checkpointCoordinator != null) {
checkpointCoordinator.restoreLatestCheckpointedState(getAllVertices(), false, false);
}
} scheduleForExecution(slotProvider); //加入schedule
}
catch (Throwable t) {
LOG.warn("Failed to restart the job.", t);
fail(t);
}
}

 

关于重启策略,

参考https://ci.apache.org/projects/flink/flink-docs-release-1.2/dev/restart_strategies.html

If checkpointing is not enabled, the “no restart” strategy is used. If checkpointing is activated and the restart strategy has not been configured, the fixed-delay strategy is used with Integer.MAX_VALUE restart attempts.

 

StreamingJobGraphGenerator
private void configureCheckpointing() {
CheckpointConfig cfg = streamGraph.getCheckpointConfig(); long interval = cfg.getCheckpointInterval();
if (interval > 0) {
// check if a restart strategy has been set, if not then set the FixedDelayRestartStrategy
if (streamGraph.getExecutionConfig().getRestartStrategy() == null) {
// if the user enabled checkpointing, the default number of exec retries is infinite.
streamGraph.getExecutionConfig().setRestartStrategy(
RestartStrategies.fixedDelayRestart(Integer.MAX_VALUE, DEFAULT_RESTART_DELAY));
}
}

当打开checkpoint的时候,默认是使用fixedDelayRestart,并Integer.MAX_VALUE次重启

Flink – submitJob的更多相关文章

  1. Flink – JobManager.submitJob

    JobManager作为actor, case SubmitJob(jobGraph, listeningBehaviour) => val client = sender() val jobI ...

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

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

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

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

  4. Flink 1.1 – ResourceManager

    Flink resource manager的作用如图,   FlinkResourceManager /** * * <h1>Worker allocation steps</h1 ...

  5. Flink - Checkpoint

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

  6. Apache 流框架 Flink,Spark Streaming,Storm对比分析(一)

    本文由  网易云发布. 1.Flink架构及特性分析 Flink是个相当早的项目,开始于2008年,但只在最近才得到注意.Flink是原生的流处理系统,提供high level的API.Flink也提 ...

  7. Apache Flink:特性、概念、组件栈、架构及原理分析

     2016-04-30 22:24:39    Yanjun Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,它能够基于同一个Flink运行时(Flink Runtim ...

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

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

  9. Flink(二)CentOS7.5搭建Flink1.6.1分布式集群

    一. Flink的下载 安装包下载地址:http://flink.apache.org/downloads.html  ,选择对应Hadoop的Flink版本下载 [admin@node21 soft ...

随机推荐

  1. [BigData - Hadoop - YARN] YARN:下一代 Hadoop 计算平台

    Apache Hadoop 是最流行的大数据处理工具之一.它多年来被许多公司成功部署在生产中.尽管 Hadoop 被视为可靠的.可扩展的.富有成本效益的解决方案,但大型开发人员社区仍在不断改进它.最终 ...

  2. [Big Data - ELK] ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台

    ELK平台介绍 在搜索ELK资料的时候,发现这篇文章比较好,于是摘抄一小段: 以下内容来自: http://baidu.blog.51cto.com/71938/1676798 日志主要包括系统日志. ...

  3. Linux 下配置Tomcat的虚拟路径

    如果你的Linux服务器下,不止一个tomcat的时候,这个时候,你就会发现,每次去发布项目很麻烦,还需要到webapps下面去看,繁琐的很,这里就用到了,Tomcat的虚拟路径,制定一个目录,作为t ...

  4. 【iCore4 双核心板_ARM】例程二:读取ARM按键状态

    实验原理: 按键的一端与STM32 PB9相连,另外一端接地,且PB9外接一个1K电阻大小的上拉电阻, 初始化时把PB9设置成输入模式,当按键弹起时,PB9由于上拉电阻的作用呈高电平(3.3V): 当 ...

  5. 聊聊Python中的生成器和迭代器

    Python中有两个重要的概念,生成器和迭代器,这里详细记录一下. 1. 生成器 什么是生成器呢? 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...

  6. tensorflow模型量化

    tensorflow模型量化/DATA/share/DeepLearning/code/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/t ...

  7. json转 PostMan bulk Edit application/x-www-form-urlencoded 需要的格式

    {?\n\s*"([^"]+)"\s*:\s*"?([^,"]+)"?\s*,?}? $1:$2\n PostMan需要的格式. json转 ...

  8. Ubuntu下搜狗输入法只显示黑框,不显示输入的汉字选项

    1. cd ~/.config 2.删除三个文件夹: SogouPY, SogouPY.users, sogou-qimpanel 然后重启输入法

  9. [JS] Topic - Object.create vs new

    故事背景 Ref: 你不知道的javascript之Object.create 和new区别 var Base = function () {} (1) var o1 = new Base(); (2 ...

  10. ASP.NET MVC 4 (八) URL链接和Ajax帮助函数

    使用帮助函数创建链接 MVC提供一些帮助函数创建链接,这些函数根据路径映射表自动调整生成的URL: 说明 示例 输出结果 应用程序相对URL Url.Content("~/Content/S ...