3

这是一个理论问题:

当我使用消息队列构建应用程序时,我将需要多个队列支持不同的数据类型以用于不同的目的。假设我有 20 个队列(例如,一个用于创建新用户,一个用于处理新订单,一个用于编辑用户设置等)。

我将使用“最少”1 个 Web 角色和 1 个辅助角色将其部署到 Windows Azure。

如何以正确的方式从所有这 20 个队列中读取数据?这就是我的想法,但我对此几乎没有实际经验:

创建一个在工作角色“主”类中产生 20 个线程的类。让这些线程中的每一个执行一个方法来轮询不同的队列,并让所有这些线程在每次轮询之间休眠(当然还有增加休眠时间的退避机制)。

这导致有 20 个线程(或 21 个?)和 20 个正在被主动轮询的队列,从而导致大量浪费的消息(每次轮询一个空队列时,它都被计费为一条消息)。

你怎么解决这个问题?

4

3 回答 3

5

我阅读了其他答案(非常好的答案)并想对此发表自己的看法。

正如@Lucifure 所描述的,坚持使用 Windows Azure 队列:我真的不认为需要多个队列,除了两种情况:

  • 你想要不同的优先级。您最不想要的就是一条高优先级消息被困在数百条低优先级消息后面。为这些创建一个高优先级队列。
  • 消息读取+删除的数量将超过每秒 500 个事务的目标。在这种情况下,创建多个队列,将事务量分散到存储分区(存储帐户每秒将处理超过 5K 的事务)。

如果您坚持使用单个队列(基于存储,而不是服务总线),您可以一次读取消息块(最多 32 个)。您可以轻松制定一种格式来帮助您区分消息类型(可能带有简单的前缀)。然后,只需将消息交给适当的线程进行处理。服务总线队列没有多消息读取,尽管它们允许预取(这会导致缓冲消息被下载到缓存中)。

一个队列优于多个队列的优势:您消除(或大大减少)“许多队列没有消息,导致空读取”的问题。

如果您需要更高的吞吐量,您可以随时增加执行队列读取和分派的线程数。

请记住,每个删除都是原子的;没有批处理。就队列轮询而言:您考虑退避是正确的。成功阅读消息(或消息块)后,您无需后退。当你在尝试阅读后没有得到任何东西时,请退后。

与服务总线队列相比,一个很好的优势是:Windows Azure 队列为您提供了一个近似的消息计数(这在考虑向多个实例横向扩展时非常有用)。服务总线队列不提供此功能。

于 2012-06-10T04:36:14.227 回答
2

另一种策略是使用单个或更少的队列,以便队列可以支持多于一种类型的消息。如果您的系统架构可以支持,这种方法更易于管理且成本更低。

在现实世界中,我已经成功地使用了多个队列(出于可扩展性目的),每个队列在由计时器事件触发的单独线程上读取。根据队列上的负载和应用程序的需要,定时器事件被更改为以动态变化的时间间隔为队列提供服务。

于 2012-06-09T22:48:07.430 回答
1

如果存储队列的回退机制对您来说还不够,我建议您考虑使用服务总线队列。使用服务总线队列,您不必进行如此激进的轮询。

您仍然需要实现一个循环来轮询队列,但接收超时使其比使用存储队列时的持续轮询机制更轻。

在下面的示例中,我尝试从队列中接收消息。如果未找到消息,它将保持连接打开 30 秒,以查看是否有新消息进入。如果 30 秒后没有消息到达,则 Receive 方法将返回 null(我将有一个循环尝试再次调用 Receive)。请注意,最大超时为 24

MessagingFactory factory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", ServiceNamespace, string.Empty), credentials); 
QueueClient myQueueClient = factory.CreateQueueClient("TestQueue");
myQueueClient.Receive(new TimeSpan(hours: 0, minutes: 0, seconds: 30));

为要读取的每个队列弹出线程是一个好主意,但是看到 CLR 线程池的容量限制,您还应该考虑异步接收消息(例如使用TaskFactory.FromAsync):http: //msdn.microsoft。 com/en-us/library/windowsazure/hh851744.aspx

于 2012-06-09T22:31:00.023 回答