我有一个属于专用计划(Azure 应用服务计划 P1V2)的 Azure 函数应用程序。
Azure Function App 具有用于 Azure 存储队列的队列触发器功能。
我希望尽可能接近 FIFO,我意识到 Azure 存储队列不能保证真正的 FIFO,但文档还指出 Azure 存储队列和队列触发器通常遵循先进先出。 (请参阅“其他信息”https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-azure-and-service-bus-queues-compared-contrasted#additional-information )
我的host.json如下:
{
"version": "2.0",
"extensions": {
"queues": {
"batchSize": 1,
"maxDequeueCount": 10,
"newBatchThreshold": 0
}
}
}
我的应用程序设置为
WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT = 1
,它应该在自动缩放情况下将虚拟机数量限制为 1。 (附带问题:当功能应用程序处于专用计划下时,此应用程序设置是否无用?它仅适用于消费和弹性高级计划吗?我问是因为 Microsoft.Web/sites、arm 模板有一个类似的站点配置) :
似乎是的,我的队列触发器一次执行一个,并且我看不到超过 1 个实例正在运行的“可见”证据(即使在高容量期间)。
但是,队列触发器仍然没有按照队列插入时间的顺序启动。我以特定顺序插入了 3 条消息,但队列触发器在消息 2 之前处理了消息 3(同样,容量很大,还存在其他消息)
我注意到,当 CPU 百分比过高时,应用服务计划中的自动缩放有一些规则,最多允许 10 个实例,最少 1 个实例,默认为 1 个实例。
我可以通过 Azure 功能级别的设置在应用程序服务计划级别覆盖此自动缩放吗?这已经由
WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT = 1
完成了吗?
设置
WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT
主要适用于消费和弹性保费计划,不适用于您正在使用的专用计划(P1V2)。在专用计划中,Azure Functions 在专用 VM 实例上运行,因此扩展行为的管理方式不同,并且此设置不会直接影响您的函数应用。
专用计划中的自动缩放在应用服务计划级别进行控制,而不是在函数应用本身内进行控制。您在应用服务计划级别配置的自动缩放规则可以覆盖在函数应用配置中限制缩放的任何尝试。
您可以创建自定义自动缩放规则来根据特定指标扩展您的应用程序:-
您可以修改应用服务计划中的自动缩放设置,以确保一次仅运行一个实例,但这可能会影响峰值负载期间的性能和可扩展性。考虑在函数应用中实现自定义逻辑,以强制执行严格的消息排序,例如检查时间戳,而不管队列检索顺序如何。
自定义逻辑:-
using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
namespace FunctionApp5
{
public class Function1
{
[FunctionName("Function1")]
public void Run([ServiceBusTrigger("myqueue", Connection = "servicebusconn")] string myQueueItem, ILogger log)
{
try
{
if (string.IsNullOrEmpty(myQueueItem))
{
log.LogError("Received empty or null message from the queue.");
return;
}
log.LogInformation($"Received message from the queue: {myQueueItem}");
var message = Newtonsoft.Json.JsonConvert.DeserializeObject<MyMessage>(myQueueItem);
if (message.Timestamp < previousMessageTimestamp)
{
log.LogError($"Received out-of-order message at timestamp: {message.Timestamp}");
}
else
{
previousMessageTimestamp = message.Timestamp;
log.LogInformation($"Processing message received at timestamp: {message.Timestamp}");
}
}
catch (Exception ex)
{
log.LogError($"An error occurred while processing the message: {ex.Message}");
}
}
public class MyMessage
{
public DateTime Timestamp { get; set; }
}
private static DateTime previousMessageTimestamp = DateTime.MinValue;
}
}
虽然 Azure 存储队列通常遵循 FIFO(先进先出)模式,但实际处理顺序可能会因并发、消息可见性超时和重试等因素而有所不同。即使您的队列触发器设置为一次处理一条消息(batchSize 为 1),函数应用的多个实例的并发执行(可能是由于自动缩放或其他因素)可能会影响消息处理的顺序。”