【问题标题】:How do I detect unexpected worker role failures and reprocess data in those cases?在这些情况下,我如何检测意外的辅助角色故障并重新处理数据?
【发布时间】:2011-05-20 07:46:56
【问题描述】:

我想创建一个托管在 Windows Azure 中的 Web 服务。客户端将上传文件进行处理,云端将处理这些文件,生成结果文件,客户端将下载它们。

我想我将使用 Web 角色来处理 HTTP 请求,并使用工作角色来进行实际处理,并使用 Azure 队列或 Azure 表存储之类的东西来跟踪请求。让我们假设它是 Azure 表存储 - 每个用户上传的文件都有一个“请求”记录。

一个主要的设计问题是处理单个文件可能需要一秒钟到十个小时不等。

所以我预计会出现以下情况:启动工作角色,进入 Azure 表存储,找到标记为“准备处理”的请求,将其标记为“正在处理”,开始实际处理。通常它会处理文件并将请求标记为“已处理”,但如果它意外死亡怎么办?

除非我处理它,否则请求将永远处于“正在处理”状态。

如何跟踪标记为“正在处理”但已放弃的请求? Windows Azure 中的哪种机制最方便?

【问题讨论】:

    标签: azure reliability azure-worker-roles


    【解决方案1】:

    您遇到的主要问题是队列今天无法将可见性超时设置为大于 2 小时。因此,您需要另一种机制来指示正在进行的工作。我会建议一个blob租约。对于您处理的每个文件,您要么租用 blob 本身,要么租用 0 字节标记 blob。您的工作人员扫描可用的 blob 并尝试租用它们。如果他们获得了租约,这意味着它没有被处理,他们会继续处理。如果租约失败,则必须有其他工人积极参与。

    工作人员完成文件处理后,只需将文件复制到 blob 存储中的另一个容器中(或根据需要将其删除),以便不再对其进行扫描。

    在队列消息可以更新之前,租约确实是您唯一的答案。

    edit:我应该澄清一下,租约在这里起作用的原因是必须每 30 秒左右主动维护一次租约,因此您有一个非常小的窗口,您可以在其中知道是否有人死亡或仍在努力。

    【讨论】:

    • 忘记了 2 小时的队列消息限制 - 我很少有队列消息存活那么久)。但是,服务总线消息的超时时间要长得多(几天前刚刚发布)。
    • 调用“续租”是否会从我的帐户中扣除?
    • 是的。您进行的每个 REST 调用都作为事务计费。租赁调用是一个 PUT,所以 1 个事务。如果您每 30 秒更新一次租约,则需要将近一年的时间(每次租约)才会花费您 1 美元(347 天)。
    【解决方案2】:

    我相信这个问题与技术无关。
    由于您的处理作业运行时间很长,我建议这些作业应该在执行期间报告它们的进度。通过这种方式,一个在相当长的时间内没有报告进度的工作成为清理的明确候选者,然后可以在另一个工作角色上重新启动。
    如何记录进度和进行工作调换取决于您自己。一种方法是使用数据库作为记录机制并创建一个 ping 作业进度表的代理工作进程。如果工作进程确定任何问题,它可以采取纠正措施。

    其他方法是将工人角色识别与长期运行的进程相关联。工作人员角色可以使用某种心跳来传达他们的健康状况。
    如果作业没有长时间运行,您可以在状态标志上标记作业的开始时间,并且可以使用超时机制来确定处理是否失败。

    【讨论】:

      【解决方案3】:

      您描述的问题最好使用 Azure 队列来处理,因为 Azure 表存储不会为您提供任何类型的管理机制。

      使用 Azure 队列,您可以在获取队列项目时设置超时(默认值:30 秒)。一旦你读取了一个队列项目(例如“处理文件 x 在 url y 的 blob 中等待你”),该队列项目在指定的时间段内变得不可见。这意味着其他工作角色实例不会尝试同时获取它。完成处理后,您只需删除队列项即可。

      现在:假设您快完成了,还没有删除队列项。突然之间,您的角色实例意外崩溃(或者硬件出现故障,或者您由于某种原因重新启动)。队列项处理代码现已停止。最终,当从最初读取队列项后经过的时间(相当于您设置的超时值)时,该队列项再次变为可见。您的工作角色实例之一将再次读取队列项目并可以对其进行处理。

      需要注意的几点:

      • 队列项目有一个出队计数。注意这一点。一旦您为特定队列项目达到一定数量的出队(我喜欢使用 3 次作为我的限制),您应该将此队列项目移动到“毒物队列”或表存储以进行离线评估 - 可能有问题消息或处理该消息的过程。
      • 确保您的处理是幂等的(例如,您可以多次处理同一消息而不会产生副作用)
      • 由于队列项目可能会变为不可见,然后稍后恢复可见,队列项目不必按 FIFO 顺序进行处理。

      编辑:根据 Ryan 的回答 - Azure 队列消息最多在 2 小时超时。服务总线队列消息的超时时间要长得多。此功能前几天刚刚通过 CTP。

      【讨论】:

      • 这不适合我的任务,因为我想不出一个合理的默认值。任何任务都可能需要一秒到几个小时的时间来处理,这很正常。
      • 那么,为什么不将所有队列项的超时设置为 12 小时呢?最坏的情况是失败的任务(由于崩溃)不会被重新处理 1/2 天。作为替代方案,您能否在将其放入队列之前预测一个球场超时值?如果是这样,您可以设置 2 个或更多队列(例如 fastq、mediumq、slowq)并生成线程以从每个队列中读取,使用的超时时间为 30 秒、1 小时、12 小时。
      • 我无法预测它也可能需要 14 小时 - 没有合理的上限。无论我为某些项目设置的超时时间都将被锁定相当长的一段时间。例如,用户上传一个需要 30 秒处理的文件,而角色处理它崩溃。用户必须等待整个超时时间才能重新处理它,即使它是系统中唯一的文件。
      • 我们谈论的是边缘案例。在被回收之前,我已经运行了一个月的角色实例(特别是对于操作系统更新)。在设计解决方案时请考虑到这一点。您每月可能只会遇到 2 或 3 件物品,其中有多少?只有您可以决定这是否值得额外的工程(例如将其变成分阶段的工作流程)。
      【解决方案4】:

      您角色的 OnStop() 可能是解决方案的一部分,但在某些情况下(硬件故障)它不会被调用。为了解决这种情况,让您的 OnStart() 将具有相同 RoleInstanceID 的所有内容标记为已放弃,因为如果仍有任何事情发生,则不会调用它。 (幸运的是,您可以观察到 Azure 重用了其角色实例 ID。)

      【讨论】:

      • 听起来不错,但重用是否被记录为任何地方唯一可能的行为?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多