在Azure功能应用程序中限制Azure存储队列处理

问题描述 投票:20回答:2

我创建了一个Azure功能应用程序,其中包含一个Azure存储队列触发器,用于处理每个队列项都是URL的队列。该功能只下载URL的内容。我有另一个函数加载和解析站点的XML站点地图,并将所有页面URL添加到队列中。我遇到的问题是,功能应用程序运行得太快,它会破坏网站,使其开始返回服务器错误。有没有办法限制/限制功能应用程序运行的速度?

当然,我可以编写一个简单的Web作业来连续处理它们(或者使用一些异步但限制并发请求的数量),但我真的很喜欢Azure Functions的简单性并想尝试“无服务器”计算。

azure azure-functions
2个回答
28
投票

您可以考虑几个选项。

首先,你可以在控制队列处理的host.json中配置一些旋钮(记录为here)。 queues.batchSize旋钮是一次获取多少队列消息。如果设置为1,则运行时将一次获取1条消息,并且仅在完成该消息的处理时获取下一条消息。这可以为您提供单个实例的某种级别的序列化。

另一个选项可能是您在排队的消息上设置NextVisibleTime,使它们间隔开 - 默认情况下,排队的消息变为可见并准备好立即处理。

最后一个选项可能是您将一个消息与一个站点的所有URL集合排队,而不是一次排队,因此在处理消息时,您可以在函数中串行处理URL,并限制并行性那样。


1
投票

如果有几个并行函数添加到队列中,NextVisibleTime可能会变得混乱。对于遇到此问题的任何人来说,另一个简单的选择:创建另一个队列,“throttled-items”,并让您的原始函数跟随队列触发器。然后,添加一个简单的计时器函数,每分钟从原始队列移动消息,相应地间隔NextVisibleTime。

    [FunctionName("ThrottleQueueItems")]
    public static async Task Run([TimerTrigger("0 * * * * *")] TimerInfo timer, ILogger logger)
    {
        var originalQueue = // get original queue here;
        var throttledQueue = // get throttled queue here;
        var itemsPerMinute = 60; // get from app settings
        var individualDelay = 60.0 / itemsPerMinute;
        var totalRetrieved = 0;
        var maxItemsInBatch = 32; // change if you modify the default queue config
        do
        {
            var pending = (await originalQueue.GetMessagesAsync(Math.Min(maxItemsInBatch, htmlPerMinute - totalRetrieved))).ToArray();
            if (!pending.Any())
                break;
            foreach (var message in pending)
            {
                await throttledQueue.AddMessageAsync(new CloudQueueMessage(message.AsString), null,
                                                                                        TimeSpan.FromSeconds(individualDelay * ++totalRetrieved), null, null);
                await originalQueue.DeleteMessageAsync(message);
            }
        } while (itemsPerMinute > totalRetrieved);
    }
© www.soinside.com 2019 - 2024. All rights reserved.