在这些情况下,如何检测意外的工作者角色故障并重新处理数据?

时间:2011-05-20 07:46:57

标签: azure reliability azure-worker-roles

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

我想我会使用Web角色来处理实际处理的HTTP请求和辅助角色,以及用于跟踪请求的Azure Queue或Azure Table Storage。让我们假装它将是Azure表存储 - 每个用户上传文件的一个“请求”记录。

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

所以我期待以下情况:启动辅助角色,获取Azure表存储,找到标记为“准备处理”的请求,将其标记为“正在处理”,开始实际处理。通常它会处理文件并将请求标记为“已处理”,但如果它意外死亡会怎么样?

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

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

4 个答案:

答案 0 :(得分:4)

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

一旦工人完成了文件的处理,它只是将文件复制到blob存储中的另一个容器中(如果你愿意,可以将其删除),以便不再扫描它。

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

编辑:我应该澄清,租约在这里工作的原因是租约必须每30秒左右积极维护一次,所以你有一个非常小的窗口,你知道是否有人已经死亡或仍在继续工作。

答案 1 :(得分:2)

我认为这个问题不是针对特定技术的。
由于您的处理作业长期运行,我建议这些作业应在执行期间报告其进度。通过这种方式,在大量持续时间内未报告进度的作业成为清理的明确候选者,然后可以在另一个工作者角色上重新启动。
如何记录进度并进行工作交换取决于您。一种方法是使用数据库作为记录机制并创建一个ping作业进度表的代理工作进程。如果工人流程确定任何问题,可以采取纠正措施。

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

答案 2 :(得分:2)

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

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

现在:假设你已经差不多完成了,还没有删除队列项。突然之间,您的角色实例意外崩溃(或硬件失败,或者您因某种原因重新启动)。队列项处理代码现已停止。最终,当自最初读取队列项以来的时间过去(相当于您设置的超时值)时,该队列项再次可见。您的一个辅助角色实例将再次读取队列项并可以对其进行处理。

要记住的一些事项:

  • 队列项目有出队计数。注意这一点。一旦你为特定的队列项目击中了一定数量的队列(我喜欢使用3次作为我的限制),你应该将这个队列项目移动到“毒物队列”或表存储器以进行离线评估 - 可能有问题消息或处理该消息的过程。
  • 确保您的处理幂等(例如,您可以多次处理相同的消息,没有副作用)
  • 因为队列项可以不可见,然后返回到可见性,所以不必按FIFO顺序处理队列项。
编辑:根据Ryan的回答 - Azure队列消息最多在2小时超时。 Service Bus队列消息具有更大的超时。几天前,这个功能刚刚推出了CTP。

答案 3 :(得分:1)

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