首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >服务的多个实例--如何保证只处理一次对象?

服务的多个实例--如何保证只处理一次对象?
EN

Stack Overflow用户
提问于 2013-05-22 23:35:53
回答 2查看 1.3K关注 0票数 0

我有以下设置:部署了N个Azure Worker角色实例。我们的桌面应用程序向Azure上传一条消息,然后上传一组与消息相关的图像。信息知道它需要什么图像。

这两个活动(消息上传和图像上传)是独立的--图像可以在用户生成消息之前上传(称为缓存--但更复杂),或者在消息上传到Azure之后的几秒钟/分钟。

我将消息存储在Azure MSSQL数据库中,图像存储在blobs中,对它们的URL存储在数据库中。还有MessageToImage表,它为消息存储指向图像的链接。下面是一个简化的DB结构(请原谅我的C#):

代码语言:javascript
运行
复制
class Message
{
    public int Id;
    public string Text;
}

class Image
{
    public int Id;
    public string Name;
    public string BlobUrl;   // Null if image was not received by the service yet
}

class MessageToImage
{
    public int MessageId;
    public List<int> ImageIds;
}

当我们准备好所有图片的信息(即所有的图像都上传完毕)时,我们需要做一些其他的事情(比如,在Facebook上发布)。这里的问题是:如何保证消息只处理一次?在最坏的情况下,我将让N个实例同时接收该消息的N个图像--哪个实例将“选择”将消息发送到进一步处理?我怎么能保证只发生一次呢?

到目前为止,我提出了以下想法:

  1. 确保“更新BlobUrl for Image”数据库逻辑是原子的,并将返回消息的“缺失”图像的数量。这样,我将只在一个实例上触发进一步的处理--作为数据库更新的结果,该实例接收"0“。但是:我如何在MSSQL级别上做到这一点呢?更复杂的是--我如何使用实体框架()?
  2. 有一个专门的工作人员角色,作业将选择具有所有图像的消息,并将其发送给处理。但这不是很好的..。看上去有点丑。

还有其他的想法/建议吗?

谢谢!

UPDATE1 @Richard和@Rob建议使用服务总线队列。我确实调查过了。我仍然没有答案的部分是,决定何时将消息发送到队列以进行处理的WORKER角色中的代码应该是什么样的呢?只有当数据库/blobs中存在所有图像时(即上传到Azure云中),消息才会发送到队列中。在这里,我仍然想指出我的角落案例-我有10个图像同时处理10个工人的角色。对于所有实例,处理同时结束。每个角色用上传的图像URL更新数据库。然后,我应该以某种方式触发最终消息处理--这意味着其中一个实例应该获得优先级。我不清楚我该怎么做。

希望这能让我的问题更清晰些。

EN

回答 2

Stack Overflow用户

发布于 2013-05-22 23:47:12

创建Azure服务总线队列,并让客户端应用程序向队列发送消息。然后,您的工作角色可以从队列中提取消息并处理这些消息。

服务总线队列最重要的一点是,它们保证消息只能从队列中取出一次,因此消息被标记为“被获取”。如果未将事务标记为在(可配置的)时间段内完成,则消息将返回到队列,以便由下一个工作人员请求提取。

这意味着,如果您的worker角色在处理过程中失败,消息最终将重新出现在队列中,由下一个工作人员来获取它,并(希望)完成所需的工作。

有关更多信息,请阅读此链接:

如何使用服务总线队列

票数 2
EN

Stack Overflow用户

发布于 2013-05-23 00:13:47

您应该考虑使用服务总线消息传递会话

在您的客户端上,为上传会话生成唯一的批处理上传Id (使用GUID而不是int)。上传的每个图像都应该附有这个Id (上传批次中所有图像的Id相同)。当您的服务接收到图像时,它会将一个“上传图像”BrokeredMessage发布到服务总线队列或主题中,并将SessionId设置为客户端提供的唯一Id。

当您的消息从客户端发送到服务时,使用它发送批处理上传Id。当从服务发布中接收到这一点时,另一个队列/主题上会出现一个"Process“BrokeredMessage。此BrokeredMessage的接收方将读取批处理上传Id,然后开始侦听与相关sessionId相关的所有“上传图像”消息。它可以继续这样做,直到它已经接收到它们全部(可能需要发送一个总上传计数,以便它知道什么时候停止)。一旦收到它们,它就可以生成一个新的BrokeredMessage来触发图像上传的处理(例如向facebook发布帖子)。

您希望为最终处理阶段(post到facebook)生成一个独立的BrokeredMessage,以便如果您的角色在处理消息时失败,消息将在稍后重新传递。

要记住的是,消息“至少收到一次”,如果您的角色在处理消息过程中中途失败,则消息将在超时后返回到队列/主题。因此,您的处理逻辑需要能够处理它正在处理之前已经部分处理过的消息的情况。

以下是不同的行为者为实现你想要的而应该做的事情:

客户

  • 生成一个唯一的sessionId (或者从您的web服务请求一个)
  • 将每个图像上载到web角色,并使用相关的sessionId
  • 将作业“消息”上载到web角色,并在上传批次中使用相关的sessionId和imageCount (可以在图像上传之前/期间/之后完成)

网络角色

  • 当接收到上传的图像时,将图像存储在blob存储区中,将包含图像URL的UploadsQueue发送到队列(“BrokeredMessage”),其中包含SessionId集和正文
  • 当谴责上传的作业“消息”时,向队列("JobsQueue")发送包含sessionID和imageCount的"UploadBatch“BrokeredMessage

工人角色

  • 当从"UploadBatch“接收到"JobsQueue”消息时,从"UploadsQueue“上的消息主体AcceptMessageSession( sessionId )获取sessionId和imageCount,并在该会话中继续轮询消息,直到收到所有上载消息为止。一次(receivedCount == imageCount)向"JobsQueue“发布一条"SendToFacebook”消息,并在正文中列出要处理的图像等。
  • 当收到来自"SendToFacebook“的"JobsQueue”消息时,从消息体获取要处理的图像列表,并将它们发送到facebook等。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16703298

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档