工作者角色过程 - 配置值轮询

时间:2013-10-28 07:24:02

标签: c# .net azure azure-web-roles azure-worker-roles

我有一个Worker角色来处理队列中的项目。它基本上是一个无限循环,它将项目从队列中弹出并异步处理它们。

我有两个配置设置(PollingIntervalMessageGetLimit),我希望更改后可以获取辅助角色(因此不需要重新启动)。

private TimeSpan PollingInterval 
{
    get
    {
        return TimeSpan.FromSeconds(Convert.ToInt32(RoleEnvironment.GetConfigurationSettingValue("PollingIntervalSeconds")));
    }
}

private int MessageGetLimit 
{ 
    get 
    {
        return Convert.ToInt32(RoleEnvironment.GetConfigurationSettingValue("MessageGetLimit"));
    } 
}

public override void Run()
{
    while (true)
    {
        var messages = queue.GetMessages(MessageGetLimit);

        if (messages.Count() > 0)
        {
            ProcessQueueMessages(messages);
        }
        else
        {
            Task.Delay(PollingInterval);
        }
    }
}

问题:

在高峰时段,while循环可能每秒运行几次。这意味着它每天最多可查询配置项100,000次。

这有害还是低效?

2 个答案:

答案 0 :(得分:3)

John的答案很好,使用环境更改/更改事件来修改您的设置而不重启,但我想也许更好的方法是使用指数退避策略使您的轮询更多高效。通过使代码行为更加智能化,您将减少调整它的频率。请记住,每次更新这些环境设置时,都必须将其推广到所有实例,这可能需要一些时间,具体取决于您运行的实例数。此外,你在这里迈出了一步,人类必须参与其中。

您正在使用Windows Azure存储队列,这意味着每次GetMessages执行它时都会调用该服务并检索0个或更多消息(直到您的MessageGetLimit)。每当它要求您收取交易费用时。现在,了解交易真的很便宜。每天甚至100,000笔交易是0.01美元/天。但是,不要低估循环的速度。 :)你可能获得更多的吞吐量,如果你有多个工作者角色实例,这会增加(虽然与实际运行实例本身相比仍然是一个非常小的金额)。

更有效的途径是采用指数退避方法从队列中读取消息。看看Maarten的这篇文章就一个简单的例子:http://www.developerfusion.com/article/120619/advanced-scenarios-with-windows-azure-queues/。结合退出方法,根据队列深度自动调整工作者角色,您将拥有一个更少依赖于人工调整设置的解决方案。输入实例计数的最小值和最大值,根据消息在下次请求消息时出现的次数来调整要提取的消息数量等。这里有很多选项可以减少您的参与并拥有一个高效的系统。

此外,您可能会查看Windows Azure Service Bus Queues,因为它们实现了长轮询,因此在等待工作到达队列时会导致更少的事务。

答案 1 :(得分:2)

Upfront disclaimer,我没有使用RoleEnvironments。

GetConfigurationSettingValue的MDSN文档指出从磁盘读取配置。 http://msdn.microsoft.com/en-us/library/microsoft.windowsazure.serviceruntime.roleenvironment.getconfigurationsettingvalue.aspx。所以经常打电话肯定会很慢。

MSDN文档还显示设置更改时触发了一个事件。 http://msdn.microsoft.com/en-us/library/microsoft.windowsazure.serviceruntime.roleenvironment.changed.aspx。您可以使用此事件仅在实际更改时重新加载设置。

这是一种(未经测试,未编译)的方法。

private TimeSpan mPollingInterval;
private int mMessageGetLimit;

public override void Run()
{
    // Refresh the configuration members only when they change.
    RoleEnvironment.Changed += RoleEnvironmentChanged;

    // Initialize them for the first time
    RefreshRoleEnvironmentSettings();

    while (true)
    {
        var messages = queue.GetMessages(mMessageGetLimit);

        if (messages.Count() > 0)
        {
            ProcessQueueMessages(messages);
        }
        else
        {
            Task.Delay(mPollingInterval);
        }
    }
}

private void RoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e)
{
    RefreshRoleEnvironmentSettings();    
}

private void RefreshRoleEnvironmentSettings()
{
    mPollingInterval = TimeSpan.FromSeconds(Convert.ToInt32(RoleEnvironment.GetConfigurationSettingValue("PollingIntervalSeconds")));
    mMessageGetLimit = Convert.ToInt32(RoleEnvironment.GetConfigurationSettingValue("MessageGetLimit"));
}