作业重试和检查点最佳做法

个别作业任务甚至作业执行可能会因各种原因而失败。本页面以任务重启和作业检查点为核心介绍了处理这些失败的最佳做法。

计划作业任务重启

使作业具有幂等性,以便任务重启不会导致输出损坏或重复。也就是说,编写针对一组给定输入具有相同行为的可重复逻辑,无论其重复次数或执行时间如何。

将输出写入与输入数据不同的位置,让输入数据保持不变。这样,如果作业再次运行,则作业可以从头开始重复此过程,并获得相同的结果。

通过重复使用相同的唯一标识符或检查输出是否已存在,避免输出数据重复。重复数据表示集合级数据损坏。

使用检查点

尽可能为作业设置检查点,使得在任务失败后重新开始时,任务可以接续上次进度执行,而不是从头重新开始工作。这样做可以加快作业速度,并最大限度地减少不必要的费用。

定期写入部分结果并指示永久性存储位置(例如 Cloud Storage 或数据库)的进度。当任务开始时,在启动时查找部分结果。如果发现部分结果,则从中断的地方开始处理。

如果您的作业不适合设置检查点,请考虑将其拆分为较小的数据块并运行数目更多任务。

检查点示例 1:计算 Pi

如果您的作业执行递归算法(例如将 Pi 计算到多个小数位),并使用值设置为 1 的并行性:

  • 每 10 分钟或丢失工作容忍度允许的任何时间将进度写入 pi-progress.txt Cloud Storage 对象一次。
  • 当任务开始时,查询 pi-progress.txt 对象并将值加载为开始位置。使用该值作为函数的初始输入。
  • 将最终结果作为名为 pi-complete.txt 的对象写入 Cloud Storage,以避免通过并行执行或重复执行出现重复,或写入 pi-complete-DATE.txt 按完成日期区分。

检查点示例 2:处理来自 Cloud SQL 的 10000 条记录

如果您的作业在关系型数据库(如 Cloud SQL)中处理 10000 条记录:

  • 检索要通过 SQL 查询(如 SELECT * FROM example_table LIMIT 10000)处理的记录
  • 以一个批次 100 个写出更新后的记录,以免大量处理工作在中断时不会丢失。
  • 写入记录时,请注意已处理哪些记录。您可以向表添加已处理的布尔值列,只有在确认处理后,布尔值才会设置为 1。
  • 任务开始时,用于检索要处理的项的查询应添加条件“已处理 = 0”。
  • 除了从头开始的重试之外,此方法还支持将工作分解成多个较小的任务,例如通过修改查询,一次选择 100 条记录:LIMIT 100 OFFSET $CLOUD_RUN_TASK_INDEX*100 并运行 100 个任务来处理所有 10,000 条记录。CLOUD_RUN_TASK_INDEX 是运行 Cloud Run 作业的容器中存在的内置环境变量。

将所有这些部分结合使用,最终查询可能如下所示:SELECT * FROM example_table WHERE processed = 0 LIMIT 100 OFFSET $CLOUD_RUN_TASK_INDEX*100

后续步骤