...
Page properties | |||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).
...
In view of this, we think the JM crash may cause great regression for batch jobs, especially long running batch jobs. This FLIP is mainly to solve this problem so that batch jobs can recover most job progress after JM crashes. In this FLIP, our goal is to let most finished tasks not need to be re-run.
Public Interfaces
Introduce new configuration options
We intend to introduce the following new configuration parameters.
Key | Type | Default Value | Description |
execution.batch.job-recovery.enabled | Boolean | false | A flag to enable or disable the job recovery |
execution.batch.job-recovery.previous-worker.recovery.timeout | Duration | 30 s | The timeout for a new job master to wait for the previous worker to reconnect |
execution.batch.job-recovery.snapshot.min-pause | Duration | 3 min | The minimal pause between operator coordinator snapshotssnapshots. To avoid performance issues caused by too frequent snapshots. Used to take snapshots for operator coordinator or other components. |
job-event.store.write-buffer.size | MemorySize | 1M | The size of the write buffer of JobEventStore, the content will be flushed to external file system once it's full |
job-event.store.write-buffer.flush-interval | Duration | 1 s | The flush interval of write buffer of JobEventStore, over this time, the content will be flushed to external file system |
Introduce SupportsBatchSnapshot interface
In order to support Job Recovery, we will reuse the SplitEnumerator#snapshotState method to obtain the internal state of the split enumerator. In order to distinguish it from a normal checkpoint, we will pass -1(NO_CHECKPOINT) to identify indicate that this is a snapshot for the no-checkpoint/batch scenarios. Some current split enumerator implementations may rely on an postive checkpoint id, or does not support taking snapshot in no-checkpoint/batch scenarios. Therefore, job recovery will be disabled unless the source developer explicitly indicates specifies that it can support taking snapshot snapshots in no - checkpoint/batch scenarios. We introduced , the state of SourceCoordinator/SplitEnumerator will not be recored and restored(see the JobEvent section for how to handle this case). We will introduce a new interface SupportsBatchSnapshot to do this.indicate whether the split enumerator supports taking snapshots in batch scenarios.
Code Block | ||
---|---|---|
| ||
/** * An identifier interface for {@link SplitEnumerator}, which is used to support taking snapshot in * no-checkpoint/batch scenarios (for example to support job recovery in batch jobs). Once a {@link * SplitEnumerator} implements this interface, it'sits {@link SplitEnumerator#snapshotState} method * needs to accept -1 (NO_CHECKPOINT) as the argument. */ @PublicEvolving public interface SupportsBatchSnapshot {} |
...
ExecutionJobVertexInitializedEvent: This event is responsible for recording the initialization information of ExecutionJobVertex, its content contains the decided parallelism of this job vertex, and its input information. This event will be triggered and written out when an ExecutionJobVertex is initialized.
ExecutionVertexFinishedEvent: This event is responsible for recording the information of finished task. Our goal is that all finished tasks don’t need to re-run, so the simple idea is to trigger an event when a task is finished. The content of this event contains:
The state of the finished task/ExecutionVertex, including IO metrics, accumulators, etc. These contents can be easily obtained from ExecutionGraph.
- If the job vertex which this task belongs to has operator coordinators, the states of the operator coordinators also need to be recorded. See section OperatorCoordinator for details.
- The state of shuffle master, see section ShuffleMaster for details.
OperatorCoordinator
In order to obtain the state of operator coordinators, we will enrich the OperatorCoordinator#checkpointCoordinator method to let it accept -1 (NO_CHECKPOINT) as the value of checkpointId, to support snapshotting the state of operator coordinator in batch jobs. After JM crashes, the operator coordinator can be restored from the previous recorded state. In addition to a simple restore(by OperatorCoordinator#resetToCheckpoint method), it also needs to call OperatorCoordinator#subtaskReset for the non-finished tasks (which may in running state before JM crashes) , because these tasks will be reset and re-run after JM crashes.
Consider that the operator coordinators may have large state, we believe it may cause large overhead if we snapshot the operator coordinator at each execution vertex finished. To solve this problem, we will add a new configuration option "execution.batch.job-recovery.operator-coordinator-snapshot.min-pause" to control the minimum pause between snapshots. When restoring, we will also reconcile the execution job vertex state with the operator coordinator state to be consistent. In other words, we will adjust the execution job vertex to the state at the time of the lastest snapshot operator coordinators.
However, currently, some operator coordinators may not support taking snapshot in no-checkpoint/batch scenarios (or does not accept -1 as argument), we need to add the following method to the operator coordinator:
Code Block | ||
---|---|---|
| ||
public interface OperatorCoordinator extends CheckpointListener, AutoCloseable {
// other methods
/**
* Whether the operator coordinator supports taking snapshot in no-checkpoint/batch scenarios.
* If it returns true, it's {@link OperatorCoordinator#checkpointCoordinator} and {@link
* OperatorCoordinator#resetToCheckpoint} methods need to accept -1 (NO_CHECKPOINT) as the value
* of checkpoint id. Otherwise returns false.
*/
default boolean supportsBatchSnapshot() {
return false;
} |
Method OperatorCoordinator#supportsBatchSnapshot is used to identify whether the current operator coordinator supports taking snapshot in no-checkpoint/batch scenarios. If an operator coordinator does not support snapshot, which means it will return the inital state after JM restarts, we will handle it as follows:
1. If not all tasks corresponding to this operator coordinator are finished, we will reset all these tasks and re-run them.
2. If all tasks corresponding to this operator coordinator finished, we don't need to do anything and the job can continue to run. However, once one of these tasks needs to be restarted at some point in the future (for example, due to PartitionNotFound exception), we need to reset all these tasks and re-run them.
For the source coordinator, whether it supports batch snapshot depends on whether it's SplitEnumerator supports batch snapshot. For it, we introduce the SupportsBatchSnapshot mentioned above to identify it.
ShuffleMaster
In order to obtain the state of shuffle master, we will add the following methods to shuffle master. Before the job starts running, we will check whether the shuffle master supports taking snapshots(through method supportsBatchSnapshot). If it is not supported, we will disable Job Recovery for jobs.
Note that it's mainly designed for external/remote shuffle service, the Flink default Netty/TM shuffle is stateless and only needs to be an empty implementation.
Code Block | ||
---|---|---|
| ||
interface ShuffleMaster<T extends ShuffleDescriptor> extends AutoCloseable {
// other methods
/**
* Whether the shuffle master supports taking snapshot in batch scenarios, which will be used
* when enable Job Recovery. If it returns true, we will call {@link #snapshotState} to take
* snapshot, and call {@link #restoreState} to restore the state of shuffle master.
*/
default boolean supportsBatchSnapshot() {
return false;
}
default void snapshotState(
CompletableFuture<ShuffleMasterSnapshot> snapshotFuture,
ShuffleMasterSnapshotContext context) {
snapshotFuture.complete(null);
}
default void restoreState(List<ShuffleMasterSnapshot> snapshots) {}
}
/**
* This class represents a snapshot of shuffle master, which can be used to restore the internal
* state of the shuffle master. It is full or incremental.
*/
interface ShuffleMasterSnapshot extends Serializable {
/** Returns whether the snapshot is incremental. */
boolean isIncremental();
}
/**
* Snapshot context used to create {@link ShuffleMasterSnapshot}, which can provide necessary
* informations.
*/
interface ShuffleMasterSnapshotContext {
} |
Persistent JobEventStore
We intend to introduce a persistent JobEventStore to record the JobEvents, the store is based on the file system and has the following features:
...
Code Block | ||
---|---|---|
| ||
interface ShuffleMaster<T extends ShuffleDescriptor> extends AutoCloseable interface ShuffleMaster<T extends ShuffleDescriptor> extends AutoCloseable { // other methods /** * Get all partitions and their metrics, the metrics mainly includes the meta information of partition(partition bytes, etc). * @param jobId ID of the target job @param jobId ID of the target job * @return All partitions belongs to the target job and their metrics @return All partitions belongs to the target job and their metrics */ Collection<PartitionWithMetrics> getAllPartitionWithMetrics(JobID jobId CompletableFuture<Collection<PartitionWithMetrics>> getAllPartitionWithMetrics(JobID jobId); interface PartitionWithMetrics interface PartitionWithMetrics { ShuffleMetrics getPartitionMetrics ShuffleMetrics getPartitionMetrics(); ShuffleDescriptor getPartition ShuffleDescriptor getPartition(); } interface ShuffleMetrics interface ShuffleMetrics { ResultPartitionBytes getPartitionBytes ResultPartitionBytes getPartitionBytes(); } } |
Compatibility, Deprecation, and Migration Plan
...