我在 azure 中有一个简单的工作角色,对 SQL azure 数据库进行一些数据处理。工作人员基本上每 2 分钟将来自第 3 方数据源的数据添加到我的数据库中。当我有两个角色实例时,这显然会不必要地加倍。我希望有 2 个实例用于冗余和 99.95 的正常运行时间,但不希望它们同时处理,因为它们只会复制同一个作业。是否有我缺少的标准模式?我知道我可以在数据库中设置标志,但我希望有另一种更简单或更好的方法来管理它。谢谢
4 回答
正如 Mark 建议的那样,您可以使用 Azure 队列来发布消息。您可以让工作角色实例将后续消息发布到队列,作为它在处理当前消息时所做的最后一件事。这应该解决马克提出的关于需要信号量的问题。在您的队列消息中,您可以在可以处理消息时嵌入时间戳标记。创建新消息时,只需在当前时间上增加两分钟。
而且......如果它不明显:如果工作角色实例在完成处理之前崩溃并且无法重新发布新的队列消息,那很好。在这种情况下,当前队列消息将简单地重新出现在队列中,然后另一个实例可以自由处理它。
我不认为有一个超级简单的方法可以做到这一点。
您可以使用 Mark 提到的信号量,基本上记录处理的开始和停止。然后你可以运行任意数量的实例,每个实例都检查信号量记录,并且只有在信号量允许的情况下才会执行。
但是,这里需要注意的是,如果其中一个实例在处理过程中崩溃并且从未释放信号量,会发生什么?您可以实现一个“超时”值,如果在 X 时间内没有解锁,其他实例将尝试启动处理。
或者,您可以使用AzureWatch 之类的第三方监视服务来监视 Azure 中无响应的实例,如果“就绪”实例的数量低于 1,则启动一个新实例。这样可以节省一些钱,因为不必有 2 个实例始终启动并运行,但在实例失败和启动新实例之间存在轻微延迟。
建议的信号量将是要走的路,尽管我可能会在 blob 存储中使用简单的时间戳心跳。
另一个想法是,这有多大必要?如果您的负载可以维持几分钟,也许只是让角色循环?
大卫的解决方案的小收获。将消息重新发布到队列将作为当前执行的最后一件事发生,因此如果机器在此过程中崩溃,当前消息将过期并重新出现在队列中。这假设消息最初是被偷看的,并且需要一个出队操作才能从队列中删除。出队必须在将新消息插入队列之前发生。如果角色在这 2 次操作之间崩溃,那么系统中将没有任何令牌,并将停止。ESB 重复检查听起来像是一种可行的方法,但听起来也不是确定性的,因为总线只能检查当前存在于队列中的相同消息。但是,如果其中一条消息在前一条消息出队之后立即进入,
An alternative solution, if you can afford it, would be to never de-queue and just lease the message via Peek operations. You would have to ensure that the invisibility timeout never goes beyond the processing time in your worker role. As far as creating the token in the first place, the same worker role startup strategy described before combined with ASB dup check should work (since messages would never move from the queue).