容错机制 (检查点 Checkpoint)

目录

容错机制

检查点  Checkpoint

1.检查点的保存

 1.1 周期性的触发保存

1.2 保存的时间点

1.3 保存的具体流程

2.从检查点恢复状态 

(1)重启应用

(2)读取检查点,重置状态

(3)重放数据

(4)继续处理数据  

3.检查点算法

3.1 检查点分界线(Barrier)

3.2 分布式快照算法  

 4.保存点(Savepoint)

容错机制

检查点  Checkpoint

        在发生故障后,最简单的恢复方法是重启机器或重启应用。然而,对于流处理应用,由于任务是有状态的,重启后需要继续之前的处理计算。为了实现这一点,需要对内存中的状态进行持久化存盘。

        持久化存盘的过程类似于编写文档或玩RPG游戏时的存档操作。通过将某个时间点的所有状态保存下来,形成一个“检查点”(checkpoint)。检查点是Flink容错机制的核心,用于在故障恢复后从检查点中恢复之前的状态,从而继续数据处理。

                                       容错机制 (检查点 Checkpoint)_第1张图片

        检查点用于确保故障恢复后处理结果的一致性。因此,检查点有时也被称为“一致性检查点”。通过使用检查点,可以确保即使在发生故障时,流处理应用也能从一致的状态中恢复,并继续正确地处理数据。这对于确保数据的完整性和可靠性至关重要。

        在Flink中,可以通过配置检查点的时间间隔、存储位置以及数据同步机制等参数来优化故障恢复的效果。合理地配置这些参数可以帮助提高系统稳定性并降低故障恢复的代价。此外,为了进一步提高系统的可靠性,还可以考虑使用其他容错机制,如备份和恢复策略等。

1.检查点的保存

        在理想情况下,检查点的保存应该是“随时”进行的,即每处理完一个数据就保存当前的状态。这种即时保存的方式可以确保在处理数据时发生故障时,系统能够迅速恢复到上一个完整状态,然后重新处理那条数据。

        然而,这种即时保存的方式可能会对系统性能产生一定的影响,因为每次保存检查点都需要进行磁盘I/O操作,并且检查点的存储也需要占用一定的空间。因此,在实际应用中,通常会根据系统的负载和可用资源来平衡检查点的频率。

        一种常见的策略是设置一个固定的时间间隔来保存检查点。在这种策略下,系统会在每个时间间隔结束时保存当前状态的检查点。如果在这个时间间隔内发生了故障,系统可以从最后一个检查点中恢复状态,然后重新处理那些在检查点之后到达的数据。

        另外,为了进一步优化性能和降低存储成本,还可以采用增量式检查点的策略。在这种策略下,系统只会保存那些在上次检查点之后发生变化的状态数据。这种方式可以减少检查点的大小和存储需求,同时也可以减少恢复时间,因为只需要恢复最新的状态数据而不是整个系统的状态。

 1.1 周期性的触发保存

        为了平衡数据处理的性能和故障恢复的需求,通常采用周期性触发检查点的方式。在Flink中,检查点的保存是周期性触发的,间隔时间可以进行设置。这样可以确保系统在正常处理数据的同时,不会因为频繁的存档操作而影响性能。

        检查点作为应用状态的一份“存档”,实际上是所有任务状态在同一时间点的一个“快照”(snapshot)。当每隔一段时间检查点保存操作被触发时,系统会将每个任务当前的状态复制一份,并按照一定的逻辑结构放在一起进行持久化保存。这种方式可以确保在故障发生时,系统能够从最后一个检查点中恢复状态,并继续正确地处理数据。

        通过合理配置检查点的触发间隔,可以平衡系统性能和故障恢复的需求。较短的触发间隔可以减少故障恢复的延迟,但会增加存储和IO的开销。较长的触发间隔可以降低存储和IO的开销,但会增加故障恢复的延迟。因此,需要根据实际的应用场景和需求进行权衡,选择合适的检查点触发间隔。

1.2 保存的时间点

        在Flink流处理应用中,我们采用了一种特定的状态保存策略:当所有任务都恰好处理完一个相同的输入数据时,将它们的状态保存下来。这种策略有几个重要的优点。

        首先,它避免了除状态之外其他额外信息的存储,从而提高了检查点保存的效率。由于我们只在所有任务处理完同一个输入数据时进行状态保存,因此不需要存储与处理过程无关的其他信息,这有助于减少存储空间的占用,并提高检查点的生成速度。

        其次,这种策略构建了一个类似于“事务”的处理模型。在每个检查点,要么所有任务都完整地处理完了一个数据,并且状态得到了保存;要么就是没有处理完,状态也没有保存。这种“全有或全无”的特性确保了系统状态的一致性。如果出现故障,我们可以恢复到之前保存的状态,而故障时正在处理的所有数据都需要重新处理。

        为了实现故障恢复,源(Source)任务需要能够将偏移量作为算子状态保存下来,并且在需要时能够向数据源重新提交偏移量、请求重放数据。这就要求外部数据源能够支持重置偏移量的操作。Kafka是一个满足这些要求的典型例子,它允许我们保存并重置消费者的偏移量,从而实现数据的重新读取和处理。

        综上所述,通过合理地选择状态保存策略,并利用外部数据源的特性,我们可以在Flink流处理应用中实现高效且可靠的故障恢复机制。这不仅可以保证数据处理的正确性,还可以提高系统的可用性和稳定性。

1.3 保存的具体流程

        在Flink流处理应用中,源(Source)任务负责从外部数据源读取数据,并记录当前的偏移量。这个偏移量被作为算子状态(Operator State)保存下来,以便在故障发生时能够重新提交偏移量并请求重放数据。

        一旦源任务读取了数据,它将这些数据发送给下游的Map任务。Map任务将每个单词转换成(word, count)的二元组,其中count的初始值为1。这种转换是无状态的算子任务,意味着它不会存储任何状态信息。

        接下来,使用word作为键(key)进行分区,调用sum()方法对count值进行求和统计。sum()算子将当前求和的结果作为按键分区状态(Keyed State)保存下来。这种状态是与应用中特定的键值关联的,因此不同的键值会有各自的状态。

        最终,通过这种处理流程,我们可以得到当前单词的频次统计(word, count)。这个结果可以用于各种分析和报告,帮助我们了解数据的分布和模式。

容错机制 (检查点 Checkpoint)_第2张图片

2.从检查点恢复状态 

  在运行流处理程序时,Flink 会周期性地保存检查点。当发生故障时,就需要找到最近一
次成功保存的检查点来恢复状态  
容错机制 (检查点 Checkpoint)_第3张图片
这里 Source 任务已经处理完毕,所以偏移量为 5 map 任务也处理完成了。而 sum 任务
在处理中发生了故障,此时状态并未保存。
接下来就需要从检查点来恢复状态了。具体的步骤为:

 

1)重启应用
遇到故障之后,第一步当然就是重启。我们将应用重新启动后,所有任务的状态会清空
2)读取检查点,重置状态
找到最近一次保存的检查点,从中读出每个算子任务状态的快照,分别填充到对应的状态
中。这样, Flink 内部所有任务的状态,就恢复到了保存检查点的那一时刻,也就是刚好处理
完第三个数据的时候

 容错机制 (检查点 Checkpoint)_第4张图片

3)重放数据
从检查点恢复状态后还有一个问题:如果直接继续处理数据,那么保存检查点之后、到发
生故障这段时间内的数据,也就是第 4 5 个数据(“ flink ”“ hello ”)就相当于丢掉了;这会造
成计算结果的错误。
为了不丢数据,我们应该从保存检查点后开始重新读取数据,这可以通过 Source 任务向
外部数据源重新提交偏移量( offset )来实现,

         容错机制 (检查点 Checkpoint)_第5张图片

4)继续处理数据  

 

接下来,我们就可以正常处理数据了。首先是重放第 4 5 个数据,然后继续读取后面的
数据
容错机制 (检查点 Checkpoint)_第6张图片
        当处理到第 5 个数据时,就已经追上了发生故障时的系统状态。之后继续处理,就好像没
有发生过故障一样;我们既没有丢掉数据也没有重复计算数据,这就保证了计算结果的正确性。
在分布式系统中,这叫作实现了“精确一次”( exactly-once )的状态一致性保证。

 

3.检查点算法

3.1 检查点分界线(Barrier

        在不暂停流处理的前提下,让每个任务“认出”触发检查点保存的那个数据,可以通过引入特殊的数据结构来实现。这种特殊的数据结构被称为检查点分界线(Checkpoint Barrier)。

        检查点分界线是一种特殊的数据形式,类似于水位线(watermark),用于标识检查点保存的时间点。在数据流中,Source 任务会接收到保存检查点的指令,并在当前数据流中插入这个结构。之后的所有任务在遇到这个标识时,就会开始对状态进行持久化快照保存。

        由于数据流是保持顺序依次处理的,遇到这个标识就代表之前的数据都处理完了,可以保存一个检查点。而在标识之后的数据引起的状态改变,就不会体现在这个检查点中,而需要保存到下一个检查点。

        检查点分界线与水位线类似,也是一条特殊的数据,由 Source 算子注入到常规的数据流中。它的位置是限定好的,不能超过其他数据,也不能被后面的数据超过。分界线中带有一个检查点 ID,这是当前要保存的检查点的唯一标识。

        通过这种方式,检查点分界线将一条流逻辑上分成了两部分:分界线之前到来的数据导致的状态更改,都会被包含在当前分界线所表示的检查点中;而基于分界线之后的数据导致的状态更改,则会被包含在之后的检查点中。

        通过合理地使用检查点分界线,我们可以实现在不暂停流处理的情况下,让每个任务识别并响应触发检查点保存的数据。这种设计有助于提高系统的可用性和稳定性,确保数据处理的正确性和一致性。

容错机制 (检查点 Checkpoint)_第7张图片

3.2 分布式快照算法  

        在处理多个分区的分界线传递时,Flink 采用了异步分界线快照(asynchronous barrier
snapshotting)算法,这是 Chandy-Lamport 算法的一种变体。

        该算法的核心在于两个原则。首先,当上游任务向多个并行下游任务发送分界线时,需要确保分界线被广播到所有下游任务。这样可以确保所有并行分区都能正确地识别到检查点保存的时间点。

        其次,当多个上游任务向同一个下游任务传递分界线时,下游任务需要进行“分界线对齐”(barrier alignment)操作。这意味着下游任务需要等待所有并行分区的分界线都到达,然后才开始进行状态保存。这样可以确保所有分区都能在相同的时间点进行状态保存,从而实现一致的检查点。

        通过这种异步分界线快照算法,Flink 可以在不暂停流处理的情况下,有效地处理多个分区之间的分界线传递,并确保每个任务都能正确地识别触发检查点保存的数据。这有助于提高系统的可用性和稳定性,确保数据处理的正确性和一致性。

 4.保存点(Savepoint

        除了检查点(checkpoint)外,Flink 还提供了另一个非常独特的功能,那就是保存点(savepoint)。从名称上就可以看出,保存点也是一种存盘的备份方式,其原理和算法与检查点基本相同,只是多了一些额外的元数据。

        实际上,保存点就是通过检查点的机制来创建流式作业状态的一致性镜像(consistent image)的。这种一致性镜像能够确保在从保存点恢复应用程序时,所有任务的状态都能够准确地回溯到之前的状态。

        在保存点中,状态快照是以算子 ID 和状态名称组织起来的,形成一种键值对的形式。当从保存点启动应用程序时,Flink 会将保存点的状态数据重新分配给相应的算子任务。这样,任务就可以从一致的状态镜像开始执行,确保数据的正确性和一致性。

        与检查点相比,保存点更加灵活。由于保存点包含了一些额外的元数据,用户可以自由地选择将应用程序恢复到某个特定的状态,而不是只能恢复到最后一次检查点的状态。此外,由于保存点可以独立于运行中的作业进行创建,因此用户可以在不影响作业运行的情况下进行状态的备份和恢复操作。

保存点是一个手动触发的存盘备份功能,与Flink的自动检查点机制不同。用户可以明确地手动触发保存点操作,以创建应用程序的状态镜像。相比之下,检查点是由Flink自动管理的,主要用于故障恢复。

保存点的用途非常灵活,可以作为强大的运维工具使用。以下是保存点的具体用途和场景:

  1. 版本管理和归档存储:用户可以在需要时创建一个保存点,并将其设置为特定版本,对应用程序的状态进行归档存储。
  2. 更新Flink版本:当Flink版本升级时,由于Flink的底层架构已经非常稳定,程序本身通常是兼容的。用户可以通过创建一个保存点来停止应用程序,进行Flink版本升级,然后从保存点重启应用程序,而无需重新执行所有计算。
  3. 更新应用程序:除了更新Flink版本,用户还可以直接更新应用程序。前提是程序的状态拓扑结构和数据类型保持不变,以便能够从之前的保存点正常加载。这对于修复应用程序中的逻辑错误或进行不同业务逻辑的测试非常有用。
  4. 调整并行度:如果应用程序在运行过程中发现资源不足或存在大量剩余资源,用户可以通过从保存点重启应用程序来调整并行度。
  5. 暂停应用程序:用户可以使用保存点来灵活地暂停和重启应用程序,以优化集群资源的配置。

为了确保保存点的兼容性和状态的正确加载,用户应该为每个算子手动指定ID。在程序代码中,可以使用SingleOutputStreamOperatoruid()方法来指定算子ID。


其中,:jobId是要进行镜像保存的作业ID,:targetDirectory是可选的目标路径,表示保存点的存储路径。用户也可以在程序代码中设置默认的保存点路径。

你可能感兴趣的:(flink知识点,数据库,大数据,flink)