基于MassTransit与Azure ServiceBus实现Azure Container App工作者缩容至零
针对MassTransit+Azure Container Apps零缩容的问题解答
1. 编程方式创建弹性伸缩规则(运行时生成实体名场景)
- 容器启动时,通过MassTransit API获取自动生成的ServiceBus实体名称:
// 从总线拓扑中提取主题与订阅名称 var bus = serviceProvider.GetRequiredService<IBus>(); var topicName = bus.Topology.Publish.GetMessageTopology<MyMessage>().EntityName; var subscriptionName = bus.Topology.Subscribe.GetConsumerTopology<MyConsumer>().EntityName; var subscriptionPath = $"{serviceBusNamespace}/{topicName}/{subscriptionName}"; - 使用Azure管理SDK动态创建伸缩规则:
var containerAppClient = new ContainerAppsClient(new DefaultAzureCredential(), subscriptionId); var scaleRule = new ScaleRule() { Name = "servicebus-scale", Trigger = new ScaleRuleTrigger() { Type = "servicebus", Metadata = new Dictionary<string, string>() { ["queueName"] = subscriptionPath, ["messageCount"] = "1", ["namespace"] = serviceBusNamespace }, Authentication = new ScaleRuleAuth() { SecretRef = "servicebus-connection-string", TriggerParameter = "connection" } }, Scale = new ScaleRuleScale() { MinReplicas = 0, MaxReplicas = 5, Cooldown = "PT5M" } }; await containerAppClient.ScaleRules.CreateOrUpdateAsync(resourceGroupName, containerAppName, "servicebus-scale", scaleRule); - 权限配置:为容器应用托管标识分配
Container App Contributor和Service Bus Data Reader权限,确保能读取队列深度并修改伸缩规则。
2. 针对ServiceBus主题的伸缩规则配置
Azure Container Apps UI仅显示队列选项,但可通过CLI或API直接针对主题订阅配置规则(订阅本质是后台队列):
- 使用Azure CLI创建规则:
az containerapp rule create \ --resource-group <your-rg> \ --name <your-container-app> \ --rule-name topic-sub-scale \ --type scale \ --trigger-type servicebus \ --source <servicebus-conn-secret-name> \ --queue-name "<namespace>/<topic-name>/<subscription-name>" \ --min-replicas 0 \ --max-replicas 5 \ --threshold 1 \ --cooldown 300 - 核心是在
--queue-name参数中填入订阅的完整路径(命名空间/主题/订阅),Azure会识别该路径对应的订阅消息队列作为伸缩触发器。
3. Bicep部署阶段提前知晓实体名称
有两种可靠方案:
方案一:利用MassTransit默认命名规则构造名称
MassTransit默认将类型FullName中的点替换为下划线作为实体名,例如:
- 消息类型
MyApp.Orders.OrderSubmitted对应主题名MyApp_Orders_OrderSubmitted - 消费者类型
MyApp.Orders.OrderSubmittedConsumer对应订阅名MyApp_Orders_OrderSubmittedConsumer
在Bicep中通过变量提前构造:
var serviceBusNamespaceName = 'your-servicebus-namespace' var messageTypeFullName = 'MyApp.Orders.OrderSubmitted' var consumerTypeFullName = 'MyApp.Orders.OrderSubmittedConsumer' var topicName = replace(messageTypeFullName, '.', '_') var subscriptionName = replace(consumerTypeFullName, '.', '_') var subscriptionPath = '${serviceBusNamespaceName}/${topicName}/${subscriptionName}' // 在伸缩规则资源中使用subscriptionPath resource containerAppScaleRule 'Microsoft.App/containerApps/scaleRules@2023-05-01' = { parent: containerApp name: 'servicebus-topic-scale' properties: { trigger: { type: 'servicebus' metadata: { queueName: subscriptionPath messageCount: '1' namespace: serviceBusNamespaceName } authentication: [ { secretRef: 'servicebus-connection' triggerParameter: 'connection' } ] } scale: { minReplicas: 0 maxReplicas: 5 cooldown: 'PT5M' } } }
方案二:显式指定MassTransit实体名称
在MassTransit配置中手动指定主题和订阅名称,消除默认规则的不确定性:
services.AddMassTransit(cfg => { cfg.AddConsumer<OrderSubmittedConsumer>(); cfg.UsingAzureServiceBus((ctx, sbCfg) => { sbCfg.Host(Environment.GetEnvironmentVariable("ServiceBusConnection")); // 显式指定主题名称 sbCfg.Message<OrderSubmitted>(x => x.SetEntityName("OrderSubmittedTopic")); // 显式指定订阅名称 sbCfg.SubscriptionEndpoint<OrderSubmitted>("OrderSubmittedSubscription", x => { x.ConfigureConsumer<OrderSubmittedConsumer>(ctx); }); }); });
之后在Bicep中直接使用指定的OrderSubmittedTopic和OrderSubmittedSubscription构造路径即可,完全可控。
内容的提问来源于stack exchange,提问作者Evan Nielsen
相关产品推荐
相关产品推荐

