两区还是三区:Azure 工作负载的区域冗余设计方法

2026-09-10 21 预计阅读时间: 1 分钟
来源: azure.microsoft.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:11 分钟

Azure 可用性区域的设计,不能用一个数字概括整个工作负载。真正需要回答的问题不是“要用几个区域”,而是“每个组件需要跨几个区域,才能承受一个区域失效”。

两区和三区并不是全局二选一。更稳妥的做法是逐个组件分析故障域、恢复目标、数据一致性和服务能力,再决定采用两区、三区,还是直接使用 Azure 服务自身提供的区域冗余。

把工作负载拆成故障边界

一个典型应用通常至少包含入口层、计算层、缓存、消息系统、数据库和存储。它们对区域失效的敏感度并不相同:

  • 无状态 Web 或 API 实例通常可以分布到两个区域,并通过负载均衡器分散流量。
  • 需要持续写入的数据库,除了区域数量,还要考虑复制延迟、故障转移方式和数据丢失目标。
  • 缓存可以接受重建时,区域冗余的要求可能低于主数据库。
  • 消息系统如果依赖严格的顺序、分区或事务语义,增加区域并不一定自动得到更好的结果。
  • 入口和网络组件必须与后端的容灾策略匹配,否则应用仍可能存在单一区域故障点。

这意味着一个工作负载可以采用混合策略:计算层使用两区部署,关键数据服务使用三区或服务托管的区域冗余,非关键缓存则采用更简单的重建方案。

先看服务托管的冗余能力

Azure 中有些服务可以由平台管理区域级复制、故障转移或冗余。只要服务提供的语义满足业务要求,优先使用这种能力通常比自行拼装多个实例更容易运维。

评估时应确认几个问题:

  1. 服务是否在目标区域提供可用性区域支持。
  2. 所选 SKU、部署模式和 API 版本是否支持两区或三区。
  3. 区域失效时,故障转移是自动完成,还是需要人工或应用侧介入。
  4. 复制是同步还是异步,是否存在可接受的数据丢失窗口。
  5. 备份、监控、扩容和升级是否覆盖所有副本。

不要把资源模板中的 zones: ['1', '2', '3'] 当成通用的高可用开关。区域编号、服务能力和 SKU 都可能因区域而异,部署前必须检查目标区域的支持情况。

两区与三区如何做决定

两区设计适合大多数希望承受单一区域失效、同时控制成本和复杂度的无状态组件。它能提供两个独立故障域,但在一个区域失效后,剩余区域需要承担全部流量,因此必须预留容量和验证扩缩容速度。

三区设计适合确实需要第三个独立故障域的组件,例如业务要求在一个区域失效后仍保留更大的容量余量,或者服务本身通过三区复制提供更明确的数据可用性语义。三区通常也意味着更高的实例、网络、存储和运维成本。

可以按下面的顺序判断:

  • 先定义组件必须承受的故障:单实例、可用性区域、区域,还是更大范围的灾难。
  • 再确认 RTO、RPO 和故障转移期间的容量要求。
  • 检查 Azure 服务与 SKU 是否支持目标区域模式。
  • 计算一个区域丢失后剩余容量是否足够。
  • 用故障注入或演练验证 DNS、负载均衡、连接重试、数据复制和告警链路。

如果只是因为“三区看起来更可靠”而增加第三个区域,却没有验证复制语义和业务恢复流程,复杂度可能增加,实际恢复能力却没有同步提升。

一个可改造的 Azure 部署示例

下面的 Bicep 示例展示如何把区域数量作为组件级参数,用于一个虚拟机规模集。它假设已经存在目标子网,适合作为无状态计算层的起点。部署前请根据目标区域和 SKU 检查区域支持,并为生产环境补充负载均衡、托管身份、诊断设置和安全配置。

将内容保存为 main.bicep,把 subnetId 替换为现有子网资源 ID:

param vmssName string = 'api-vmss'
param location string = resourceGroup().location
param subnetId string
param adminUsername string = 'azureuser'
@secure()
param adminPassword string
param zones array = [
  '1'
  '2'
]

resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = {
  name: vmssName
  location: location
  zones: zones
  sku: {
    name: 'Standard_D2s_v5'
    tier: 'Standard'
    capacity: 2
  }
  properties: {
    upgradePolicy: {
      mode: 'Automatic'
    }
    virtualMachineProfile: {
      storageProfile: {
        imageReference: {
          publisher: 'Canonical'
          offer: '0001-com-ubuntu-server-jammy'
          sku: '22_04-lts-gen2'
          version: 'latest'
        }
        osDisk: {
          createOption: 'FromImage'
          caching: 'ReadWrite'
          managedDisk: {
            storageAccountType: 'Premium_LRS'
          }
        }
      }
      osProfile: {
        computerNamePrefix: 'api'
        adminUsername: adminUsername
        adminPassword: adminPassword
      }
      networkProfile: {
        networkInterfaceConfigurations: [
          {
            name: 'primary-nic'
            properties: {
              primary: true
              ipConfigurations: [
                {
                  name: 'primary-ip'
                  properties: {
                    subnet: {
                      id: subnetId
                    }
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }
}

可以先执行预览,再部署:

az deployment group what-if \
  --resource-group rg-app-prod \
  --template-file main.bicep \
  --parameters subnetId='/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Network/virtualNetworks/<vnet>/subnets/<subnet>' \
               adminPassword='<strong-password>' \
               zones='["1","2"]'

az deployment group create \
  --resource-group rg-app-prod \
  --template-file main.bicep \
  --parameters subnetId='/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Network/virtualNetworks/<vnet>/subnets/<subnet>' \
               adminPassword='<strong-password>' \
               zones='["1","2"]'

若这个组件确实需要三区,可以把参数改为 zones='["1","2","3"]',但这只是部署层面的变化。应用仍需要确认负载均衡策略、实例容量、连接重试和故障后的流量分配都能正常工作。生产环境也不应在命令行直接传递密码,示例中的密码参数应改为 Key Vault、CI/CD secret 或其他安全注入方式。

在选择区域之前,可以用 Azure CLI 查看目标区域的可用 SKU 和区域信息:

az vm list-skus \
  --location eastus \
  --resource-type virtualMachines \
  --query 'sort_by([].{name:name, zones:locationInfo[0].zones}, &name)' \
  --output table

这个查询只能帮助发现计算资源能力,不能替代具体 Azure 服务的功能文档和配额检查。数据库、存储、网络入口等组件需要分别验证。

落地时保留一张组件决策表

设计评审可以为每个组件记录以下内容:

组件 失效目标 区域模式 复制语义 单区失效后的容量 故障转移方式
API 计算层 丢失一个区域 两区 无状态 由剩余实例承载 负载均衡器
主数据库 丢失一个区域 由服务能力决定 需确认同步或异步 需满足写入与读取目标 自动或人工
缓存 可重建 两区或单区重建 非关键 允许降级 应用重建
消息系统 区域失效与积压 按分区和顺序要求决定 需验证顺序与重复投递 需保留处理能力 服务或应用处理

这张表能把“用了几个区域”的讨论转化为可验证的工程决策,也能暴露隐藏的单点:单区域密钥服务、单区域监控、固定区域的连接字符串,或者只在一个区域运行的运维入口。

采用建议

把区域冗余视为组件级设计参数,而不是工作负载的统一标签。优先使用 Azure 服务托管的区域冗余;对无状态计算层,两区通常是控制成本和复杂度的合理起点;只有在容量、数据可用性或服务语义确实需要时,才引入三区。

上线前至少完成以下检查:

  • 每个关键组件都写明了单区域失效后的行为。
  • 所有选定 SKU 和目标区域都确认支持对应区域模式。
  • 剩余区域有足够容量,且扩容配额已经验证。
  • RTO、RPO、复制延迟和故障转移责任边界明确。
  • 演练覆盖入口、应用、数据、依赖服务和监控告警,而不只是计算实例。

好的区域设计不是把数字做大,而是让每个组件拥有与业务风险相匹配的故障域。


相关推荐