flink checkpoint 恢复_Flink 源码:JM 端从 Checkpoint 恢复流程

本文深入解析 Flink 作业管理器(JM)如何恢复 Checkpoint 元数据,包括加载和校验元数据、分配 StateHandle 给 subtask 的详细流程。重点讨论了并行度检查、KeyGroupRange 生成、KeyedState 和 OperatorState 的分配策略,以及在恢复过程中遇到的挑战和解决方案。
摘要由CSDN通过智能技术生成

本文主要讲述:

  • JM 端恢复 Checkpoint 元数据流程
  • JM 端为 subtask 分配 StateHandle 流程

一、 JM 端恢复 Checkpoint 元数据流程

JM 端从 Checkpoint 中恢复任务的流程是从 CheckpointCoordinator 的 restoreSavepoint 方法开始的。restoreSavepoint 方法的源码如下所示:

public boolean restoreSavepoint(
  String savepointPointer,boolean allowNonRestored,
  Map tasks,
  ClassLoader userClassLoader) throws Exception {

 // 从外部存储获取 Checkpoint 元数据,这里的 checkpointStorage 是 FsCheckpointStorage
 final CompletedCheckpointStorageLocation checkpointLocation = 
    checkpointStorage.resolveCheckpoint(savepointPointer);

 // 加载 Checkpoint 元数据,并对 Checkpoint 进行校验,
  // 校验项包括 maxParallelism、allowNonRestoredState
 CompletedCheckpoint savepoint = Checkpoints.loadAndValidateCheckpoint(
   job, tasks, checkpointLocation, userClassLoader, allowNonRestored);

 // 将要恢复的 Checkpoint 信息写入到 zk 中
 completedCheckpointStore.addCheckpoint(savepoint);

 // Reset the checkpoint ID counter
 long nextCheckpointId = savepoint.getCheckpointID() + 1;
 checkpointIdCounter.setCount(nextCheckpointId);

 // 从最近一次 Checkpoint 处恢复 State
 return restoreLatestCheckpointedState(tasks, true, allowNonRestored);
}

首先从 savepointPointer 所在的目录找到 _metadata 文件(Checkpoint 的元数据文件),然后生成 CompletedCheckpointStorageLocation。CompletedCheckpointStorageLocation 见名之意:已经完成的 Checkpoint 存储位置。

加载元数据及校验逻辑

然后 Checkpoints.loadAndValidateCheckpoint() 方法加载 Checkpoint 元数据,并对 Checkpoint 进行校验,校验项包括 maxParallelism、allowNonRestoredState。Checkpoints 类 loadAndValidateCheckpoint()  方法的精简版校验源码如下所示:

public static CompletedCheckpoint loadAndValidateCheckpoint(
  JobID jobId,
  Map tasks,
  CompletedCheckpointStorageLocation location,
  ClassLoader classLoader,boolean allowNonRestoredState) throws IOException {

 // 从新的 ExecutionGraph 中生成 OperatorId 与 ExecutionJobVertex 的映射
 Map operatorToJobVertexMapping = new HashMap<>();for (ExecutionJobVertex task : tasks.values()) { for (OperatorID operatorID : task.getOperatorIDs()) {
   operatorToJobVertexMapping.put(operatorID, task);
  }
 }
 HashMap operatorStates = new HashMap<>(checkpointMetadata.getOperatorStates().size());// 循环检查所有的 OperatorState,这里的 OperatorState 不是指 Flink 的 OperatorState,// 而是指 算子级别的 State,这里的 Operator 指代算子for (OperatorState operatorState : checkpointMetadata.getOperatorStates()) { // 在新的 ExecutionGraph 中找 Checkpoint 中 OperatorId 对应的算子
  ExecutionJobVertex executionJobVertex = 
      operatorToJobVertexMapping.get(operatorState.getOperatorID());// executionJobVertex == null 说明有 OperatorState ,但找不到对应的 executionJobVertexif (executionJobVertex != null) { // 只要新旧 maxParallelism 相同,或者 新的 maxParallelism 没有配置,都认为校验通过if (executionJobVertex.getMaxParallelism() == operatorState.getMaxParallelism()
     || !executionJobVertex.isMaxParallelismConfigured()) {
    operatorStates.put(operatorState.getOperatorID(), operatorState);
   } else { // 相反 新旧 Job 的 maxParallelism 不同,// 且新 Job 的 maxParallelism 是用户手动设定的,则抛出异常,恢复失败throw new IllegalStateException(msg);
   }
  } else if (allowNonRestoredState) { // 跳过了恢复流程
   LOG.info("Skipping savepoint state for operator {}.");
  } else { // 不允许跳过恢复,检查当前 算子,是否包含状态,// 如果包含,则抛异常,Job 无法启动for (OperatorSubtaskState operatorSubtaskState : operatorState.getStates()) { if (operatorSubtaskState.hasState()) { throw new IllegalStateException(msg);
    }
   }
  }
 }// (3) convert to checkpoint so the system can fall back to it
 CheckpointProperties props = CheckpointProperties.forSavepoint();return new CompletedCheckpoint(XXX);
}

loadAndValidateCheckpoint 方法的检验过程,首先遍历新 Job 的 ExecutionGraph 中,通过 ExecutionGraph 生成 OperatorId 与 ExecutionJobVertex 的映射保存到 operatorToJobVertexMapping 中。然后循环检查所有的 OperatorState,这里的 OperatorState 不是指 Flink 的 OperatorState,而是指算子级别的 State(Operator 指代算子)。

在新的 ExecutionGraph 中找 Checkpoint 中 OperatorId 对应的算子保存到 executionJobVertex 中。executionJobVertex == null 说明有 OperatorState,但在新的 ExecutionGraph 中找不到对应的 executionJobVertex。

executionJobVertex != null 的情况

executionJobVertex != null 说明当前遍历的算子在新的 ExecutionGraph 中可以找到,此时检查新旧任务的 maxParallelism 是否可以匹配。只要新旧 maxParallelism 相同或者新的 maxParallelism 没有配置,都认为校验通过。这里 maxParallelism 没有设置指的是 maxParallelism 可能是 Flink 引擎自动生成的,而不是用户在代码中手动设置的。相反新旧 Job 的 maxParallelism 不同,且新 Job 的 maxParallelism 是用户手动设定的,则抛出异常,恢复失败。这也是在 《从 KeyGroup 到 Rescale》文章中讲到的,maxParallelism 不同,任务不能恢复。

executionJobVertex == null 的情况

executionJobVertex == null 说明有 OperatorState,但在新的 ExecutionGraph 中找不到对应的 executionJobVertex。这种现象说明 Flink 任务的代码发生了变动,删除了一些有状态算子,使得 Checkpoint 中保存的一些 State 不能正常恢复了。

executionJobVertex == null 的情况要对 allowNonRestoredState 参数进行检查,allowNonRestoredState 表示跳过那些无法映射到新程序的状态。如果 allowNonRestoredState 设置为 true,则 Flink 会跳过恢复当前算子的 State;如果 allowNonRestoredState 设置为 false,Flink 会检查当前算子是否有 State,如果有 State 则抛出异常,任务恢复失败。

恢复元数据

校验流程结束后,会将本次 Checkpoint 信息写入 zk,便于从 Checkpoint 中恢复。

restoreLatestCheckpoin

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值