Azure Automation:使用检查点实现可靠的容错Runbook执行

原文地址:https://azure.microsoft.com/blog/2014/09/03/azure-automation-reliable-fault-tolerant-runbook-execution-using-checkpoints/

作为Azure Automation Runbook的编写者,我们都希望创建的Runbook在遇到意外问题(如错误、异常、网络问题和崩溃)时能够可靠地执行。Azure Automation可以帮助您实现这一目标。Azure Automation构建于Windows PowerShell工作流基础之上,支持检查点技术,能够保持工作流状态,这样一旦发生中断,随后将可以在中断点或其附近恢复。因此,检查点是一项十分强大的功能,大家势必希望在Automation Runbook中加以利用。有效利用检查点可使您创建的Runbook自动执行长时间运行的流程,顺利访问不同的网络系统,保证不重复那些不应该重复(非幂等任务)或重复起来较为昂贵的操作,并可有计划地中断以纳入手动步骤。

在本文中,我们将探讨在Automation Runbook中使用检查点的原因、场景和方式。大家可以重温一些有关PowerShell 工作流检查点的现有信息,从而帮助理解本文。

什么是检查点?

检查点是Runbook作业的当前状态快照,包括当前的变量值、所有输出及其他可序列化状态信息。每个检查点均将保存到存储中。如果有意或无意导致Runbook挂起,接着重新恢复,工作流引擎将使用最新检查点数据还原和恢复Runbook。

Azure Automation检查点

在Azure Automation中,当您保持一个Runbook作业时,将会创建检查点并将其存储到Azure Automation数据库中。数据库中仅会存储每项作业的最新检查点。各检查点会替换前一个检查点。如果Runbook先挂起而后恢复,最后存储的检查点将用于存储和恢复Runbook。

与PowerShell 工作流(将检查点存储到托管工作流会话的计算机硬盘中)不同,Azure Automation将检查点存储到Azure Automation数据库中。因此,如果运行Runbook的工作进程发生崩溃,那么待该进程重新启动后或其他工作进程可以继续完成作业,使用数据库中的最新检查点恢复作业。

为什么使用检查点?

以下是在Runbook中使用检查点的几点原因:

  • 确保某些操作不重复
    • 检查点对于在Runbook发生崩溃(挂起)后又恢复时保证不重复执行那些不应该重复的操作(非幂等任务)。例如,创建虚拟机后立即核查Runbook检查点,如果Runbook作业挂起后又恢复,则不能创建重复的虚拟机。
  • 保护长时间运行的任务
    • 在现实世界中,错误时常发生。包含多个步骤、长时间运行的任务容易因网络问题、计算机重启或崩溃、超时、电源中断等造成中断。为避免重新执行昂贵任务,需要检查Runbook的检查点,确保任何Runbook重新启动后都不会重新执行任务。
  • 确保长时间运行的Runbook完成运行
    • Azure Automation具有“公平共享”功能,该功能会卸载运行时间达 30 分钟的所有Runbook,以便其他Runbook继续运行。最终,将会重新加载被卸载的Runbook,完成加载后,将从最后一个Runbook检查点恢复执行。因此,为保证Runbook最终完成,您必须不时添加检查点且运行间隔不得超过 30 分钟。(此论坛文章列举了有关这个问题的一个示例。)
  • 允许计划内中断或手动中断
    • 在某些场景下,您可能希望挂起正在运行的Runbook。例如,挂起Runbook作业等到批准后再继续运行,或者挂起Runbook作业等待修复意外或计划内系统问题。

 

如何向Runbook添加检查点?

Checkpoint-Workflow 活动

Checkpoint-Workflow活动(别名:Persist)是一项标准的PowerShell工作流活动,在Runbook中可用于在某个特定的点创建检查点。在Runbook中发生Checkpoint-Workflow活动的特定点创建检查点。


Download-Updates
Reboot-VM
Checkpoint-Workflow
Email-Team
Checkpoint-Workflow

-PSPersist活动通用参数

每当调用此活动时,都可以纳入–PSPersist工作流活动通用参数。这将会在活动完成后,立即强制创建检查点。

 …
Download-Updates
Reboot-VM –PSPersist $True
Email-Team –PSPersist $True
…
 

$PSPersistPreference工作流首选项变量

在Runbook中,您可以包含$PSPersistPreference = $True语句。这将会导致在完成preference语句执行的活动后删除检查点。如果将此preference语句设在Runbook开头,那么将会在Runbook中的每项活动后均创建一个检查点。您可以通过包含 $PSPersistPreference = $False语句(这是Runbook默认设置)关闭自动检查点,而后运行活动时将不会使用自动检查点。

请注意,出于性能和策略原因,每项活动后均执行Persist可能并非最佳方法。每个检查点均需要处理,以便实现工作流状态序列化并将其存储到数据库中。另外,在某些场景中(后面的例子),如果Runbook挂起,您可能会希望重复一些活动。出于上述原因,不推荐运用此方法。

 …
Download-Updates
$PSPersistPreference = $True
Update-VM
Email-Team
$PSPersistPreference = $False
…
 

Suspend-Workflow 活动

当在Runbook中使用Suspend-Workflow活动时,最直接的结果是创建Runbook检查点,然后将Runbook挂起。您将需要在Runbook中使用此活动,例如,如果需要Runbook执行某项作业,然后等待审批再继续运行。“获得”批准的方式是恢复Runbook作业。

 …
Download-Updates
# Get permission to apply updates
Suspend-Workflow
# Continue if resumed
Reboot-VM –PSPersist $True
Email-Team –PSPersist $True
…
 

添加检查点的位置

通常情况下,最好明确标记Persist工作流的位置。并不是要设置$PSPersistPreference变量在每项活动后执行综合检查,通常最好从综合战略角度出发,在需要Persist操作的工作流位置使用Checkpoint-Workflow活动、Suspend-Workflow 活动或 –PSPersist参数。某些位置的确需要Persist工作流,但有些位置确实不需要Persist工作流(示例如下)。另外,请记住,Persist工作流需要在系统层实现,这会在一定程度上影响工作流性能。

最佳实践: 在下列情况下,您可能需要在工作流中添加检查点:

  • 在不希望重复(非幂等)的任何活动后面。
  • 由于成本限制不希望重复的长时间运行或费用昂贵的活动后面。
  • 在运行时间超过 30 分钟的Runbook中。30 分钟后,将启用“公平共享”功能,暂时卸载Runbook,以便其他Runbook运行。最终,系统将重新加载该Runbook,并从最后一个检查点恢复执行。如果未添加任何检查点,那么Runbook将从头恢复,当然还会再次执行公平共享,这种情况将会重复出现,Runbook将永远无法完成。
  • 在超出正常问题概率(可能导致故障和工作流挂起)的任何活动前。您希望在工作流恢复时重复该活动,从而确保活动工作顺利完成。例如,访问可能受到网络问题影响的远程系统的活动。

最佳实践: 不能在下列情况下添加检查点:

  • 在工作流挂起后又恢复时希望重复的工作后
  • 重复执行的成本比创建检查点费用低的工作后
  • 在InlineScript块中(不允许)

演示场景:更新虚拟机

  1. 从 Windows 更新下载最新修补程序
  2. 重新启动虚拟机以应用修补程序
    • 检查点
  3. 向团队发送电子邮件报告已应用更新
    • 检查点

在此场景下,可以重复步骤 1(因为幂等),但不能重复步骤 2 和步骤 3。因此,需要在步骤 2 和步骤 3 后添加检查点。“每项活动后自动Persist”设置仍然有效;但是,在步骤 1 后添加检查点未必会向系统添加工作。

演示场景:通知客户

  1. 从数据库获取客户列表
  2. 向客户发送电子邮件通知新策略
    • 检查点
  3. 向管理层发送电子邮件,表明已向客户发送电子邮件
    • 检查点

有时候,您不希望重复活动组,但只有在该组的所有活动均成功完成的情况下才适用。在此场景下,步骤 1 和步骤 2 应始终同时运行,确保在发出电子邮件时检索到的客户列表保持最新状态。因此,如果Runbook工作进程在步骤 2(发送客户电子邮件)前发生崩溃,待到Runbook作业恢复后,我们希望它再次从步骤 1(检索客户列表)开始运行。但是,如果在步骤 3 前发生崩溃或挂起,那么我们希望确保不重复执行步骤 2(不希望再次向客户发送电子邮件)。

最佳实践: 值得注意的是,不能在工作流InlineScript块或函数中添加检查点。这是因为InlineScript块或函数以PowerShell 脚本(而非PowerShell工作流脚本)的形式运行。因此,为了充分利用工作流Persist的优势,最好将Runbook代码拆分为多项模块化活动,这样就能在活动之间添加检查点,或者如果需要InlineScript,那么可以使用多个InlineScript块,以便在InlineScript块之间创建检查点。

挂起和恢复Runbook

创建检查点和挂起/恢复Runbook同时使用。向Runbook添加检查点,这样当Runbook挂起时,Runbook即可从最后一个检查点恢复。

Azure Automation 的Runbook作业可通过多种方式挂起:

  • 用户使用 Azure Automation 门户界面挂起
    • 您可以选择在 Azure Automation 门户界面中挂起正在运行的Runbook作业。
    • 该作业将在下一个检查点挂起。如果未在Runbook中创建任何检查点,那么Runbook将继续运行直至结束,并且始终显示“正在挂起”状态。
  • 用户在Runbook中使用Suspend-Workflow 挂起
    • 在Runbook中包括Suspend-Workflow活动。
    • 将为作业创建检查点,然后在调用Suspend-Workflow的位置挂起。
  • 用户使用 Suspend-AzureAutomationJobcmdlet挂起
    • 在PowerShell脚本或工作流中,您可以使用Suspend-AzureAutomationJobcmdlet挂起正在运行的Azure Automation Runbook作业。
    • 该作业将在下一个检查点挂起。如果未在Runbook中创建任何检查点,那么Runbook将继续运行直至结束,并且始终显示“正在挂起”状态。
  • Azure Automation工作流引擎在Runbook运行时间超过 30 分钟时挂起
    • 当正在运行的作业运行时间超过 30 分钟时,将会触发“公平共享”功能,系统将暂时卸载Runbook。作业状态将被设置为“正在运行,等待资源”。最终,将重新加载Runbook,然后从最后一个检查点开始执行。
  • Azure Automation 工作流引擎在Runbook发生异常后意外挂起
    • 当正在运行的作业发生异常时,Runbook工作进程会将其卸载,Runbook状态将设置为“已挂起”。
  • 因Runbook工作进程发生崩溃而意外挂起
    • 如果Runbook工作进程发生崩溃,该工作进程上运行的作业将立即终止。这些作业在数据库中的状态仍继续为“正在运行”。当上述或替换工作进程恢复在线状态时,将恢复这些作业并从最后一个检查点继续执行。

Azure Automation的Runbook作业可通过多种方式恢复。在任何情况下,作业都将从最后一个检查点进行恢复;若未创建检查点,则从头开始恢复。

  • 在 Azure Automation 门户界面中手动挂起
    • 您可以选择使用 Azure Automation 门户界面恢复挂起的作业。
  • 使用 Resume-AzureAutomationJobcmdlet挂起
  • 在Runbook工作进程崩溃后自动挂起
    • 当工作进程恢复在线状态或者指定另一个工作进程接替其操作时,该工作进程将会在为其分配的数据库中查找作业。对于状态显示为“正在运行”但尚未在工作进程上运行的任何作业,工作进程将从最后一个检查点自动恢复(这与上方挂起列表中的第 5 项的情况相同)。

值得注意的是,恢复Runbook时,可在不同于之前挂起的工作进程上恢复Runbook。因此,需要重新创建Runbook期望使用的任何本地状态。例如,这意味着,如果Runbook需要在检查点后的任意一点与Azure相连,需要在各检查点后再次调用本地文件中设置状态的命令(如Connect-Azure、Add-AzureAccount、Select-AzureSubscription或 Set-AzureSubscription)。

小结

大家可以看到,如果要充分利用PowerShell工作流的这项关键功能并使Runbook能够应对中断情况,应在Runbook中添加检查点。添加检查点很简单。创作Runbook期间预先计划,即可保护较为昂贵的长时间运行任务应对意外中断,真正创建强大可靠的Runbook。