辅助角色进程 - 配置值轮询

本文关键字:配置 角色 进程 | 更新日期: 2023-09-27 18:37:08

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

我有两个配置设置(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 次配置项。

这是有害的还是低效的?

辅助角色进程 - 配置值轮询

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

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

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

此外,您可以查看Windows Azure 服务总线队列,因为它们实现了长轮询,因此在等待工作进入队列时,它会导致更少的事务。

预先免责声明,我没有使用过 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"));
}