3

我有一个工作角色,将数据放入大约 10 个需要处理的队列中。有很多数据 - 可能每秒大约 10-100 条消息在各种队列中排队。

队列保存不同的数据并分别处理它们。特别是有一个非常活跃的队列。

我现在设置它的方式,我是一个单独的工作者角色,它产生 10 个不同的线程,每个线程执行一个方法,该方法有一段时间(真){从队列中获取消息并处理它}。每当队列中的数据得到备份时,我们只需启动更多此类进程以帮助加快队列中数据的处理速度。此外,由于一个队列更活跃,我实际上启动了许多指向同一方法的线程来处理来自该队列的数据。

但是,我看到部署的 CPU 利用率很高。几乎始终处于或接近 100%。

我想知道这是否是因为线程饥饿?还是因为访问队列是 RESTful 的,并且线程最终通过建立连接并减慢速度而相互阻塞?或者,是因为我使用:

while(true)
{
   var message = get message from queue;
   if(message != null)
   {
       //process message
   }
}

这执行得太快了?

消息的每次处理也会将其保存到 Azure 表存储或数据库 - 因此可能是保存此数据的过程正在消耗 CPU。

实际上,调试高 CPU 负载真的很困难。所以,我的问题是:我是否可以进行一般的架构更改来帮助缓解+防止任何可能存在的问题?(例如,使用不同类型的轮询而不是使用 while(true) - 尽管我认为该示例最终是相同的)。

也许简单地使用 new Thread() 产生新线程并不是最好的方法。

4

5 回答 5

10

我建议在你的循环中放置一个 sleep 语句......这个紧密的循环不仅可能会占用 CPU 资源,而且你还需要为存储交易付费。每检查一万次队列,就要花一分钱。这是一个很小的成本,但随着时间的推移,它可能会变得很重要。

我也经常使用这样的代码:

while(true) { var msg = q1.GetMessage(); if (msg != null) { ... } msg = q2.GetMessage(); if (msg != null) { ... } }

换句话说,串行而不是并行轮询队列(这应该完全是一个词)。这样一来,您实际上一次只做一件事(如果您的任务是 CPU 密集型的,这很有用),但您仍在检查每个循环中的所有队列。

于 2010-11-03T06:28:57.247 回答
3

CPU也有同样的问题。这可能是由于 Azure 队列的本地实现效率低下造成的。

最后,我添加了指数睡眠策略(用于实施 - 请参阅Lokad.CQRS for Azure项目),其中经常轮询队列,但如果其中任何一个都没有消息,我们会逐渐开始增加睡眠间隔,直到达到一些上限。如果发现消息 - 我们立即删除间隔。

这种方式在整个系统上不会浪费存储事务(和本地开发 CPU),但如果多条消息连续出现,则保持极快的响应。

于 2010-11-03T06:33:35.113 回答
2

查看Brian Hitney 的Scaling Down Azure Roles视频。基本方法是产生一些线程,每个线程都有一个“worker”,然后监视给定的队列并采取适当的行动。特别是这可以防止一个队列阻塞其他队列....

于 2010-11-04T12:38:16.237 回答
1

有一篇很棒的 MSDN 文章涵盖了所有这些

MSDN - 在 Windows Azure 上最大化基于队列的消息传递解决方案的可扩展性和成本效益的最佳实践

它谈到了在有工作要做时添加线程和实例 - 并在没有工作时退出,这样你就不会连续和不必要地从多个线程和实例轮询队列,增加交易成本并将 CPU 变成加热器持续 100% 的 CPU 利用率。

于 2012-06-15T09:01:11.010 回答
1

我认为您的问题来自循环实现。轮询必须通过诸如 sleep() 之类的东西来减慢。否则,没有什么可以阻止循环消耗 100% 的 CPU 内核(这实际上是正常行为)。

于 2010-11-03T09:10:24.463 回答