13.生产环境实践

本文面向生产环境,系统性阐述如何将 .NET Aspire 应用部署到 Azure Container Apps(ACA),并围绕性能、安全、高可用、自动扩缩容、备份与恢复、监控与告警以及成本优化进行深入实践说明。

一、性能优化策略

生产环境的性能优化应同时覆盖代码层面与平台层面。代码层面,建议在 Aspire 的 ServiceDefaults 中统一配置 HTTP 客户端的弹性策略、OpenTelemetry 采样与必要的诊断;平台层面,利用 ACA 的并发请求阈值、CPU/内存配额与工作负载配置,使应用具备足够的吞吐与稳定性。

在 .NET 9/10 及 Aspire 中,推荐使用 Microsoft.Extensions.ResilienceMicrosoft.Extensions.Http.Resilience(基于 Polly)来统一配置重试、超时与熔断策略。下面示例展示如何在 ServiceDefaults 项目中为所有 HttpClient 应用标准弹性管道,并根据服务的容错需求进行微调:

csharp 复制代码
// ServiceDefaults/HostingExtensions.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
using Polly;
using Polly.Retry;
using Polly.CircuitBreaker;

public static class HostingExtensions
{
	public static IServiceCollection AddServiceDefaults(this IServiceCollection services)
	{
		// 为所有 HttpClient 应用标准弹性策略(重试 + 熔断 + 超时)
		services.AddHttpClient("default")
			.AddResilienceHandler("standard-pipeline");

		services.AddResiliencePipeline("standard-pipeline", builder =>
		{
			// 重试策略:指数退避,最多重试 3 次,对瞬时错误更友好
			builder.AddRetry(new RetryStrategyOptions
			{
				MaxRetryAttempts = 3,
				Delay = TimeSpan.FromMilliseconds(200),
				BackoffType = DelayBackoffType.Exponential,
				ShouldHandle = args => ValueTask.FromResult(args.Outcome.Exception is HttpRequestException)
			});

			// 熔断策略:连续失败达到阈值后短暂切断,避免雪崩
			builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions
			{
				FailureRatio = 0.5,            // 50% 失败率触发熔断
				MinimumThroughput = 20,         // 至少 20 次调用后才评估
				BreakDuration = TimeSpan.FromSeconds(30)
			});

			// 超时:防止调用长期占用资源
			builder.AddTimeout(TimeSpan.FromSeconds(5));
		});

		return services;
	}
}

上述代码通过 AddResiliencePipeline 将重试、熔断与超时组合为一个管道,并在 AddHttpClient 时统一接入。重试策略采用指数退避减少拥塞,熔断策略在失败率过高时及时止损,超时确保资源及时释放。这种集中式的策略配置适合 Aspire 的多服务方案,避免重复实现与不一致的容错行为。

针对数据库与外部依赖的观测,可在 OpenTelemetry 中启用对应的自动化采集(如 OpenTelemetry.Instrumentation.SqlClient),同时在高并发场景下建议在 ACA 配置更高的并发阈值并提升 CPU/内存工作负载档位,以保证吞吐与延迟目标。

二、安全配置(HTTPS、认证)

在 Azure Container Apps 中,入口(Ingress)负责 TLS 终止与域名绑定,应用通常位于反向代理之后。这意味着应用需要正确处理转发头,以感知原始请求的协议与主机,避免重定向循环或 OIDC 回调失败。首先启用转发头,并在非开发环境使用 HTTPS 重定向与 HSTS:

csharp 复制代码
// 某个 ASP.NET Core 服务的 Program.cs
using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

// 允许读取 X-Forwarded-* 头,获取原始协议与客户端信息
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
	options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
	options.KnownNetworks.Clear();
	options.KnownProxies.Clear();
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
	app.UseHsts();
}

app.UseHttpsRedirection();

app.MapGet("/", () => "Secure by default");

app.Run();

由于 ACA 已处理 TLS 与入口路由,上述配置确保应用正确识别 HTTPS,并在需要时进行安全重定向与强制 HTTPS(HSTS)。反向代理场景下,不正确的转发头处理会导致"过多重定向"等问题,故需优先调用 UseForwardedHeaders()

身份认证方面,生产环境常见方案是接入 Microsoft Entra ID(原 Azure AD)并使用 JWT Bearer 保护 API。示例展示最小化的 Bearer 配置,Authority 指向租户的 v2 端点,Audience 使用你在 Entra ID 中注册的应用 ID 或自定义 API 标识符:

csharp 复制代码
// Program.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;

builder.Services
	.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
	.AddJwtBearer(options =>
	{
		options.Authority = "https://login.microsoftonline.com/<your-tenant-id>/v2.0";
		options.Audience  = "api://<your-api-app-id-or-audience>";
		// 在 ACA/反向代理场景下,回调与重定向依赖转发头,前文已启用
		options.RequireHttpsMetadata = true;
		options.SaveToken = true;
	});

builder.Services.AddAuthorization();

app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/secure", (HttpContext ctx) =>
{
	return ctx.User?.Identity?.IsAuthenticated == true
		? Results.Ok("You are authenticated.")
		: Results.Unauthorized();
}).RequireAuthorization();

当 ACA 前置了 Application Gateway/WAF 作为七层防护时,需保留原始主机头用于 OIDC/重定向的正确生成,可通过网关的 Header 重写将 Host 注入到 X-Forwarded-Host,应用端读取该头生成绝对 URL。

三、高可用性设计

高可用由应用内与平台内协同实现。应用内建议开启健康检查与就绪/存活端点,并在 ACA 的探针上配置健康检查,使入口在实例异常时自动摘除流量。Aspire 的 ServiceDefaults 提供便捷的健康检查接入,常见做法为在各服务提供 /health(就绪)与 /alive(存活),并在 ACA 入口配置相应的 Probe。

平台层面,高可用通过多副本部署与单区域/多区域容灾实现。ACA 支持将单个容器应用扩展到多个副本,并与活跃修订模式搭配滚动发布;跨区域可通过多个 ACA 环境与全局流量管理(Front Door 或 Traffic Manager)实现故障转移。数据库与缓存服务则使用各自的高可用能力(例如 Azure SQL 的自动备份与高可用、Cosmos DB 的多区域写入)。

四、自动扩缩容

在 ACA 中,扩缩容由 KEDA 驱动,支持 HTTP 并发、TCP、CPU/内存与多种事件源。对于典型 Web API,推荐使用 HTTP 并发规则,按 15 秒滑动窗口的并发请求数进行扩缩。下面以 Azure CLI 为例配置最常见的 HTTP 并发缩放,并设置最小/最大副本数:

shell 复制代码
# 设置最小与最大副本,以及 HTTP 并发阈值(超过并发阈值则横向扩展)
az containerapp update --name <APP_NAME> --resource-group <RG_NAME> --min-replicas 1 --max-replicas 10 --scale-rule-name http-rule --scale-rule-type http --scale-rule-http-concurrency 100

在事件驱动场景(例如队列长度、Kafka 消费延迟)可改用自定义规则,并且在低负载时允许缩到 0 以节省成本。需要注意缩容冷却时间与稳定窗口,避免频繁抖动。

五、备份和恢复

应用容器本身通常是无状态的,生产环境的备份与恢复重点在于状态后端,如数据库与对象存储。对于 Azure SQL Database,平台提供自动备份与时间点恢复(PITR),但也可以导出 BACPAC 到存储账户进行外部保存;对于 Cosmos DB 可依赖其自动备份策略。下面展示以 Azure CLI 执行 SQL 数据库导出到 Blob 的示例:

shell 复制代码
# 将 Azure SQL 数据库导出为 BACPAC 到存储账户
az sql db export --admin-user <SQL_ADMIN> --admin-password <SQL_PASSWORD> --name <DB_NAME> --server <SQL_SERVER_NAME> --storage-key <STORAGE_ACCOUNT_KEY> --storage-key-type StorageAccessKey --storage-uri https://<STORAGE_ACCOUNT>.blob.core.windows.net/<CONTAINER>/<FILE>.bacpac

# 基于历史备份执行时间点恢复(PITR)到新库
az sql db restore --dest-name <DB_NAME_RESTORE> --name <DB_NAME_SOURCE> --server <SQL_SERVER_NAME> --resource-group <RG_NAME> --time "2025-12-21T03:00:00Z"

对于文件与日志型数据,使用 Azure Storage 的生命周期管理与版本控制/软删除策略提高容灾能力,并通过独立备份作业(可用 Aspire 9.5 的 Azure Container App Jobs)在夜间批处理进行归档。若采用 ACA Jobs,可在 AppHost 中以 PublishAsScheduledAzureContainerAppJob("0 0 * * *") 发布一个定时任务,专门负责备份管道。

六、监控和告警

Aspire 默认集成 OpenTelemetry,生产环境建议将采集的数据接入 Azure Monitor/Application Insights,以获得统一的指标、日志与分布式追踪视图。最简方式是在应用中引入 Azure.Monitor.OpenTelemetry.AspNetCore 并调用 UseAzureMonitor(),连接字符串通过环境变量 APPLICATIONINSIGHTS_CONNECTION_STRING 提供即可:

csharp 复制代码
// Program.cs(任意 ASP.NET Core 服务)
using Azure.Monitor.OpenTelemetry.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// 将 OpenTelemetry 指向 Azure Monitor(Application Insights)
builder.Services.AddOpenTelemetry().UseAzureMonitor();

var app = builder.Build();
app.Run();

在生产环境应使用环境变量或配置文件注入连接串,避免硬编码。完成接入后,可在 Application Insights 中查看请求、依赖、异常与分布式追踪,并使用"Application Map"识别服务间调用拓扑。

在 ACA 层面还需设置平台告警,例如当 CPU 使用率、内存压力或 HTTP 5xx 比例超阈值时触发告警。可以通过 Azure Monitor 的指标告警或日志查询告警来创建规则,示例以 CPU 使用率为例:

shell 复制代码
# 创建基于容器应用 CPU 使用率的指标告警(示例,实际度量名以订阅/区域支持为准)
az monitor metrics alert create --name "aca-cpu-high" --resource-group <RG_NAME> --scopes "/subscriptions/<SUB_ID>/resourceGroups/<RG_NAME>/providers/Microsoft.App/containerApps/<APP_NAME>" --condition "avg ContainerCpuUsage > 80" --description "ACA CPU usage high" --action-group <ACTION_GROUP_RESOURCE_ID>

告警的动作建议指向通知渠道(邮件、短信、Teams、Webhook)以及自动化修复(例如扩容或触发回滚)。对于日志告警,可使用 KQL 查询 Application Insights 的失败率与响应时间分布。

七、成本优化

在无状态 Web/API 场景中,ACA 的按需缩放可以显著降低成本。合理设置 minReplicas=0 允许在闲时缩到 0;在 HTTP 并发规则中将阈值调高以减少不必要的扩容;在事件驱动场景中,通过队列长度/延迟触发扩容,并在冷却时间内避免波动。此外,在观测侧可使用 OpenTelemetry 采样减少遥测数据的摄入量。对于 ASP.NET Core,可按需配置采样比例,控制请求与依赖的采集密度,以平衡问题定位与成本。

此外,建议将开发/测试环境与生产环境分别指向不同的 Application Insights 资源,并启用数据保留与采样策略;对容器镜像与日志归档使用生命周期管理,定期清理未使用的修订与镜像标签,降低存储占用;在 ACA 工作负载档位选择上,优先评估吞吐目标与峰值,避免超配。

八、总结

本文围绕 .NET Aspire 在 Azure Container Apps 的生产落地,从性能弹性策略、反向代理场景下的 HTTPS 与认证安全、高可用的健康检查与多副本部署、基于 KEDA 的自动扩缩容、状态后端的备份与恢复、OpenTelemetry 到 Azure Monitor 的监控与告警、以及以缩到 0 与采样为核心的成本优化进行了实践说明。关键要点是:将弹性、观测与安全在 ServiceDefaults 统一接入,充分利用 ACA 的入口、扩缩容与环境隔离能力,再配合 Azure Monitor 的指标/日志与告警,实现端到端的可观测与自动化运维。配套的 ACA Jobs 能够为备份与批处理提供规范的生产运行路径,使整个系统在可靠性与成本之间取得平衡。

相关推荐
切糕师学AI9 小时前
.NET 文件操作中常见的内存泄漏场景梳理
.net·内存泄漏
唐青枫9 小时前
深入理解 C#.NET record:不可变对象与值语义的现代实践
c#·.net
追逐时光者19 小时前
一个 WPF 开源、免费的 SVG 图像查看控件
后端·.net
时光追逐者1 天前
一个基于 .NET 开源、功能强大的分布式微服务开发框架
分布式·微服务·开源·c#·.net·.net core
步步为营DotNet1 天前
深入探究.NET中依赖注入(DI)的生命周期管理:构建稳健且高效的应用
.net
步步为营DotNet1 天前
深度解析.NET中LINQ查询的延迟执行与缓存机制:优化数据查询性能
缓存·.net·linq
我是唐青枫2 天前
C#.NET ref struct 深度解析:语义、限制与最佳实践
c#·.net
武藤一雄2 天前
[奇淫巧技] WPF篇 (长期更新)
windows·microsoft·c#·.net·wpf