你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 .NET 的可靠 Web 应用模式 - 应用该模式

Azure 应用服务
Azure Front Door
用于 Redis 的 Azure 缓存
.NET

本文介绍如何应用可靠 Web 应用模式。 可靠 Web 应用模式是一套用于定义迁移到云时应如何修改 Web 应用(重新架构)的原则和实现技术。 它重点关注在云中取得成功所需的最低限度代码更新。

为便于应用本指南,可以部署可靠 Web 应用模式的参考实现

显示了参考实现的体系结构的示意图。参考实现的体系结构。下载此体系结构的 Visio 文件

以下指南在整个过程中均以参考实现作为示例。 若要应用可靠 Web 应用模式,请遵循与架构良好的框架要素一致的以下建议:

可靠性

可靠性可确保应用程序符合你对客户的承诺。 有关详细信息,请参阅可靠性设计评审核对清单。 可靠 Web 应用模式通过在代码级别引入两个关键设计模式来提高可靠性:重试模式和断路器模式。

使用重试模式

重试模式可解决临时服务中断(称为暂时性故障),这些故障通常可在数秒钟内解决。 这些故障通常由云环境中的服务限制、动态负载分发和网络问题导致。 实现重试模式涉及重新发送失败请求,从而在承认失败之前允许可配置的延迟和尝试。

使用重试模式的应用程序应集成 Azure 的客户端软件开发工具包 (SDK) 和服务特定的重试机制,以提高效率。 缺少此模式的应用程序应使用以下指南采用重试模式。

首先尝试使用 Azure 服务和客户端 SDK

大多数 Azure 服务和客户端 SDK 都有内置的重试机制。 应使用 Azure 服务的内置重试机制来加快实现速度。

示例:参考实现使用 Entity Framework Core 中的连接复原,在对 Azure SQL Database 的请求中应用重试模式(请参阅以下代码)。

services.AddDbContextPool<ConcertDataContext>(options => options.UseSqlServer(sqlDatabaseConnectionString,
    sqlServerOptionsAction: sqlOptions =>
    {
        sqlOptions.EnableRetryOnFailure(
        maxRetryCount: 5,
        maxRetryDelay: TimeSpan.FromSeconds(3),
        errorNumbersToAdd: null);
    }));

当客户端库不支持重试时,请使用 Polly 库

可能需要调用不是 Azure 服务或原生不支持重试模式的依赖项。 在这种情况下,应使用 Polly 库来实现重试模式。 Polly 是一个 .NET 复原和暂时性错误处理库。 借助它,可以使用 Fluent API 来描述应用程序中心位置的行为。

示例:参考实现使用 Polly 来设置 ASP.NET Core 依赖项注入。 每次代码构造调用 IConcertSearchService 对象的对象时,Polly 都会强制实施重试模式。 在 Polly 框架中,该行为称为策略。 代码在 GetRetryPolicy 方法中提取此策略,GetRetryPolicy 方法在每次前端 Web 应用调用 Web API 音乐会搜索服务时应用重试模式(请参阅以下代码)。

private void AddConcertSearchService(IServiceCollection services)
{
    var baseUri = Configuration["App:RelecloudApi:BaseUri"];
    if (string.IsNullOrWhiteSpace(baseUri))
    {
        services.AddScoped<IConcertSearchService, MockConcertSearchService>();
    }
    else
    {
        services.AddHttpClient<IConcertSearchService, RelecloudApiConcertSearchService>(httpClient =>
        {
            httpClient.BaseAddress = new Uri(baseUri);
            httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
            httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, "Relecloud.Web");
        })
        .AddPolicyHandler(GetRetryPolicy())
        .AddPolicyHandler(GetCircuitBreakerPolicy());
    }
}

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    var delay = Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromMilliseconds(500), retryCount: 3);
    return HttpPolicyExtensions
      .HandleTransientHttpError()
      .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
      .WaitAndRetryAsync(delay);
}

RelecloudApiConcertSearchService 实例的策略处理程序对 API 的所有请求应用重试模式。 它使用 HandleTransientHttpError 逻辑来检测可以安全重试的 HTTP 请求,然后根据配置重试请求。 它包括一些随机性,以便在发生错误时顺利应对 API 流量中的潜在突发。

使用断路器模式

将重试模式和断路器模式配对可扩展应用程序处理与暂时性故障无关的服务中断的功能。 断路器模式可防止应用程序持续尝试访问无响应服务。 断路器模式释放应用程序并避免浪费 CPU 周期,以便应用程序为最终用户保留其性能完整性。

示例:参考实现在 GetCircuitBreakerPolicy 方法中添加了断路器模式(请参阅以下代码)。

private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}

在代码中,RelecloudApiConcertSearchService 实例的策略处理程序对 API 的所有请求应用断路器模式。 它使用 HandleTransientHttpError 逻辑来检测可以安全重试的 HTTP 请求,但限制指定时间段内的聚合错误数。

安全性

安全性针对蓄意攻击及滥用宝贵数据和系统提供保障措施。 有关详细信息,请参阅可靠性设计审查检查表。 可靠 Web 应用模式使用托管标识来实现以标识为中心的安全性。 专用终结点、Web 应用程序防火墙和对 Web 应用的受限访问提供安全入口。

强制实施最小特权

为了确保安全和效率,仅向用户(用户标识)和 Azure 服务(工作负载标识)授予所需的权限。

为用户标识分配权限

评估应用程序需求,以定义一组角色,这些角色涵盖所有用户操作而不重叠。 为每个用户找到最合适的角色。 确保他们只能访问其履行职责所需了解的内容。

为工作负载标识分配权限

仅授予对操作至关重要的权限,例如数据库中的 CRUD 操作或访问机密。 工作负载标识具有永久权限,因此无法为工作负载标识提供实时或短期权限。

  • 首选基于角色的访问控制 (RBAC)。 始终从 Azure RBAC 开始分配权限。 提供精确的控制,确保可审核的精细访问。 使用 Azure RBAC 仅授予服务执行其预期功能所需的权限。

  • 补充 Azure 服务级别访问控制。 如果 Azure RBAC 未涵盖特定方案,请补充 Azure 服务级别访问策略。

配置用户身份验证和授权

身份验证和授权是 Web 应用程序安全性的关键方面。 身份验证是验证用户身份的过程。 授权规定用户可以在应用程序中执行的操作。 目标是在不削弱安全状况的前提下实现身份验证和授权。 若要实现此目标,需要使用 Azure 应用程序平台的功能(Azure 应用服务)和标识提供者 (Microsoft Entra ID)。

配置用户身份验证

通过平台的各种功能启用用户身份验证来保护 Web 应用。 Azure App Service 支持使用标识提供者(如 Microsoft Entra ID)进行身份验证,从而从代码卸载身份验证工作负载。

配置服务身份验证和授权

配置服务身份验证和授权,以便环境中的服务具有执行必要功能的权限。 使用 Microsoft Entra ID 中的托管标识自动创建和管理服务标识,从而消除手动凭据管理。 托管标识允许 Web 应用安全地访问 Azure 服务,例如 Azure Key Vault 和数据库。 它还有助于 CI/CD 管道集成,用于部署到 Azure App Service。 但是,混合部署或旧版系统等方案中仍继续使用本地身份验证解决方案来简化迁移。 当系统准备好采用现代标识管理方法时,转换到托管标识。 有关详细信息,请参阅监视托管标识

使用 DefaultAzureCredential 设置代码

使用 DefaultAzureCredential 在云端为本地开发和托管标识提供凭据。 DefaultAzureCredential 生成用于 OAuth 令牌获取的 TokenCredential。 处理大多数 Azure SDK 方案和 Microsoft 客户端库。 检测应用程序的环境,以根据需要使用正确的标识并请求访问令牌。 DefaultAzureCredential 可简化 Azure 部署的应用程序的身份验证。有关详细信息,请参阅 DefaultAzureCredential

示例:参考实现在启动期间使用 DefaultAzureCredential 类,以便在 Web API 和 Key Vault 之间使用托管标识(请参阅以下代码)。

builder.Configuration.AddAzureAppConfiguration(options =>
{
     options
        .Connect(new Uri(builder.Configuration["Api:AppConfig:Uri"]), new DefaultAzureCredential())
        .ConfigureKeyVault(kv =>
        {
            // Some of the values coming from Azure App Configuration are stored Key Vault. Use
            // the managed identity of this host for the authentication.
            kv.SetCredential(new DefaultAzureCredential());
        });
});

使用基础结构即代码创建托管标识

应使用 Bicep 模板来创建和配置 Azure 基础结构以支持托管标识。 托管标识不使用机密或密码,因此无需密钥保管库或机密轮换策略即可确保完整性。 可以将连接字符串存储在应用程序配置服务中。

示例:参考实现使用 Bicep 模板 (1) 创建托管标识,(2) 将标识与 Web 应用关联,以及 (3) 授予标识访问 SQL 数据库的权限。 连接字符串中的 Authentication 参数告知 Microsoft 客户端库使用托管标识进行连接(请参阅以下代码)。

    Server=tcp:my-sql-server.database.windows.net,1433;Initial Catalog=my-sql-database;Authentication=Active Directory Default

有关详细信息,请参阅从 .NET 应用服务连接到 SQL 数据库

使用中央机密存储来管理机密

将应用程序转移到云端时,请使用 Azure Key Vault 安全地存储所有此类机密。 此集中式存储库为不支持托管标识的服务提供安全存储、密钥轮换、访问审核和监视。 对于应用程序配置,建议采用 Azure App Configuration

示例:参考实现在密钥保管库中存储以下机密:(1) PostgreSQL 数据库用户名和密码,(2) Redis 缓存密码,以及 (3) 与 Microsoft 身份验证库 (MSAL) 实现关联的 Microsoft Entra ID 的客户端密码。

不要将密钥保管库置于 HTTP 请求流中

在应用程序启动时(而不是在每个 HTTP 请求期间)从密钥保管库加载机密。 密钥保管库用于在部署期间安全地存储和检索敏感数据。 HTTP 请求中的高频率访问可能会超过密钥保管库的吞吐容量,从而导致请求限制和 HTTP 状态代码 429 错误。 更多信息请参阅《密钥保管库事务限制》。

使用一种方法访问密钥保管库中的机密

有两个主要选项可配置 Web 应用以访问密钥保管库中的机密:

  • 应用程序服务应用设置:使用应用程序服务中的应用设置将机密直接注入为环境变量

  • 直接机密引用:直接引用应用程序代码中的机密。 在应用程序的属性文件(例如适用于 Java 应用程序的 application.properties)中添加特定引用,以便应用与密钥保管库通信。

为简单起见,请务必选择其中一种方法并坚持使用,以避免不必要的复杂性。

首选临时访问方法

使用临时权限来防范未经授权的访问和违规。 使用共享访问签名 (SAS) 进行临时访问。 使用用户委派 SAS 在授予临时访问权限时最大程度地提高安全性。 它是唯一使用 Microsoft Entra 凭据且不需要存储帐户密钥的 SAS。

使用专用终结点

在所有生产环境中为所有受支持的 Azure 服务使用专用终结点。 专用终结点为 Azure 虚拟网络资源和 Azure 服务提供专用连接。 默认情况下,与大多数 Azure 服务的通信会跨公共网络。 专用终结点不需要任何代码更改、应用配置或连接字符串。 有关详细信息,请参阅如何创建专用终结点确保终结点安全的最佳做法

示例:Azure App Configuration、Azure SQL Database、Azure Cache for Redis、Azure Storage、Azure App Service 和 Key Vault 使用专用终结点。

使用 Web 应用程序防火墙并限制入站 Internet 流量

发往 Web 应用的所有入站 Internet 流量都必须通过 Web 应用程序防火墙,以防止常见的 Web 攻击。 强制所有入站 Internet 流量通过公共负载均衡器(如果有)和 Web 应用程序防火墙。

示例:参考实现强制所有入站 Internet 流量通过 Front Door 和 Azure Web 应用程序防火墙。 在生产中,保留原始 HTTP 主机名

配置数据库安全性

对数据库的管理员级别访问权限授予执行特权操作的权限。 特权操作包括创建和删除数据库、修改表架构或更改用户权限。 开发人员通常需要管理员级访问权限来维护数据库或排查问题。

  • 避免永久提升权限。 应仅向开发人员授予执行特权操作需要的实时访问权限。 通过实时访问,用户将获得临时权限来执行特权任务

  • 请勿授予应用程序提升的权限。 不应授予能够获取应用程序标识的管理员级别访问权限。 应为应用程序配置对数据库的最低特权访问。 如此可以限制 bug 和安全漏洞的爆发半径。

成本优化

成本优化是寻找方法来减少不必要的费用和管理开销。 有关详细信息,请参阅成本优化设计评审核对清单。 可靠 Web 应用模式通过合理精简技术、自动缩放和高效资源使用来实现成本更优化的 Web 应用。

针对每个环境调整资源大小

了解 Azure 服务的不同性能层,并仅使用相应的 SKU 来满足每个环境的需求。 生产环境需要满足生产所需的服务级别协议 (SLA)、功能和规模的 SKU。 非生产环境通常不需要相同的功能。 若要节省额外成本,请考虑 Azure 开发/测试定价选项Azure 预留用于计算的 Azure 节省计划

示例:参考实现使用 Bicep 参数触发资源部署配置。 其中一个参数指示要部署的资源层 (SKU)。 Web 应用为生产环境使用性能更高、成本更高的 SKU,而为非生产环境使用成本更低的 SKU(请参阅以下代码)。

var redisCacheSkuName = isProd ? 'Standard' : 'Basic'
var redisCacheFamilyName = isProd ? 'C' : 'C'
var redisCacheCapacity = isProd ? 1 : 0

使用自动缩放

自动缩放可为生产环境自动执行横向缩放。 按性能指标自动缩放。 如果你不了解应用程序的缩放条件,CPU 使用率性能触发器是一个很好的起点。 需要配置和调整缩放触发器(CPU、RAM、网络和磁盘)以与 Web 应用程序的行为相对应。 不要垂直缩放以满足经常变化的需求。 它的成本效益较低。 有关详细信息,请参阅在 Azure 应用服务中进行缩放在 Microsoft Azure 中进行自动缩放

示例:参考实现在 Bicep 模板中使用以下配置。 它为 Azure 应用服务创建自动缩放规则。 该规则最多可扩展到 10 个实例,默认为一个实例。 它使用 CPU 使用率作为缩放的触发器。Web 应用托管平台在 CPU 使用率达到 85% 时横向扩展,而在 CPU 使用率达到 60% 时横向缩减。 横向扩展设置为 85% 而不是接近 100% 的百分比提供了缓冲区,可防止粘性会话导致的累积用户流量。 它还通过提前缩放来防止流量激增,从而避免 CPU 使用率达到上限。 这些自动缩放规则并不通用(请参阅以下代码)。

resource autoScaleRule 'Microsoft.Insights/autoscalesettings@2022-10-01' = if (autoScaleSettings != null) { 
  name: '${name}-autoscale' 
  location: location 
  tags: tags 
  properties: { 
    targetResourceUri: appServicePlan.id 
    enabled: true 
    profiles: [ 
      { 
        name: 'Auto created scale condition' 
        capacity: { 
          minimum: string(zoneRedundant ? 3 : autoScaleSettings!.minCapacity) 
          maximum: string(autoScaleSettings!.maxCapacity) 
          default: string(zoneRedundant ? 3 : autoScaleSettings!.minCapacity) 
        } 
        rules: [ 
          ... 
        ] 
      } 
    ] 
  } 
}

有效使用资源

  • 使用共享服务。 集中和共享某些资源可提供成本优化和较低的管理开销。 将共享网络资源置于中心虚拟网络中。

    示例:参考实现将 Azure Firewall、Azure Bastion 和 Key Vault 置于中心虚拟网络中。

  • 删除未使用的环境。 在下班后或节假日期间删除非生产环境,以优化成本。 可以使用基础结构即代码删除 Azure 资源和整个环境。 删除要从 Bicep 模板中删除的资源的声明。 使用 What-if 操作在更改生效之前预览更改。 备份日后需要使用的数据。 了解要删除的资源的依赖项。 如果有依赖项,则可能需要更新或删除这些资源。 有关详细信息,请参阅 Bicep 部署 What-if 操作

  • 并置功能。 如果有备用容量,可将应用程序资源和功能并置在单个 Azure 资源上。 例如,多个 Web 应用可以使用单个服务器(应用服务计划),或者单个缓存可以支持多种数据类型。

    示例:参考实现使用单个 Azure Cache for Redis 实例在前端(存储购物车和 MSAL 令牌)和后端(保留持即将开始的音乐会数据)Web 应用中进行会话管理。 它选择最小的 Redis SKU,不仅提供所需的容量,还通过采用多种数据类型来有效利用容量,以控制成本。

卓越运营

卓越运营涵盖了部署应用程序并使其在生产环境中保持运行的运营流程。 有关详细信息,请参阅设计卓越运营的审查清单。 可靠 Web 应用模式为基础结构部署实现基础结构即代码,并监视可观测性。

自动进行部署

使用 CI/CD 管道将更改从源代码管理部署到生产环境。 如果使用 Azure DevOps,则应使用 Azure Pipelines。 如果您使用的是 GitHub,请使用 GitHub 操作。 Azure 支持 ARM 模板 (JSON)、Bicep 和 Terraform,并为每个 Azure 资源提供模板。有关详细信息,请参阅 Bicep、Azure Resource Manager 和 Terraform 模板以及可重复基础结构

示例:参考实现使用 Azure Dev CLI 和基础结构即代码(Bicep 模板)创建 Azure 资源、设置配置并部署所需资源。

配置监视

要监视 Web 应用,请从应用程序代码、基础结构(运行时)以及平台(Azure 资源)收集指标和日志并进行分析。 为体系结构中的每个 Azure 资源添加诊断设置。 每个 Azure 服务都有一组可以捕获的不同日志和指标。 有关详细信息,请参阅监视平台监视应用程序服务

监视基线指标

使用 Azure Application Insights 跟踪基线指标,例如请求吞吐量、平均请求持续时间、错误和依赖项监视。 使用 NuGet 包 Microsoft.ApplicationInsights.AspNetCore 中的 AddApplicationInsightsTelemetry 来启用遥测收集。 有关详细信息,请参阅启用 Application Insights 遥测.NET 中的依赖注入

示例:参考实现使用代码在 Application Insights 中配置基线指标(请参阅以下代码)。

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.AddApplicationInsightsTelemetry(Configuration["App:Api:ApplicationInsights:ConnectionString"]);
   ...
}

根据需要创建自定义遥测

使用 Application Insights 收集自定义遥测,以便更好地了解 Web 应用用户。 创建 TelemetryClient 类的实例,并使用 TelemetryClient 方法创建正确的指标。 将查询转换为 Azure Dashboard 小组件。

示例:参考实现添加指标,帮助运营团队确定 Web 应用是否成功完成事务。 它通过监视客户是否可以下订单来验证 Web 应用是否联机,而不是通过衡量请求数或 CPU 使用率。 参考实现使用 TelemetryClient(通过依赖项注入)和 TrackEvent 方法来收集与购物车活动相关的事件的遥测。 遥测跟踪用户添加、删除和购买的票证(请参阅以下代码)。

  • AddToCart 计算用户将特定票证 (ConcertID) 添加到购物车的次数。
  • RemoveFromCart 记录用户从购物车中删除的票证。
  • CheckoutCart 记录每次用户购买票证的事件。

this.telemetryClient.TrackEvent 计算添加到购物车中的票证。 它提供事件名称 (AddToCart) 并指定包含 concertIdcount 的字典)(请参阅以下代码)。

this.telemetryClient.TrackEvent("AddToCart", new Dictionary<string, string> {
    { "ConcertId", concertId.ToString() },
    { "Count", count.ToString() }
});

有关详细信息,请参阅:

收集基于日志的指标

跟踪基于日志的指标,以便更好地了解基本应用程序运行状况和指标。 可以在 Application Insights 中使用 Kusto 查询语言 (KQL) 查询来查找和整理数据。 更多信息请参阅《基于 Azure Application Insights 日志的指标》和《Application Insights 中基于日志的预先聚合指标》。

启用平台诊断

Azure 的诊断设置可以指定要收集的平台日志和指标及其存储位置。 平台日志为内置日志,可以提供诊断和审核信息。 你可以为大多数 Azure 服务启用平台诊断,但每个服务有其自己的日志类别。 不同的 Azure 服务可以选择不同的日志类别。

  • 为所有受支持的服务启用诊断。 Azure 服务会自动创建平台日志,但不会自动存储日志。 必须为每个服务启用诊断设置,并且应为每个支持诊断的 Azure 服务启用诊断设置。

  • 将诊断发送到与应用程序日志相同的目的地。 启用诊断时,可以选择要收集的日志及其发送目的地。 应将平台日志和应用程序日志发送到相同的目的地,以便关联两个数据集。

性能效率

性能效率是指工作负荷能够以高效的方式扩展以满足用户对它的需求。 有关详细信息,请参阅设计性能效率审查清单。 可靠 Web 应用模式使用缓存端模式来最大程度地减少高需求数据的延迟。

使用缓存端模式

缓存端模式是一种缓存策略,可改进内存中数据管理。 该模式为应用程序分配处理数据请求的责任,并确保缓存与持久性存储(例如数据库)之间的一致性。 当 Web 应用收到数据请求时,会首先搜索缓存。 如果数据缺失,将从数据库检索数据、响应请求并相应地更新缓存。 此方法可缩短响应时间并提高吞吐量,并减少缩放需求。 还通过减少主数据存储上的负载并最大程度地降低服务中断风险来提高服务可用性。

示例:参考实现通过缓存关键数据来提高应用程序效率,例如即将举行的音乐会的信息对门票销售至关重要。 它使用 ASP.NET Core 的分布式内存缓存进行内存中项存储。 当应用程序找到特定的连接字符串时,会自动使用 Azure Cache for Redis。 它还支持没有 Redis 的本地开发环境,以简化设置并降低成本和复杂性。 方法 (AddAzureCacheForRedis) 将应用程序配置为使用 Azure Cache for Redis(请参阅以下代码)。

private void AddAzureCacheForRedis(IServiceCollection services)
{
    if (!string.IsNullOrWhiteSpace(Configuration["App:RedisCache:ConnectionString"]))
    {
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = Configuration["App:RedisCache:ConnectionString"];
        });
    }
    else
    {
        services.AddDistributedMemoryCache();
    }
}

有关详细信息,请参阅 ASP.NET Core 中的分布式缓存AddDistributedMemoryCache 方法

缓存高需求数据

优先缓存最常访问的数据。 确定提高用户参与度和系统性能的关键数据点。 专门针对这些领域实施缓存策略,以提高缓存端模式的有效性,显著减少延迟和数据库负载。 使用 Azure Monitor 跟踪数据库的 CPU、内存和存储。 这些指标可帮助确定是否可以使用较小的数据库 SKU。

示例:参考实现缓存支持即将举行的音乐会的数据。 “即将开始的音乐会”页面创建最多的 SQL 数据库查询,并为每次访问生成一致的输出。 缓存端模式在第一次请求此页后缓存数据,以减少数据库上的负载。 以下代码使用 GetUpcomingConcertsAsync 方法将数据从 SQL 数据库拉取到 Redis 缓存中。 该方法使用最新的音乐会填充缓存。 该方法按时间筛选,对数据进行排序,并将数据返回到控制器以显示结果(请参阅以下代码)。

public async Task<ICollection<Concert>> GetUpcomingConcertsAsync(int count)
{
    IList<Concert>? concerts;
    var concertsJson = await this.cache.GetStringAsync(CacheKeys.UpcomingConcerts);
    if (concertsJson != null)
    {
        // There is cached data. Deserialize the JSON data.
        concerts = JsonSerializer.Deserialize<IList<Concert>>(concertsJson);
    }
    else
    {
        // There's nothing in the cache. Retrieve data from the repository and cache it for one hour.
        concerts = await this.database.Concerts.AsNoTracking()
            .Where(c => c.StartTime > DateTimeOffset.UtcNow && c.IsVisible)
            .OrderBy(c => c.StartTime)
            .Take(count)
            .ToListAsync();
        concertsJson = JsonSerializer.Serialize(concerts);
        var cacheOptions = new DistributedCacheEntryOptions {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
        };
        await this.cache.SetStringAsync(CacheKeys.UpcomingConcerts, concertsJson, cacheOptions);
    }
    return concerts ?? new List<Concert>();
}

使缓存数据保持最新

计划定期缓存更新,以便与最新的数据库更改保持同步。 根据数据波动性和用户需求确定最佳刷新率。 这种做法可确保应用程序使用缓存端模式提供快速访问和最新信息。

示例:参考实现仅缓存数据一小时。 它具有在数据更改时清除缓存键的过程。 CreateConcertAsync 方法清除缓存键(请参阅以下代码)。

public async Task<CreateResult> CreateConcertAsync(Concert newConcert)
{
    database.Add(newConcert);
    await this.database.SaveChangesAsync();
    this.cache.Remove(CacheKeys.UpcomingConcerts);
    return CreateResult.SuccessResult(newConcert.Id);
}

确保数据一致性

实施各种机制以在任何数据库写入操作后立即更新缓存。 使用事件驱动的更新或专用数据管理类来确保缓存一致性。 始终将缓存与数据库修改保持同步是缓存端模式的核心。

示例:参考实现使用 UpdateConcertAsync 方法使缓存中的数据保持一致(请参阅以下代码)。

public async Task<UpdateResult> UpdateConcertAsync(Concert existingConcert), 
{
   database.Update(existingConcert);
   await database.SaveChangesAsync();
   this.cache.Remove(CacheKeys.UpcomingConcerts);
   return UpdateResult.SuccessResult();
}

测试数据库性能

数据库性能会影响应用程序的性能和可伸缩性。 请务必测试数据库性能,以确保其得到优化。 一些关键注意事项包括选择正确的云区域、连接池、缓存端模式和优化查询。

  • 测试网络跃点。 将应用程序移动到云可能会给数据库带来额外的网络跃点和延迟。 应测试新云环境引入的额外跃点。

  • 建立性能基线。 应使用本地性能指标作为初始基线,来比较云中的应用程序性能。

后续步骤

按照 GitHub 存储库中的说明部署参考实现。 使用以下资源详细了解 .NET 应用程序、Web 应用、云最佳实践和迁移。

升级 .NET Framework 应用程序

参考实现部署到运行 Windows 的应用服务,但它可以在 Linux 上运行。 应用服务 Windows 平台使你能够将 .NET Framework Web 应用移动到 Azure,而无需升级到较新的框架版本。 有关 Linux 应用服务计划或添加到最新版本 .NET 的新功能和性能改进的信息,请参阅以下指南。

Azure 上的 Web 应用简介

有关 Azure 上 .NET Web 应用程序的实践介绍,请参阅此部署基本 .NET Web 应用程序的指南

云最佳做法

有关 Azure 采用和体系结构指南,请参阅:

  • 云采用框架。 可以帮助组织准备和执行策略,以便在 Azure 上生成解决方案。
  • 架构良好的框架。 一组指导原则,可用于提升工作负载的质量。

对于需要比可靠 Web 应用模式更高 SLO 的应用程序,请参阅任务关键型工作负载

迁移指南

以下工具和资源可帮助你将本地资源迁移到 Azure。