2

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

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

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

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

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

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

4

4 回答 4

4

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

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

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

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

于 2011-05-20T13:37:34.590 回答
2

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

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

于 2011-05-20T08:36:28.810 回答
2

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

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

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

要记住几件事:

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

编辑:根据 Ryan 的回答 - Azure 队列消息在 2 小时超时后最大输出。服务总线队列消息的超时时间要长得多。这个功能前几天刚上CTP。

于 2011-05-20T11:20:16.043 回答
1

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

于 2011-05-20T07:57:22.557 回答