Azure Kubernetes 服务 (AKS)的有状态工作负荷升级模式

注释

本文提及了术语 slave(副本),这是 Microsoft 已不再使用的术语。 从 Redis 软件中删除术语后,我们将将其从本文中删除。

使用这些模式通过Azure Kubernetes 服务 (AKS)节点池滚动升级来协调数据库可用性。

本文中的过程是规划框架,而不是可用性或数据持续性保证。 结果取决于数据库拓扑、复制模式、存储、操作员、中断设置、客户端重试行为和工作负荷。 在具有代表性的环境中排练完整的过程,并衡量它是否符合恢复时间目标(RTO)和恢复点目标(RPO)。

本文中介绍的数据库升级模式

本文为具有有状态工作负荷的 AKS 群集提供特定于数据库的升级模式,包括:

  • PostgreSQL 受控切换。
  • Redis 群集副本优先滚动升级。
  • MongoDB 副本集辅助优先滚动升级。
  • 安全响应的紧急升级清单。
  • 验证和回滚规划。

与标准 AKS 节点池升级不同,这些模式使用 Kubernetes 节点替换协调数据库复制检查和角色更改。 数据库和 AKS 管理员可以使用这些模式。 请使用文档中说明的切换操作或升级操作,适用于管理您的部署的数据库 Operator。 不要将这些模式替换为特定于操作员的说明。

有关详细信息,请参阅以下相关文章:


若要快速开始,请选择与您已部署的产品和拓扑对应的模板:

选择数据库升级模式

数据库类型 升级模式 可用性注意事项 最适合
PostgreSQL 受控切换 在连接耗尽和切换期间,写入会暂停。 测量您环境中的时间间隔。 支持故障转移机制的主和流式备用部署
Redis 群集 副本优先滚动升级 客户端可能会在故障转移期间收到暂时性错误或重定向。 Redis 群集使用异步复制。 每个主节点都配有一个副本节点的 Redis 集群部署
MongoDB 辅助优先滚动升级 从主节点降级开始,到选出新的主节点为止,写入会失败。 具有三个或更多成员且包含可选举次要成员的副本集

紧急升级清单

如果需要加快升级以解决安全问题,请不要跳过数据库运行状况和恢复检查。

  1. 验证工作负载和 AKS 升级先决条件:

    # Verify the database pods and their node placement.
    kubectl get pods -l tier=database -o wide
    
    # Confirm that the latest backup job completed.
    kubectl get job backup-job -o jsonpath='{.status.completionTime}'
    

    此外,使用数据库或操作员支持的命令来验证复制运行状况。 在隔离环境中还原最新备份,并确认客户端在出现瞬时连接错误和选举错误时会重试。

  2. 仅选择与产品和拓扑匹配的模式:

    对于其他数据库产品,请遵循该产品或其 Kubernetes 操作员的升级指南。

  3. 使用安全网运行:

    • 务必预先测试回滚流程。
    • 在升级期间监视应用程序指标。
    • 使数据库团队保持备用状态。
    • 如果复制状态、法定人数状态、槽位覆盖情况或应用程序健康状况出现恶化,请停止升级。

PostgreSQL 受控切换

对于采用流复制备用库的 PostgreSQL 主库,请使用此受控切换方案。 这些示例展示的是健康检查,但用于提升、隔离以及让成员重新加入的命令取决于您的 PostgreSQL Operator 或高可用性实现。

Important

在应用程序写入已暂停、候选节点已追平,以及高可用性机制能够隔离或重新配置原主库之前,不要将备用节点提升为主库。 在旧主库仍接受写入时将备用库提升为主库,可能会导致数据库时间线出现分叉。

先决条件

  • 使用支持的 PostgreSQL 版本和支持的操作员或高可用性实现。
  • 将成员分布在不同的故障域中。 为部署配置 Pod 中断预算和拓扑分散约束。
  • 通过在隔离环境中还原备份来验证最近的备份。
  • 确认应用程序在主节点发生变更后重新连接。
  • 在开始 AKS 升级之前,先记录好针对操作人员的、用于执行切换、回滚和重新加入的命令。

步骤 1:验证复制拓扑

对当前主数据库运行以下查询:

kubectl exec <current-primary-pod> -- psql -X -c "
SELECT application_name, state, sync_state, write_lsn, flush_lsn, replay_lsn
FROM pg_stat_replication;"

目标切换候选项必须处于 streaming 状态。 如果您的 RPO 要求同步复制,还要验证候选对象是否具备您的配置所需的预期 sync_state

在预期的备用服务器上运行以下查询:

kubectl exec <candidate-standby-pod> -- psql -X -c "
SELECT pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();"

确认 pg_is_in_recovery() 返回 true,并确认接收位置和重播位置满足您测试的切换阈值。 PostgreSQL 流式复制默认是异步的,因此,仅凭 Pod 处于就绪状态,并不能说明备库已经追上主库状态。

步骤 2:暂停写入并切换主节点

如果所有应用程序流量通过 PgBouncer 传递,请连接到 PgBouncer 管理数据库并暂停应用程序数据库:

kubectl exec <pgbouncer-pod> -- psql -p 6432 -U <admin-user> pgbouncer -c "PAUSE app_db;"

PAUSE 根据配置的连接池模式等待服务器连接被释放。 在依赖这一控制措施之前,请先确认应用程序的写入操作不会绕过 PgBouncer。

暂停写入后,使用操作员或高可用性实现完成这些操作:

  1. 重新检查候选人的 WAL 接收和重播位置。
  2. 运行支持的切换操作。
  3. 验证是否存在一个可写主数据库。
  4. 验证以前的主数据库是否已隔离或重新配置为备用服务器。
  5. 验证写入服务或端点是否解析到新的主节点。

仅在这些检查全部通过后再恢复运行 PgBouncer:

kubectl exec <pgbouncer-pod> -- psql -p 6432 -U <admin-user> pgbouncer -c "RESUME app_db;"

步骤 3:验证切换

# Verify the new primary is writable and no longer in recovery.
kubectl exec <new-primary-pod> -- psql -X -c "SELECT pg_is_in_recovery();"

# Verify all expected standbys stream from the new primary.
kubectl exec <new-primary-pod> -- psql -X -c "
SELECT application_name, state, sync_state, replay_lsn
FROM pg_stat_replication;"

测试应用程序的读取、写入、事务处理和重新连接行为。 在继续之前,请将写入不可用的持续时间和复制结果与您的 RTO 和 RPO 进行比较。

可选的同步复制配置

同步复制可以降低已确认事务的 RPO,但也会增加提交延迟;如果所需的备用节点不可用,还会降低写入可用性。 以下示例会等待任意两个已命名且直接连接的备用服务器重放每个已提交的事务:

# Use synchronous replication with multiple standbys
# postgresql.conf
synchronous_standby_names = 'ANY 2 (standby1, standby2, standby3)'
synchronous_commit = 'remote_apply'

根据测得的延迟、故障域放置和持久性要求,选择 synchronous_standby_namessynchronous_commit。 此配置不保证特定的切换持续时间。

成功验证

若要验证进度,请使用以下清单:

  • 新的主数据库接受读取和写入。
  • 所有副本的复制状态均正常。
  • 应用程序自动重新连接。
  • 数据完整性和应用程序一致性检查通过。
  • 备份和还原测试在新的主数据库上通过。

升级 AKS 节点池

az aks nodepool upgrade 操作会升级整个节点池。 AKS 增加了激增容量、封锁和清空旧节点,重新映像这些节点,并根据节点池升级设置重复此过程。 不要对每个节点运行一次命令,或在托管操作之前手动清空节点。

  1. 列出群集支持的升级目标:

    az aks get-upgrades \
       --resource-group <resource-group-name> \
       --name <cluster-name> \
       --output table
    
  2. 确认控制平面已位于所选目标版本。 根据测试的工作负荷行为、配额和可用子网地址配置节点池的滚动升级设置。 以下示例使用建议的生产 maxSurge 值:

    az aks nodepool update \
       --resource-group <resource-group-name> \
       --cluster-name <cluster-name> \
       --name <node-pool-name> \
       --max-surge 33% \
       --drain-timeout <minutes> \
       --node-soak-duration <minutes>
    
  3. 使用 az aks get-upgrades 返回的目标,对节点池启动一次托管升级:

    az aks nodepool upgrade \
       --resource-group <resource-group-name> \
       --cluster-name <cluster-name> \
       --name <node-pool-name> \
       --kubernetes-version <target-version>
    
  4. 在整个操作中监视 AKS 升级事件和数据库运行状况:

    kubectl events --all-namespaces
    kubectl get pods -l app=postgres -o wide --watch
    

    监视可观测系统中的复制、数据库可用性、应用程序错误、延迟和存储运行状况。 如果 Pod 中断预算阻止排水,请更正工作负荷可用性问题,而不是绕过预算。

验证和恢复

托管升级完成后,验证节点版本、PostgreSQL 拓扑和应用程序行为:

kubectl get nodes
kubectl get pods -l app=postgres -o wide
kubectl exec <current-primary-pod> -- psql -X -c "
SELECT application_name, state, sync_state, replay_lsn
FROM pg_stat_replication;"

AKS 不支持将群集或节点池降级到早期 Kubernetes 版本。 如果数据库运行不正常,请停止应用程序写入并使用数据库操作员支持的恢复或切换过程。 请勿将写入重定向到以前的 PostgreSQL 主数据库,除非它安全地重新加入当前时间线,并由高可用性机制提升。 如果 Kubernetes 升级导致无法恢复的兼容性问题,请将工作负荷移动到测试的群集或节点池,并根据恢复计划还原或复制数据来还原服务。


Redis 集群副本优先滚动升级

将此模式用于至少具有三个主节点且每个主节点至少具有一个副本节点的 Redis 集群。 文档中说明的 Redis 集群节点升级顺序是:先升级副本节点,手动将每个主节点故障转移到一个已升级的副本节点,然后再升级被降级的原主节点。 Redis 群集可以在拓扑更改期间返回暂时性错误或重定向。 由于 Redis 群集使用异步复制,因此可能会丢失确认的写入。 在升级之前验证客户端重试行为和可接受的 RPO。

注释

如果 Redis 操作员管理群集,请使用其记录的滚动升级工作流。 请勿将手动群集命令与活动操作员合并,除非其文档指示你这样做。

步骤 1:记录并验证拓扑

kubectl exec <redis-pod> -- redis-cli CLUSTER NODES
kubectl exec <redis-pod> -- redis-cli --cluster check 127.0.0.1:6379

记录每个节点 ID、角色、主节点到副本节点的分配关系以及哈希槽范围。 除非 16,384 个槽位都已覆盖、每个主节点在不同的故障域中都有一个健康的副本节点,并且集群报告为 cluster_state:ok,否则不要继续。

步骤 2:升级副本

对于每个副本,一次一个:

  1. 使用操作员或工作负荷部署机制在升级后的 AKS 容量上替换或重启副本。
  2. 等待 Pod 准备就绪,并等待复制追上进度。
  3. CLUSTER NODES 确认它是否仍分配给预期的主数据库。

对于保留 Redis 节点标识的 Pod 重启,不要运行 CLUSTER FORGET。 如果替换节点具有新的节点标识符,请将 redis-cli --cluster add-node--cluster-slave--cluster-master-id 配合使用,将其添加为目标主节点的副本。 等待新副本出现在群集拓扑中。

kubectl exec <existing-redis-pod> -- redis-cli --cluster add-node \
   <new-replica-ip>:6379 127.0.0.1:6379 \
   --cluster-slave \
   --cluster-master-id <primary-node-id>

步骤 3:故障转移和升级主数据库

对于每个主数据库,一次一个:

  1. 选择该主副本的已升级且已同步的副本。

  2. CLUSTER FAILOVER 在要升级的副本上运行,而不是在当前主副本上运行:

    kubectl exec <candidate-replica-pod> -- redis-cli CLUSTER FAILOVER
    
  3. 轮询 ROLEINFO REPLICATIONCLUSTER NODES,直到候选节点成为主节点,并且原主节点成为其副本节点。 响应 OK 仅表示 Redis 接受故障转移请求。

  4. 在升级后的 AKS 容量上替换或重启已降级的原主节点。

  5. 等待它作为捕获副本返回,然后再移动到下一个主副本。

在计划内升级期间,请勿使用 CLUSTER FAILOVER FORCETAKEOVER。 这些选项绕过正常协调,需要单独的故障恢复过程。

步骤 4:验证 Redis 群集

kubectl exec <redis-pod> -- redis-cli CLUSTER INFO
kubectl exec <redis-pod> -- redis-cli CLUSTER NODES
kubectl exec <redis-pod> -- redis-cli --cluster check 127.0.0.1:6379

检查槽位覆盖情况、主节点到副本节点的分配关系、复制健康状况、应用程序的读写情况、重定向处理情况以及观测到的 RPO。


MongoDB 副本集辅助优先滚动升级

将此模式用于具有三个或更多成员且包含可参与选举的辅助节点的 MongoDB 副本集。 在主节点降级和选举期间,写操作会失败,直到选出新的主节点。 应用程序必须根据 MongoDB 驱动程序指南重试符合条件的写入和暂时性事务。

注释

如果 MongoDB 操作员管理副本集,请使用其记录的滚动升级工作流和就绪情况检查。

步骤 1:验证副本集

kubectl exec <mongodb-pod> -- mongosh --quiet --eval "rs.status()"

确认所有预期成员都正常,识别当前主数据库,并验证是否捕获了至少一个可选择的辅助数据库。 此外,还应通过测试恢复来验证最新备份。

步骤 2:升级辅助节点

对于每个辅助数据库,一次一个:

  1. 使用操作员或工作负荷部署机制替换或重启升级后的 AKS 容量上的成员。

  2. 等待 Pod 准备就绪。

  3. 在更新另一个成员之前,请确认该成员已恢复到 SECONDARY 状态并完成追赶。

    kubectl exec <mongodb-pod> -- mongosh --quiet --eval \
       "rs.status().members.map(member => ({name: member.name, state: member.stateStr, optime: member.optimeDate}))"
    

步骤 3:将主节点降级

仅对当前主节点运行 rs.stepDown()。 第一个参数指定无法重新选择前主要副本的时长。 第二个参数指定可选辅助副本必须赶上多长时间。 根据经测试的选举行为选择相应的值。

kubectl exec <current-primary-pod> -- mongosh --quiet --eval "rs.stepDown(60, 30)"

当主节点降级时,该命令可能会导致连接断开或返回错误。 轮询另一个成员的副本集状态,直到选择一个新主数据库:

kubectl exec <mongodb-pod> -- mongosh --quiet --eval \
   "rs.status().members.map(member => ({name: member.name, state: member.stateStr}))"

如果在设定的时间内,没有可选举的辅助节点追上,主节点将不会退位。 重试前先解决复制运行状况问题。 不要在计划升级期间强制降级。

步骤 4:升级并验证以前的主数据库

在升级后的 AKS 容量上替换或重启以前的主数据库。 等待它作为正常的辅助数据库返回,然后验证:

  • 恰好有一个成员是 PRIMARY
  • 所有其他承载数据的成员都 SECONDARY 并且已同步。
  • 应用程序读取、写入、可重试写入和事务的行为与预期相同。
  • 测得的选举间隔满足应用的 RTO 要求。
  • 备份和还原检查通过。