Flink操作——状态与容错

文章目录

  • Checkpoints
    • 概述
    • 检查点存储
      • 可用的检查点存储选项
        • JobManagerCheckpointStorage
        • FileSystemCheckpointStorage
    • 检查点保留
      • 目录结构
      • 从保留的检查点恢复
  • Checkpointing under backpressure
    • 缓冲区 Debloating
    • 非对齐 Checkpoints
      • 对齐 Checkpoint 的超时
      • 限制
        • 并发 Checkpoint
        • 与 Watermark 的相互影响
        • 与长时间运行的记录处理相互作用
        • 某些数据分布模式不是检查点
          • 点对点连接
          • 广播 Connections
        • Troubleshooting
  • Savepoints
    • 什么是 Savepoint ?
    • 分配算子 ID
      • Savepoint 状态
    • 算子
      • 触发 Savepoint
        • Savepoint 格式
        • 触发 Savepoint
        • 使用 YARN 触发 Savepoint
        • 使用 Savepoint 停止作业
      • 从 Savepoint 恢复
        • 跳过无法映射的状态恢复
        • Restore 模式
        • NO_CLAIM (默认的)
        • CLAIM
        • LEGACY
      • 删除 Savepoint
      • 配置
    • F.A.Q
      • 我应该为我作业中的所有算子分配 ID 吗?
      • 如果我在作业中添加一个需要状态的新算子,会发生什么?
      • 如果从作业中删除有状态的算子会发生什么?
      • 如果我在作业中重新排序有状态算子,会发生什么?
      • 如果我添加、删除或重新排序作业中没有状态的算子,会发生什么?
      • 当我在恢复时改变程序的并行度时会发生什么?
      • 我可以将 savepoint 文件移动到稳定存储上吗?
  • Checkpoints vs. Savepoints
    • Overview
    • 功能和限制
  • 大状态与 Checkpoint 调优
    • 监视状态和检查点
    • 调优检查点
    • 调优RocksDB
      • 增量检查点
      • 计时器在RocksDB或JVM堆上
      • 调优RocksDB内存
    • 容量规划
    • 压缩
    • Task-Local Recovery
      • 动机
      • 方法
      • 主要(分布式存储)和次要(任务本地)状态快照的关系
      • 配置task-local恢复
      • 关于不同状态后端的任务本地恢复的详细信息
        • Allocation-preserving调度
  • Task 故障恢复
    • Restart Strategies
      • Fixed Delay Restart Strategy
      • Failure Rate Restart Strategy
      • No Restart Strategy
      • Fallback Restart Strategy
    • Failover Strategies
      • Restart All Failover Strategy
      • Restart Pipelined Region Failover Strategy

Checkpoints

概述

Checkpoint 使 Flink 的状态具有良好的容错性,通过 checkpoint 机制,Flink 可以对作业的状态和计算位置进行恢复。

参考 Checkpointing 查看如何在 Flink 程序中开启和配置 checkpoint。

要理解检查点和保存点之间的区别,请参阅检查点和保存点。

检查点存储

Checkpoint 在默认的情况下仅用于恢复失败的作业,并不保留,当程序取消时 checkpoint 就会被删除。当然,你可以通过配置来保留 checkpoint,这些被保留的 checkpoint 在作业失败或取消时不会被清除。这样,你就可以使用该 checkpoint 来恢复失败的作业。

CheckpointConfig config = env.getCheckpointConfig();
config.setExternalizedCheckpointCleanup(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);

ExternalizedCheckpointCleanup 配置项定义了当作业取消时,对作业 checkpoint 的操作:

  • ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION:当作业取消时,保留作业的 checkpoint。注意,这种情况下,需要手动清除该作业保留的 checkpoint。
  • ExternalizedCheckpointCleanup.DELETE_ON_CANCELLATION:当作业取消时,删除作业的 checkpoint。仅当作业失败时,作业的 checkpoint 才会被保留。

可用的检查点存储选项

Flink打包了这些检查点存储类型:

  • JobManagerCheckpointStorage
  • FileSystemCheckpointStorage

如果配置了检查点目录,将使用FileSystemCheckpointStorage,否则系统将使用JobManagerCheckpointStorage。

JobManagerCheckpointStorage

JobManagerCheckpointStorage在JobManager的堆中存储检查点快照。

可以将它配置为在检查点超过一定大小时失效,以避免JobManager上的OutOfMemoryError。要设置这个特性,用户可以实例化一个JobManagerCheckpointStorage,并使用相应的最大大小:

new JobManagerCheckpointStorage(MAX_MEM_STATE_SIZE);

JobManagerCheckpointStorage的限制:

  • 默认情况下,每个单独状态的大小被限制为5 MB。这个值可以在JobManagerCheckpointStorage的构造函数中增加。
  • 不管配置的最大状态大小如何,状态不能大于 Akka frame size(参见配置)。
  • 聚合状态必须适合JobManager内存。

JobManagerCheckpointStorage被鼓励用于:

  • 本地开发调试
  • 使用很少状态的作业,例如只包含一次记录函数(Map、FlatMap、Filter,…)的作业。Kafka Consumer只需要很少的状态。
FileSystemCheckpointStorage

FileSystemCheckpointStorage配置了文件系统的URL(类型、地址、路径),如“hdfs://namenode:40010/flink/checkpoints或“file:///data/flink/checkpoints”。

在检查点时,它将状态快照写入配置的文件系统和目录中的文件。最小的元数据存储在JobManager的内存中(或者,在高可用模式下,存储在元数据检查点中)。

如果指定了检查点目录,将使用FileSystemCheckpointStorage持久化检查点快照。

FileSystemCheckpointStorage被鼓励用于:

  • 所有高可用性设置。

还建议将托管内存设置为零。这将确保为JVM上的用户代码分配最大的内存量。

检查点保留

检查点在默认情况下不会被保留,只用于从失败的作业中恢复作业。当一个程序被取消时,它们被删除。但是,您可以配置保留定期检查点。根据配置的不同,当作业失败或被取消时,不会自动清除这些保留的检查点。这样,如果您的工作失败了,您将有一个检查点来恢复。

CheckpointConfig config = env.getCheckpointConfig();
config.setExternalizedCheckpointCleanup(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);

ExternalizedCheckpointCleanup模式配置当你取消作业时检查点会发生什么:

  • ExternalizedCheckpointCleanup。retain_on_cancel:任务取消时保留检查点。注意,在这种情况下,取消后必须手动清除检查点状态。
  • ExternalizedCheckpointCleanup。delete_on_cancel:当作业取消时删除检查点。检查点状态仅在作业失败时可用。

目录结构

与保存点类似,检查点由元数据文件和一些附加数据文件组成,这取决于后端状态。元数据文件和数据文件存储在配置文件中通过state.checkpoints.dir配置的目录中,也可以在代码中为每个作业指定。

当前检查点目录布局(由FLINK-8531引入)如下:

/user-defined-checkpoint-dir
    /{job-id}
        |
        + --shared/
        + --taskowned/
        + --chk-1/
        + --chk-2/
        + --chk-3/
        ...        

SHARED目录用于可能是多个检查点的一部分的状态,TASKOWNED用于JobManager永远不能删除的状态,EXCLUSIVE用于只属于一个检查点的状态。

检查点目录不是公共API的一部分,可以在未来的版本中更改。

通过配置文件进行全局配置

state.checkpoints.dir: hdfs:///checkpoints/

在检查点配置上为每个作业配置

env.getCheckpointConfig().setCheckpointStorage("hdfs:///checkpoints-data/");

配置检查点存储实例

另外,可以通过指定所需的检查点存储实例来设置检查点存储,该实例允许设置诸如写缓冲区大小之类的低级配置。

env.getCheckpointConfig().setCheckpointStorage(
  new FileSystemCheckpointStorage("hdfs:///checkpoints-data/", FILE_SIZE_THESHOLD));

从保留的检查点恢复

通过使用检查点的元数据文件,作业可以从检查点恢复,就像从保存点恢复一样(参见保存点恢复指南)。注意,如果元数据文件不是自包含的,那么jobmanager需要访问它引用的数据文件(请参阅上面的目录结构)。

$ bin/flink run -s :checkpointMetaDataPath [:runArgs]

Checkpointing under backpressure

通常情况下,对齐 Checkpoint 的时长主要受 Checkpointing 过程中的同步和异步两个部分的影响。 然而,当 Flink 作业正运行在严重的背压下时,Checkpoint 端到端延迟的主要影响因子将会是传递 Checkpoint Barrier 到 所有的算子/子任务的时间。这在 checkpointing process) 的概述中有说明原因。并且可以通过高 alignment time and start delay metrics 观察到。 当这种情况发生并成为一个问题时,有三种方法可以解决这个问题:

  1. 消除背压源头,通过优化 Flink 作业,通过调整 Flink 或 JVM 参数,抑或是通过扩容。
  2. 减少 Flink 作业中缓冲在 In-flight 数据的数据量。
  3. 启用非对齐 Checkpoints。 这些选项并不是互斥的,可以组合在一起。本文档重点介绍后两个选项。

缓冲区 Debloating

Flink 1.14 引入了一个新的工具,用于自动控制在 Flink 算子/子任务之间缓冲的 In-flight 数据的数据量。缓冲区 Debloating 机 制可以通过将属性taskmanager.network.memory.buffer-debloat.enabled设置为true来启用。

此特性对对齐和非对齐 Checkpoint 都生效,并且在这两种情况下都能缩短 Checkpointing 的时间,不过 Debloating 的效果对于 对齐 Checkpoint 最明显。 当在非对齐 Checkpoint 情况下使用缓冲区 Debloating 时,额外的好处是 Checkpoint 大小会更小,并且恢复时间更快 (需要保存 和恢复的 In-flight 数据更少)。

有关缓冲区 Debloating 功能如何工作以及如何配置的更多信息,可以参考 network memory tuning guide。 请注意,您仍然可以继续使用在前面调优指南中介绍过的方式来手动减少缓冲在 In-flight 数据的数据量。

非对齐 Checkpoints

从Flink 1.11开始,Checkpoint 可以是非对齐的。 Unaligned checkpoints 包含 In-flight 数据(例如,存储在缓冲区中的数据)作为 Checkpoint State的一部分,允许 Checkpoint Barrier 跨越这些缓冲区。因此, Checkpoint 时长变得与当前吞吐量无关,因为 Checkpoint Barrier 实际上已经不再嵌入到数据流当中。

如果您的 Checkpointing 由于背压导致周期非常的长,您应该使用非对齐 Checkpoint。这样,Checkpointing 时间基本上就与 端到端延迟无关。请注意,非对齐 Checkpointing 会增加状态存储的 I/O,因此当状态存储的 I/O 是 整个 Checkpointing 过程当中真 正的瓶颈时,您不应当使用非对齐 Checkpointing。

为了启用非对齐 Checkpoint,您可以:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

// 启用非对齐 Checkpoint
env.getCheckpointConfig().enableUnalignedCheckpoints();

或者在 flink-conf.yml 配置文件中增加配置:

execution.checkpointing.unaligned: true

对齐 Checkpoint 的超时

在启用非对齐 Checkpoint 后,你依然可以通过编程的方式指定对齐 Checkpoint 的超时:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.getCheckpointConfig().setAlignedCheckpointTimeout(Duration.ofSeconds(30));

或是在 flink-conf.yml 配置文件中配置:

execution.checkpointing.aligned-checkpoint-timeout: 30 s

在启动时,每个 Checkpoint 仍将作为对齐 Checkpoint 开始,但是如果全局 Checkpoint 开始的时间和某个子任务上 Checkpoint 开始的时间相差超过了对齐 Checkpoint 的超时时间,那么 Checkpoint 将会作为非对齐 Checkpoint 处理。

限制

并发 Checkpoint

Flink 当前并不支持并发的非对齐 Checkpoint。然而,由于更可预测的和更短的 Checkpointing 时长,可能也根本就不需要并发的 Checkpoint。此外,Savepoint 也不能与非对齐 Checkpoint 同时发生,因此它们将会花费稍长的时间。

与 Watermark 的相互影响

非对齐 Checkpoint 在恢复的过程中改变了关于 Watermark 的一个隐式保证。目前,Flink 确保了 Watermark 作为恢复的第一步, 而不是将最近的 Watermark 存放在 Operator 中,以方便扩缩容。在非对齐 Checkpoint 中,这意味着当恢复时,** Flink 会在恢复 In-flight 数据后再生成 Watermark 。如果您的 Pipeline 中使用了对每条记录都应用最新的 Watermark 的算子将会相对于 使用对齐 Checkpoint产生不同的结果**。如果您的 Operator 依赖于最新的 Watermark 始终可用,解决办法是将 Watermark 存放在 OperatorState 中。在这种情况下,Watermark 应该使用单键 group 存放在 UnionState 以方便扩缩容。

与长时间运行的记录处理相互作用

尽管没有对齐的检查点,障碍物仍然能够超过队列中的所有其他记录。如果当前记录需要大量的时间来处理,这个屏障的处理仍然可以延迟。这种情况可能发生在一次触发多个计时器时,例如在窗口操作中。第二个有问题的场景可能发生在处理单个输入记录时,当系统阻塞,等待多个网络缓冲区可用性时。Flink不能中断单个输入记录的处理,并且未对齐的检查点必须等待当前处理的记录被完全处理。
这可能会在两种情况下导致问题。这要么是由于大记录的序列化(无法放入单个网络缓冲区),要么是由于flatMap操作(为一个输入记录生成许多输出记录)。在这种情况下,反压会阻塞未对齐的检查点,直到处理单个输入记录所需的所有网络缓冲区都可用为止。在处理单个记录需要一段时间的任何其他情况下也可能发生这种情况。因此,检查点的时间可能比预期的要高,也可能会发生变化。

某些数据分布模式不是检查点

有一部分包含属性的的连接无法与 Channel 中的数据一样保存在 Checkpoint 中。为了保留这些特性并且确保没有状态冲突或 非预期的行为,非对齐 Checkpoint 对于这些类型的连接是禁用的。所有其他的交换仍然执行非对齐 Checkpoint。

点对点连接

我们目前没有任何对于点对点连接中有关数据有序性的强保证。然而,由于数据已经被以前置的 Source 或是 KeyBy 相同的方式隐式 组织,一些用户会依靠这种特性在提供的有序性保证的同时将计算敏感型的任务划分为更小的块。

只要并行度不变,非对齐 Checkpoint(UC) 将会保留这些特性。但是如果加上UC的伸缩容,这些特性将会被改变。

针对如下任务
Flink操作——状态与容错_第1张图片
如果我们想将并行度从 p=2 扩容到 p=3,那么需要根据 KeyGroup 将 KeyBy 的 Channel 中的数据突然的划分到3个 Channel 中去。这 很容易做到,通过使用 Operator 的 KeyGroup 范围和确定记录属于某个 Key(group) 的方法(不管实际使用的是什么方法)。对于 Forward 的 Channel,我们根本没有 KeyContext。Forward Channel 里也没有任何记录被分配了任何 KeyGroup;也无法计算它,因为无法保证 Key仍然存在。

广播 Connections

广播 Connection 带来了另一个问题。无法保证所有 Channel 中的记录都以相同的速率被消费。这可能导致某些 Task 已经应用了与 特定广播事件对应的状态变更,而其他任务则没有,如图所示。

Flink操作——状态与容错_第2张图片
广播分区通常用于实现广播状态,它应该跨所有 Operator 都相同。Flink 实现广播状态,通过仅 Checkpointing 有状态算子的 SubTask 0 中状态的单份副本。在恢复时,我们将该份副本发往所有的 Operator。因此,可能会发生以下情况:某个算子将很快从它的 Checkpointed Channel 消费数据并将修改应有于记录来获得状态。

Troubleshooting

损坏的动态数据

以下描述的操作是最后采取的手段,因为它们将会导致数据的丢失。

为了防止 In-flight 数据损坏,或者由于其他原因导致作业应该在没有 In-flight 数据的情况下恢复,可以使用 recover-without-channel-state.checkpoint-id 属性。该属性需要指定一个 Checkpoint Id,对它来说 In-flight 中的数据将会被忽略。除非已经持久化的 In-flight 数据内部的损坏导致无 法恢复的情况,否则不要设置该属性。只有在重新部署作业后该属性才会生效,这就意味着只有启用 externalized checkpoint
时,此操作才有意义。

Savepoints

什么是 Savepoint ?

Savepoint 是依据 Flink checkpointing 机制所创建的流作业执行状态的一致镜像。 你可以使用 Savepoint 进行 Flink 作业的停止与重启、fork 或者更新。 Savepoint 由两部分组成:稳定存储(列入 HDFS,S3,…) 上包含二进制文件的目录(通常很大),和元数据文件(相对较小)。 稳定存储上的文件表示作业执行状态的数据镜像。 Savepoint 的元数据文件以(相对路径)的形式包含(主要)指向作为 Savepoint 一部分的稳定存储上的所有文件的指针。

为了正确使用保存点,重要的是要理解检查点和保存点之间的区别,这在检查点和保存点中有描述。

分配算子 ID

强烈建议你按照本节所述调整你的程序,以便将来能够升级你的程序。主要通过 uid(String) 方法手动指定算子 ID 。这些 ID 将用于恢复每个算子的状态。

DataStream<String> stream = env.
  // Stateful source (e.g. Kafka) with ID
  .addSource(new StatefulSource())
  .uid("source-id") // ID for the source operator
  .shuffle()
  // Stateful mapper with ID
  .map(new StatefulMapper())
  .uid("mapper-id") // ID for the mapper
  // Stateless printing sink
  .print(); // Auto-generated ID

如果不手动指定 ID ,则会自动生成 ID 。只要这些 ID 不变,就可以从 Savepoint 自动恢复。生成的 ID 取决于程序的结构,并且对程序更改很敏感。因此,强烈建议手动分配这些 ID 。

Savepoint 状态

你可以将 Savepoint 想象为每个有状态的算子保存一个映射“算子 ID ->状态”:

Operator ID | State
------------+------------------------
source-id   | State of StatefulSource
mapper-id   | State of StatefulMapper

在上面的示例中,print sink 是无状态的,因此不是 Savepoint 状态的一部分。默认情况下,我们尝试将 Savepoint 的每个条目映射回新程序。

算子

你可以使用命令行客户端来触发 Savepoint,触发 Savepoint 并取消作业,从 Savepoint 恢复,以及删除 Savepoint。

从 Flink 1.2.0 开始,还可以使用 webui 从 Savepoint 恢复。

触发 Savepoint

当触发 Savepoint 时,将创建一个新的 Savepoint 目录,其中存储数据和元数据。可以通过配置默认目标目录或使用触发器命令指定自定义目标目录(参见:targetDirectory参数来控制该目录的位置。

注意: 目标目录必须是 JobManager(s) 和 TaskManager(s) 都可以访问的位置,例如分布式文件系统(或者对象存储系统)上的位置。

以 FsStateBackend 或 RocksDBStateBackend 为例:

# Savepoint 目标目录
/savepoint/

# Savepoint 目录
/savepoint/savepoint-:shortjobid-:savepointid/

# Savepoint 文件包含 Checkpoint元数据
/savepoint/savepoint-:shortjobid-:savepointid/_metadata

# Savepoint 状态
/savepoint/savepoint-:shortjobid-:savepointid/...

从 1.11.0 开始,你可以通过移动(拷贝)savepoint 目录到任意地方,然后再进行恢复。

在如下两种情况中不支持 savepoint 目录的移动:1)如果启用了 entropy injection :这种情况下,savepoint 目录不包含所有的数据文件,因为注入的路径会分散在各个路径中。 由于缺乏一个共同的根目录,因此 savepoint 将包含绝对路径,从而导致无法支持 savepoint 目录的迁移。2)作业包含了 task-owned state(比如 GenericWriteAhreadLog sink)。

和 savepoint 不同,checkpoint 不支持任意移动文件,因为 checkpoint 可能包含一些文件的绝对路径。

如果你使用 MemoryStateBackend 的话,metadata 和 savepoint 的数据都会保存在 _metadata 文件中,因此不要因为没看到目录下没有数据文件而困惑。

注意: 不建议移动或删除正在运行作业的最后一个 Savepoint ,因为这可能会干扰故障恢复。因此,Savepoint 对精确一次的接收器有副作用,为了确保精确一次的语义,如果在最后一个 Savepoint 之后没有 Checkpoint ,那么将使用 Savepoint 进行恢复。

Savepoint 格式

你可以在 savepoint 的两种二进制格式之间进行选择:

  • 标准格式 - 一种在所有 state backends 间统一的格式,允许你使用一种状态后端创建 savepoint 后,使用另一种状态后端恢复这个 savepoint。这是最稳定的格式,旨在与之前的版本、模式、修改等保持最大兼容性。
  • 原生格式 - 标准格式的缺点是它的创建和恢复速度通常很慢。原生格式以特定于使用的状态后端的格式创建快照(例如 RocksDB 的 SST 文件)。

以原生格式创建 savepoint 的能力在 Flink 1.15 中引入,在那之前 savepoint 都是以标准格式创建的。

触发 Savepoint
$ bin/flink savepoint :jobId [:targetDirectory]

这将触发 ID 为 :jobId 的作业的 Savepoint,并返回创建的 Savepoint 路径。 你需要此路径来恢复和删除 Savepoint 。你也可以指定创建 Savepoint 的格式。如果没有指定,会采用标准格式创建 Savepoint。

$ bin/flink savepoint --type [native/canonical] :jobId [:targetDirectory]
使用 YARN 触发 Savepoint
$ bin/flink savepoint :jobId [:targetDirectory] -yid :yarnAppId

这将触发 ID 为 :jobId 和 YARN 应用程序 ID :yarnAppId 的作业的 Savepoint,并返回创建的 Savepoint 的路径。

使用 Savepoint 停止作业
$ bin/flink stop --type [native/canonical] --savepointPath [:targetDirectory] :jobId

这将自动触发 ID 为 :jobid 的作业的 Savepoint,并停止该作业。此外,你可以指定一个目标文件系统目录来存储 Savepoint 。该目录需要能被 JobManager(s) 和 TaskManager(s) 访问。你也可以指定创建 Savepoint 的格式。如果没有指定,会采用标准格式创建 Savepoint。

从 Savepoint 恢复

$ bin/flink run -s :savepointPath [:runArgs]

这将提交作业并指定要从中恢复的 Savepoint 。 你可以给出 Savepoint 目录或 _metadata 文件的路径。

跳过无法映射的状态恢复

默认情况下,resume 操作将尝试将 Savepoint 的所有状态映射回你要还原的程序。 如果删除了运算符,则可以通过 --allowNonRestoredState(short:-n)选项跳过无法映射到新程序的状态:

Restore 模式

Restore 模式 决定了在 restore 之后谁拥有Savepoint 或者 externalized checkpoint的文件的所有权。在这种语境下 Savepoint 和 externalized checkpoint 的行为相似。 这里我们将它们都称为“快照”,除非另有明确说明。

如前所述,restore 模式决定了谁来接管我们从中恢复的快照文件的所有权。快照可被用户或者 Flink 自身拥有。如果快照归用户所有,Flink 不会删除其中的文件,而且 Flink 不能依赖该快照中文件的存在,因为它可能在 Flink 的控制之外被删除。

每种 restore 模式都有特定的用途。尽管如此,我们仍然认为默认的 NO_CLAIM 模式在大多数情况下是一个很好的折中方案,因为它在提供明确的所有权归属的同时只给恢复后第一个 checkpoint 带来较小的代价。

你可以通过如下方式指定 restore 模式:

$ bin/flink run -s :savepointPath -restoreMode :mode -n [:runArgs]
NO_CLAIM (默认的)

在 NO_CLAIM 模式下,Flink 不会接管快照的所有权。它会将快照的文件置于用户的控制之中,并且永远不会删除其中的任何文件。该模式下可以从同一个快照上启动多个作业。

为保证 Flink 不会依赖于该快照的任何文件,它会强制第一个(成功的) checkpoint 为全量 checkpoint 而不是增量的。这仅对state.backend: rocksdb 有影响,因为其他 backend 总是创建全量 checkpoint。

一旦第一个全量的 checkpoint 完成后,所有后续的 checkpoint 会照常创建。所以,一旦一个 checkpoint 成功制作,就可以删除原快照。在此之前不能删除原快照,因为没有任何完成的 checkpoint,Flink 会在故障时尝试从初始的快照恢复。

Flink操作——状态与容错_第3张图片

CLAIM

另一个可选的模式是 CLAIM 模式。该模式下 Flink 将声称拥有快照的所有权,并且本质上将其作为 checkpoint 对待:控制其生命周期并且可能会在其永远不会被用于恢复的时候删除它。因此,手动删除快照和从同一个快照上启动两个作业都是不安全的。Flink 会保持配置数量的 checkpoint。

Flink操作——状态与容错_第4张图片
注意:

  1. Retained checkpoints 被存储在 //chk- 这样的目录中。Flink 不会接管 / 目录的所有权,而只会接管 chk- 的所有权。Flink 不会删除旧作业的目录。
  2. Native 格式支持增量的 RocksDB savepoints。对于这些 savepoints,Flink 将所有 SST 存储在 savepoints 目录中。这意味着这些 savepoints 是自包含和目录可移动的。然而,在 CLAIM 模式下恢复时,后续的 checkpoints 可能会复用一些 SST 文件,这反过来会阻止在 savepoints 被清理时删除 savepoints 目录。 Flink 之后运行期间可能会删除复用的SST 文件,但不会删除 savepoints 目录。因此,如果在 CLAIM 模式下恢复,Flink 可能会留下一个空的 savepoints 目录。
LEGACY

Legacy 模式是 Flink 在 1.15 之前的工作方式。该模式下 Flink 永远不会删除初始恢复的 checkpoint。同时,用户也不清楚是否可以删除它。导致该的问题原因是, Flink 会在用来恢复的 checkpoint 之上创建增量的 checkpoint,因此后续的 checkpoint 都有可能会依赖于用于恢复的那个 checkpoint。总而言之,恢复的 checkpoint 的所有权没有明确的界定。

Flink操作——状态与容错_第5张图片

删除 Savepoint

$ bin/flink savepoint -d :savepointPath

这将删除存储在 :savepointPath 中的 Savepoint。

请注意,还可以通过常规文件系统操作手动删除 Savepoint ,而不会影响其他 Savepoint 或 Checkpoint(请记住,每个 Savepoint 都是自包含的)。 在 Flink 1.2 之前,使用上面的 Savepoint 命令执行是一个更乏味的任务。

配置

你可以通过 state.savepoints.dir 配置 savepoint 的默认目录。 触发 savepoint 时,将使用此目录来存储 savepoint。 你可以通过使用触发器命令指定自定义目标目录来覆盖缺省值(请参阅:targetDirectory参数)。

# 默认 Savepoint 目标目录
state.savepoints.dir: hdfs:///flink/savepoints

如果既未配置缺省值也未指定自定义目标目录,则触发 Savepoint 将失败。

注意: 目标目录必须是 JobManager(s) 和 TaskManager(s) 可访问的位置,例如,分布式文件系统上的位置。

F.A.Q

我应该为我作业中的所有算子分配 ID 吗?

根据经验,是的。 严格来说,仅通过 uid 方法给有状态算子分配 ID 就足够了。Savepoint 仅包含这些有状态算子的状态,无状态算子不是 Savepoint 的一部分。

在实践中,建议给所有算子分配 ID,因为 Flink 的一些内置算子(如 Window 算子)也是有状态的,而内置算子是否有状态并不很明显。 如果你完全确定算子是无状态的,则可以跳过 uid 方法。

如果我在作业中添加一个需要状态的新算子,会发生什么?

当你向作业添加新算子时,它将在没有任何状态的情况下进行初始化。 Savepoint 包含每个有状态算子的状态。 无状态算子根本不是 Savepoint 的一部分。 新算子的行为类似于无状态算子。

如果从作业中删除有状态的算子会发生什么?

默认情况下,从 Savepoint 恢复时将尝试将所有状态分配给新作业。如果有状态算子被删除,则无法从 Savepoint 恢复。

你可以通过使用 run 命令设置 --allowNonRestoredState (简称:-n )来允许删除有状态算子:

$ bin/flink run -s :savepointPath -n [:runArgs]

如果我在作业中重新排序有状态算子,会发生什么?

如果给这些算子分配了 ID,它们将像往常一样恢复。

如果没有分配 ID ,则有状态操作符自动生成的 ID 很可能在重新排序后发生更改。这将导致你无法从以前的 Savepoint 恢复。

如果我添加、删除或重新排序作业中没有状态的算子,会发生什么?

如果将 ID 分配给有状态算子,则无状态算子不会影响 Savepoint 恢复。

如果没有分配 ID ,则有状态算子自动生成的 ID 很可能在重新排序后发生更改。这将导致你无法从以前的Savepoint 恢复。

当我在恢复时改变程序的并行度时会发生什么?

如果 Savepoint 是用 Flink >= 1.2.0 触发的,并且没有使用像 Checkpointed 这样的不推荐的状态API,那么你可以简单地从 Savepoint 恢复程序并指定新的并行度。

如果你正在从 Flink < 1.2.0 触发的 Savepoint 恢复,或者使用现在已经废弃的 api,那么你首先必须将作业和 Savepoint 迁移到 Flink >= 1.2.0,然后才能更改并行度。参见升级作业和Flink版本指南。

我可以将 savepoint 文件移动到稳定存储上吗?

这个问题的快速答案目前是“是”,从 Flink 1.11.0 版本开始,savepoint 是自包含的,你可以按需迁移 savepoint 文件后进行恢复。

Checkpoints vs. Savepoints

Overview

从概念上讲,Flink的保存点与检查点不同,就像传统数据库系统中的备份与恢复日志的不同一样。

检查点的主要目的是在意外作业失败时提供恢复机制。一个检查点的生命周期是由Flink管理的,即一个检查点是由Flink创建、拥有和发布的,不需要用户交互。因为检查点经常被触发,并且故障恢复依赖于它,检查点实现的两个主要设计目标是i)尽可能轻地创建和ii)尽可能快地恢复。针对这些目标的优化可以利用某些属性,例如,作业代码在执行尝试之间不会改变。

  • 如果应用程序被用户终止,检查点将被自动删除(除非检查点被显式配置为保留)。
  • 检查点以特定于状态后端(本机)的数据格式存储(根据特定后端可能是增量的)。

尽管保存点是用与检查点相同的机制在内部创建的,但它们在概念上是不同的,而且生成和恢复的成本可能会更高一些。他们的设计更注重可移植性和操作灵活性,特别是在工作更改方面。保存点的用例用于计划的手动操作。例如,这可能是Flink版本的更新,更改工作图,等等。

  • 保存点完全由用户创建、拥有和删除。这意味着,在作业终止后或恢复后,Flink都不会删除保存点。
  • 保存点以独立于状态后端(规范)的格式存储(注意:自Flink 1.15以来,保存点也可以以特定于后端的本机格式存储,这种格式创建和恢复更快,但也有一些限制。

功能和限制

下表概述了各种类型的保存点和检查点的功能和限制。

  • ✓该类型快照完全支持
  • x - Flink不支持这种类型的快照
  • ! -虽然这些操作目前是可行的,但Flink并没有正式保证支持它们,所以它们有一定程度的风险

Flink操作——状态与容错_第6张图片
State backend change - 配置与快照时使用的状态后端不同的状态后端。
State Processor API (writing) - 通过State Processor API创建这种类型的新快照的能力。
State Processor API (reading) - 通过State Processor API从现有的这种类型快照读取状态的能力。
Self-contained and relocatable - 一个快照文件夹包含恢复所需的一切,它不依赖于其他快照,这意味着如果需要,它可以很容易地移动到另一个地方。
Schema evolution - 如果使用支持模式演化的序列化器(例如pojo和Avro类型),状态数据类型可以改变。
Arbitrary job upgrade - 即使现有操作符的分区类型(rescale、rebalance、map等)或飞行记录类型发生了更改,快照也可以恢复。
Non-arbitrary job upgrade - 如果作业图拓扑和动态记录类型保持不变,则可以使用更新的操作恢复快照。
Flink minor version upgrade - 用Flink的小版本恢复快照(1。x→1. y)。
Flink bug/patch version upgrade - 恢复用Flink的旧补丁版本(1.14。x→1.14.y)。
Rescaling - 使用与创建快照时不同的并行度恢复快照。

大状态与 Checkpoint 调优

本页提供了如何配置和调优使用大状态的应用程序的指南。

Flink应用程序要在大规模环境下可靠运行,必须满足两个条件:

  • 应用程序需要能够可靠地接受检查点
  • 在发生故障后,资源需要足够跟上输入数据流

第一部分讨论了如何在规模上获得执行良好的检查点。最后一节解释了一些关于规划使用多少资源的最佳实践。

监视状态和检查点

监视检查点行为的最简单方法是通过UI的检查点部分。检查点监视的文档说明了如何访问可用的检查点度量。
当扩展检查点时,有两个数字(都是通过任务级别指标和web界面)非常有趣:

  • 当触发检查点的时间一直很高时,这意味着检查点的barrier需要很长时间从source 传递到所有算子。这通常表明系统在恒定的反压力下运行。
  • 对齐持续时间,它被定义为从第一个接收到最后一个检查点barrier之间的时间。在未对齐的精确一次检查点和至少一次检查点子任务处理来自上游子任务的所有数据时,不会有任何中断。然而,使用一次对齐检查点,已经接收到检查点barrier的通道将被阻止发送进一步的数据,直到所有剩余通道赶上并接收到他们的检查点屏障(对齐时间)。

理想情况下,这两个值都应该很低—较高的值意味着检查点障碍通过job graph的速度较慢,这是由于一些反向压力(没有足够的资源来处理传入的记录)。这也可以通过增加已处理记录的端到端延迟来观察。请注意,在出现瞬态背压、数据倾斜或网络问题时,这些数字有时会很高。

未对齐的检查点可用于加快检查点barrier的传播时间。但是请注意,这并不能解决导致反压的根本问题(端到端记录延迟将保持很高)。

调优检查点

检查点按应用程序可以配置的定期间隔触发。当检查点完成的时间超过检查点间隔时,在下一个检查点完成之前不会触发下一个检查点。默认情况下,一旦正在进行的检查点完成,下一个检查点将立即被触发。

当检查点花费的时间经常超过基本间隔时(例如,因为状态增长比计划的要大,或者存储检查点的存储速度临时变慢),系统会不断地使用检查点(一旦运行完成,新的检查点就会立即启动)。这可能意味着太多的资源经常被占用在检查点上,而算子取得的进展太少。此行为对使用异步检查点状态的流应用程序影响较小,但仍可能对应用程序的整体性能产生影响。

为了防止这种情况,应用程序可以定义检查点之间的最小持续时间:

StreamExecutionEnvironment.getCheckpointConfig().setMinPauseBetweenCheckpoints(milliseconds);

这个持续时间是最近一个检查点结束和下一个检查点开始之间必须经过的最小时间间隔。下图说明了这是如何影响检查点的。

Flink操作——状态与容错_第7张图片

注意:可以对应用程序进行配置(通过CheckpointConfig),以允许同时进行多个检查点。对于Flink中状态较大的应用程序,这通常会在检查点中占用太多的资源。当手动触发一个保存点时,它可能与正在进行的检查点并发处理。

调优RocksDB

许多大型Flink流媒体应用的状态存储主力是RocksDB状态后端。后端扩展远远超过主内存,并可靠地存储大键控状态。

RocksDB的性能随着配置的不同而不同,本节概述了一些使用RocksDB状态后端调优作业的最佳实践。

增量检查点

当谈到减少检查点所花费的时间时,激活增量检查点应该是首先考虑的事项之一。与完整检查点相比,增量检查点可以显著减少检查点时间,因为增量检查点只记录与之前完成的检查点相比的更改,而不是生成状态后端的完整的、自包含的备份。

计时器在RocksDB或JVM堆上

计时器默认存储在RocksDB中,这是一个更健壮和可扩展的选择。

当性能调优作业只有很少的计时器(没有窗口,在ProcessFunction中不使用计时器)时,将这些计时器放在堆上可以提高性能。请谨慎使用此特性,因为基于堆的计时器可能会增加检查点时间,并且自然无法扩展到内存之外。

调优RocksDB内存

RocksDB状态后端的性能很大程度上取决于它可用的内存数量。为了提高性能,增加内存会有很大帮助,或者调整内存的功能。

默认情况下,RocksDB状态后端使用Flink的管理内存预算用于RocksDB缓冲区和缓存(State . Backend . RocksDB .memory. memory)。管理:真实)。请参考RocksDB内存管理来了解该机制是如何工作的。

要调优与内存相关的性能问题,以下步骤可能会有所帮助:

  • 尝试提高性能的第一步应该是增加托管内存的数量。这通常会大大改善情况,而不会增加调优低阶RocksDB选项的复杂性。
    特别是对于大型容器/进程,大部分内存通常都可以进入RocksDB,除非应用程序逻辑本身需要大量JVM堆。默认的托管内存比例(0.4)是保守的,当使用带有多gb进程大小的taskmanager时,通常可以增加。
  • RocksDB中写缓冲区的数量取决于应用程序中状态的数量(管道中所有操作符的状态)。每个状态对应一个ColumnFamily,它需要自己的写缓冲区。因此,具有多种状态的应用程序通常需要更多内存才能获得相同的性能。
  • 通过设置state.backend.rocksdb.memory.managed: false,你可以尝试比较使用托管内存的RocksDB与使用每列族内存的RocksDB的性能。特别是在测试基线时(假设没有或优雅的容器内存限制),或者测试与Flink早期版本相比的回归时,这可能是有用的。
    与托管内存设置(固定内存池)相比,不使用托管内存意味着RocksDB分配的内存与应用程序中的状态数成比例(内存占用随应用程序的变化而变化)。根据经验,非托管模式的上限大约为“140MB * num-states-across-all-tasks * num-slots”(除非应用ColumnFamily选项)。计时器也可以计算状态!
  • 如果你的应用程序有很多状态,并且你看到频繁的MemTable刷新(写端瓶颈),但是你不能提供更多的内存,你可以增加进入写缓冲区的内存比例(state.backend.rocksdb.memory.write-buffer-ratio)。详细信息请参见RocksDB内存管理。
  • 一个高级的选项(专家模式),以减少MemTable刷新的数量设置与许多状态,是调RocksDB的ColumnFamily选项(竞技场块大小,最大后台刷新线程,等),通过RocksDBOptionsFactory:
public class MyOptionsFactory implements ConfigurableRocksDBOptionsFactory {

    @Override
    public DBOptions createDBOptions(DBOptions currentOptions, Collection<AutoCloseable> handlesToClose) {
        // increase the max background flush threads when we have many states in one operator,
        // which means we would have many column families in one DB instance.
        return currentOptions.setMaxBackgroundFlushes(4);
    }

    @Override
    public ColumnFamilyOptions createColumnOptions(
        ColumnFamilyOptions currentOptions, Collection<AutoCloseable> handlesToClose) {
        // decrease the arena block size from default 8MB to 1MB. 
        return currentOptions.setArenaBlockSize(1024 * 1024);
    }

    @Override
    public OptionsFactory configure(ReadableConfig configuration) {
        return this;
    }
}

容量规划

本节讨论如何决定一个Flink作业应该使用多少资源才能可靠地运行。容量规划的基本经验规则如下:

  • 正常操作应该有足够的容量,而不是在恒定的背压下操作。有关如何检查应用程序是否在背压下运行的详细信息,请参见背压监控。
  • 在无故障期间无反压运行程序所需的资源之上提供一些额外资源。需要这些资源来“赶上”应用程序恢复期间积累的输入数据。具体的恢复时间取决于恢复操作通常需要多长时间(这取决于故障转移时需要加载到新taskmanager中的状态大小),以及场景需要多快的故障恢复速度。
    要点:基线应该在激活检查点的情况下建立,因为检查点会占用一定数量的资源(比如网络带宽)。
  • 暂时的回压通常是可以的,在负载峰值期间、在追赶阶段或当外部系统(在接收中写入)出现临时减速时,这是执行流控制的一个重要部分。
  • 某些操作(如大窗口)会导致其下游算子的负载增加:对于窗口,下游算子在构建窗口时可能没什么事做,而在窗口发出时则有负载要做。对下游并行性的规划需要考虑窗口发出多少信号,以及处理这种峰值的速度。

重要提示:为了允许以后添加资源,请确保将数据流程序的最大并行度设置为一个合理的数字。最大并行度定义了在重新缩放程序(通过保存点)时可以设置程序并行度的高度。

Flink的内部簿记以最大并行度-多键组的粒度跟踪并行状态。Flink的设计力求使其高效,即使以较低的并行度执行程序,也能获得非常高的并行度值。

压缩

Flink为所有检查点和保存点提供可选的压缩(默认为关闭)。目前,压缩总是使用snappy压缩算法(版本1.1.4),但我们计划在未来支持自定义压缩算法。压缩工作在键控状态下的键组粒度,即每个键组可以单独解压,这对重新缩放很重要。
压缩可以通过ExecutionConfig激活:

ExecutionConfig executionConfig = new ExecutionConfig();
executionConfig.setUseSnapshotCompression(true);

注意:压缩选项对增量快照没有影响,因为它们使用的是RocksDB的内部格式,总是使用开箱即用的快速压缩。

Task-Local Recovery

动机

在Flink的检查点中,每个任务生成其状态的快照,然后将其写入分布式存储。每个任务通过发送一个描述状态在分布式存储中的位置的句柄来向作业管理器确认状态的成功写入。作业管理器依次从所有任务收集句柄,并将它们捆绑到检查点对象中。

在恢复时,作业管理器打开最新的检查点对象,并将句柄发送回相应的任务,然后这些任务可以从分布式存储中恢复它们的状态。使用分布式存储来存储状态有两个重要的优点。首先,存储是容错的,其次,分布式存储中的所有状态对所有节点都是可访问的,并且可以很容易地重新分布(例如重新缩放)。

然而,使用远程分布式存储也有一个很大的缺点:所有任务都必须通过网络从远程位置读取它们的状态。在许多场景中,恢复可以将失败的任务重新调度到与前一次运行相同的任务管理器中(当然,也有机器故障等例外情况),但我们仍然需要读取远程状态。这可能导致大状态的恢复时间很长,即使在一台机器上只有一个小故障。

方法

任务本地状态恢复正是针对恢复时间长这个问题,其主要思想如下:对于每个检查点,每个任务不仅将任务状态写入分布式存储,而且在任务本地存储(例如本地磁盘或内存)中保存状态快照的辅助副本。请注意,快照的主存储必须仍然是分布式存储,因为本地存储不能确保节点故障下的持久性,也不能为其他节点提供重分发状态的访问,因此该功能仍然需要主副本。

但是,对于每个可以重新调度到前一个位置进行恢复的任务,我们可以从次要的本地副本恢复状态,并避免远程读取状态的成本。考虑到许多故障不是节点故障,而且节点故障通常一次只影响一个或很少几个节点,在恢复过程中,大多数任务很可能会返回到它们之前的位置,并发现它们的本地状态完好无损。这就是本地恢复能够有效减少恢复时间的原因。

请注意,根据所选择的状态后端和检查点策略,创建和存储次要本地状态副本可能会为每个检查点带来一些额外的成本。例如,在大多数情况下,实现将简单地将对分布式存储的写操作复制到本地文件中。
Flink操作——状态与容错_第8张图片

主要(分布式存储)和次要(任务本地)状态快照的关系

任务本地状态总是被认为是一个次要副本,检查点状态的基础真实值是分布式存储中的主要副本。这对检查点和恢复期间的本地状态问题有影响:

  • 对于检查点,主副本必须成功,而生成次要本地副本的失败将不会使检查点失败。如果无法创建主副本,检查点将失败,即使已成功创建了辅助副本。
  • 只有主副本由作业管理器确认和管理,次要副本由任务管理器拥有,其生命周期可以独立于主副本。例如,可以保留最近3个检查点的历史记录作为主要副本,只保留最新检查点的任务本地状态。
  • 对于恢复,如果有匹配的辅助副本可用,Flink将始终尝试首先从任务本地状态恢复。如果从辅助副本恢复过程中发生任何问题,Flink将透明地重试从主副本恢复任务。只有当主副本和(可选)从副本失败时,恢复才会失败。在这种情况下,根据配置,Flink仍然可以退回到旧的检查点。
  • 任务本地状态可以有不同于主状态的格式,它们不需要字节相同。例如,甚至有可能任务本地状态是由堆对象组成的内存中状态,而不存储在任何文件中。
  • 如果任务管理器丢失,则其所有任务的本地状态将丢失。

配置task-local恢复

任务本地恢复在默认情况下是不激活的,可以通过Flink的key state.backend配置激活。在CheckpointingOptions.LOCAL_RECOVERY中指定local-recovery。此设置的值可以为true启用本地恢复,也可以为false(默认)禁用本地恢复。

请注意,未对齐的检查点目前不支持任务本地恢复。

关于不同状态后端的任务本地恢复的详细信息

限制:目前,任务本地恢复仅覆盖键控状态后端。keyedstate通常是该state最大的部分。在不久的将来,我们还将讨论算子状态和计时器。

以下状态后端可以支持任务本地恢复。

  • FsStateBackend:支持key状态的任务本地恢复。该实现将状态复制到本地文件。这可能会引入额外的写成本,并占用本地磁盘空间。将来,我们还可能提供一种将任务本地状态保存在内存中的实现。

  • RocksDBStateBackend:对键控状态支持任务本地恢复。对于完整检查点,状态被复制到本地文件。这可能会引入额外的写成本,并占用本地磁盘空间。对于增量快照,本地状态基于RocksDB的本地检查点机制。这种机制还被用作创建主副本的第一步,这意味着在这种情况下,创建副副本不会引入额外的成本。我们只需保留本机检查点目录,而不是在上传到分布式存储后删除它。这个本地副本可以与RocksDB的工作目录共享活动文件(通过硬链接),因此对于活动文件,使用增量快照进行任务本地恢复也不会占用额外的磁盘空间。使用硬链接还意味着RocksDB目录必须与所有可用于存储本地状态的配置本地恢复目录在同一物理设备上,否则建立硬链接可能会失败(参见FLINK-10954)。目前,当RocksDB目录被配置为位于多个物理设备上时,这也阻止了使用本地恢复。

Allocation-preserving调度

任务本地恢复假设发生故障时保持分配的任务调度,其工作原理如下。每个任务都会记住它之前的分配,并请求完全相同的槽位在恢复中重新启动。如果这个插槽不可用,任务将从资源管理器请求一个新的、新的插槽。这样,如果任务管理器不再可用,无法返回到以前位置的任务将不会将其他恢复任务从它们以前的槽位中赶出。我们的理由是,只有当任务管理器不再可用时,前一个插槽才会消失,在这种情况下,一些任务无论如何都必须请求一个新的插槽。通过我们的调度策略,我们使最大数量的任务有机会从它们的本地状态恢复,并避免了任务相互窃取之前的插槽的级联效应。

Task 故障恢复

当 Task 发生故障时,Flink 需要重启出错的 Task 以及其他受到影响的 Task ,以使得作业恢复到正常执行状态。

Flink 通过重启策略和故障恢复策略来控制 Task 重启:重启策略决定是否可以重启以及重启的间隔;故障恢复策略决定哪些 Task 需要重启。

Restart Strategies

Flink 作业如果没有定义重启策略,则会遵循集群启动时加载的默认重启策略。 如果提交作业时设置了重启策略,该策略将覆盖掉集群的默认策略。

通过 Flink 的配置文件 flink-conf.yaml 来设置默认的重启策略。配置参数 restart-strategy 定义了采取何种策略。 如果没有启用 checkpoint,就采用“不重启”策略。如果启用了 checkpoint 且没有配置重启策略,那么就采用固定延时重启策略, 此时最大尝试重启次数由 Integer.MAX_VALUE 参数设置。下表列出了可用的重启策略和与其对应的配置值。

每个重启策略都有自己的一组配置参数来控制其行为。 这些参数也在配置文件中设置。 后文的描述中会详细介绍每种重启策略的配置项。

Flink操作——状态与容错_第9张图片
除了定义默认的重启策略以外,还可以为每个 Flink 作业单独定义重启策略。 这个重启策略通过在程序中的 StreamExecutionEnvironment 对象上调用 setRestartStrategy 方法来设置。 当然,对于 StreamExecutionEnvironment 也同样适用。

下例展示了如何给我们的作业设置固定延时重启策略。 如果发生故障,系统会重启作业 3 次,每两次连续的重启尝试之间等待 10 秒钟。

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
  3, // 尝试重启的次数
  Time.of(10, TimeUnit.SECONDS) // 延时
));

以下部分详细描述重启策略的配置项。

Fixed Delay Restart Strategy

固定延时重启策略按照给定的次数尝试重启作业。 如果尝试超过了给定的最大次数,作业将最终失败。 在连续的两次重启尝试之间,重启策略等待一段固定长度的时间。

通过在 flink-conf.yaml 中设置如下配置参数,默认启用此策略。

restart-strategy: fixed-delay

Flink操作——状态与容错_第10张图片
例如:

restart-strategy.fixed-delay.attempts: 3
restart-strategy.fixed-delay.delay: 10 s

固定延迟重启策略也可以在程序中设置:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
  3, // 尝试重启的次数
  Time.of(10, TimeUnit.SECONDS) // 延时
));

Failure Rate Restart Strategy

故障率重启策略在故障发生之后重启作业,但是当故障率(每个时间间隔发生故障的次数)超过设定的限制时,作业会最终失败。 在连续的两次重启尝试之间,重启策略等待一段固定长度的时间。

通过在 flink-conf.yaml 中设置如下配置参数,默认启用此策略。

restart-strategy: failure-rate

Flink操作——状态与容错_第11张图片
例如:

restart-strategy.failure-rate.max-failures-per-interval: 3
restart-strategy.failure-rate.failure-rate-interval: 5 min
restart-strategy.failure-rate.delay: 10 s

故障率重启策略也可以在程序中设置:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRestartStrategy(RestartStrategies.failureRateRestart(
  3, // 每个时间间隔的最大故障次数
  Time.of(5, TimeUnit.MINUTES), // 测量故障率的时间间隔
  Time.of(10, TimeUnit.SECONDS) // 延时
));

No Restart Strategy

作业直接失败,不尝试重启。

restart-strategy: none

不重启策略也可以在程序中设置:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRestartStrategy(RestartStrategies.noRestart());

Fallback Restart Strategy

使用群集定义的重启策略。 这对于启用了 checkpoint 的流处理程序很有帮助。 如果没有定义其他重启策略,默认选择固定延时重启策略。

Failover Strategies

Flink 支持多种不同的故障恢复策略,该策略需要通过 Flink 配置文件 flink-conf.yaml 中的 jobmanager.execution.failover-strategy 配置项进行配置。

Flink操作——状态与容错_第12张图片

Restart All Failover Strategy

在全图重启故障恢复策略下,Task 发生故障时会重启作业中的所有 Task 进行故障恢复。

Restart Pipelined Region Failover Strategy

该策略会将作业中的所有 Task 划分为数个 Region。当有 Task 发生故障时,它会尝试找出进行故障恢复需要重启的最小 Region 集合。 相比于全局重启故障恢复策略,这种策略在一些场景下的故障恢复需要重启的 Task 会更少。

此处 Region 指以 Pipelined 形式进行数据交换的 Task 集合。也就是说,Batch 形式的数据交换会构成 Region 的边界。

  • DataStream 和 流式 Table/SQL 作业的所有数据交换都是 Pipelined 形式的。
  • 批处理式 Table/SQL 作业的所有数据交换默认都是 Batch 形式的。
  • DataSet 作业中的数据交换形式会根据 ExecutionConfig 中配置的 ExecutionMode 决定。

需要重启的 Region 的判断逻辑如下:

  • 出错 Task 所在 Region 需要重启。
  • 如果要重启的 Region 需要消费的数据有部分无法访问(丢失或损坏),产出该部分数据的 Region 也需要重启。
  • 需要重启的 Region 的下游 Region 也需要重启。这是出于保障数据一致性的考虑,因为一些非确定性的计算或者分发会导致同一个 Result Partition 每次产生时包含的数据都不相同。

你可能感兴趣的:(flink,flink,大数据)