首页 文章

构建Azure工作者角色以处理来自~10个队列的数据的最佳方法

提问于
浏览
3

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

队列包含不同的数据并分别处理它们 . 特别是有一个非常活跃的队列 .

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

但是,我发现部署的CPU利用率很高 . 几乎达到或接近100% .

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

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

这会被执行得太快?

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

实际上,调试高CPU负载非常困难 . 所以,我的问题是:我是否可以进行一般性的架构更改,以帮助缓解可能存在的任何可能的问题? (例如,而不是使用while(true)使用不同类型的轮询 - 尽管我认为最后这个例子是相同的) .

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

5 回答

  • 1

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

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

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

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

  • 1

    与CPU有同样的问题 . 它可能是由Azure队列的非高效本地实现引起的 .

    最后,我添加了指数睡眠策略(用于实现 - 在Lokad.CQRS for Azure项目中检出),其中队列被频繁轮询,但如果任何一个都没有消息,我们逐渐开始增加睡眠间隔,直到它到达某个上边界 . 如果发现了消息 - 我们立即删除间隔 .

    这种方式总体而言系统不会浪费存储事务(和本地开发CPU),但如果连续出现多条消息,则会保持极其响应 .

  • 2

    查看由Brian Hitney撰写的Scaling Down Azure Roles视频 . 基本方法是生成一些线程,每个线程都有一个"worker",而不是监视给定的队列并采取适当的行动 . 特别是这使一个队列阻止其他队列....

  • 2

    我认为你的问题来自循环实现 . 必须通过类似sleep()的方式减慢轮询速度 . 否则,什么都不会阻止循环消耗100%CPU核心(这实际上是正常行为) .

  • 9

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

    MSDN - Best Practices for Maximizing Scalability and Cost Effectiveness of Queue-Based Messaging Solutions on Windows Azure

    它讨论了在有工作要做的时候添加线程和实例 - 并且在没有工作的情况下进行备份 - 当你没有连续不必要地从多个线程和实例轮询队列,增加交易成本并将CPU变成加热器时持续100%的CPU利用率 .

相关问题