文章

高可用架构设计总览

高可用架构设计总览

一句话:高可用不是”多加一台机器”,而是从架构层面消除单点、缩短故障恢复时间(RTO)、减少数据丢失(RPO)——让系统在部分组件故障时仍能提供服务。

概述

你的知识库中高可用内容散落在各处:MySQL 主从复制与高可用、Redis 高可用与集群、K8s 多副本、etcd 多节点等。本篇把它们串成一个统一的高可用架构设计框架

高可用核心概念

RTO 与 RPO

graph LR
    T0[故障发生] -->|RTO| T1[服务恢复]
    T0 -->|RPO| T2[数据恢复点]
    
    T0 -.->|数据丢失| T2
    T2 -.->|恢复时长| T1
概念全称含义典型值
RTORecovery Time Objective从故障发生到服务恢复的目标时间15 min / 30 min / 1 h
RPORecovery Point Objective允许的最大数据丢失量(时间维度)0 / 1 min / 5 min / 15 min
MTBFMean Time Between Failures平均故障间隔时间越长越好
MTTRMean Time To Recovery平均恢复时间越短越好
SPOFSingle Point of Failure单点故障必须消除

关系可用性 = MTBF / (MTBF + MTTR)。高可用架构通过拉长 MTBF(冗余+消除单点)和缩短 MTTR(自动故障转移+快速恢复)来提升可用性。

SLO 与 RTO/RPO 的关系

SLO约束
99.9%月度允许 ~43 min 故障 → RTO < 43 min
99.95%月度允许 ~21 min → RTO < 21 min
99.99%月度允许 ~4.3 min → RTO < 4.3 min(需自动切换)
99.999%年度允许 ~5.2 min → RTO < 1 min(需双活)

高可用设计层次

graph TD
    L1[第一层:消除单点] --> L1A[多副本部署]
    L1 --> L1B[跨 AZ 部署]
    L1 --> L1C[跨 Region 部署]
    
    L2[第二层:快速故障转移] --> L2A[健康检查 + 自动切换]
    L2 --> L2B[负载均衡 + 流量摘除]
    L2 --> L2C[DNS failover]
    
    L3[第三层:数据可靠性] --> L3A[多副本复制]
    L3 --> L3B[定期备份 + 异地备份]
    L3 --> L3C[事务日志 + PITR]
    
    L4[第四层:降级与容错] --> L4A[依赖降级]
    L4 --> L4B[熔断/限流]
    L4 --> L4C[优雅降级]
    
    L5[第五层:混沌验证] --> L5A[故障注入]
    L5 --> L5B[红蓝对抗演练]

第一层:消除单点(冗余设计)

冗余模式对比

模式架构RTORPO成本适用场景
主备(Active-Standby)1 主 1 备,备机冷备分钟级取决于同步频率2x中间件/DB
主从(Active-Passive)1 主 1 从,从机热备秒级秒级2xMySQL/Redis
双活(Active-Active)多节点同时服务接近 00Nx无状态服务
多活(Multi-Active)多 Region 同时服务00Nx + 网络全球服务

无状态服务高可用(最简单)

# K8s Deployment 多副本 + PDB
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-service
spec:
  replicas: 4                    # 至少 2 副本
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1          # 滚动更新时最多不可用 1 个
      maxSurge: 1
  template:
    spec:
      affinity:
        podAntiAffinity:         # Pod 反亲和——分散到不同节点
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app: api-service
                topologyKey: kubernetes.io/hostname
      topologySpreadConstraints:  # 跨 AZ 分散
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-service-pdb
spec:
  minAvailable: 2                # 至少保证 2 个 Pod 可用
  selector:
    matchLabels:
      app: api-service

有状态服务高可用

服务高可用方案参考
MySQLMHA/Orchestrator + 主从复制 + MGRMySQL 主从复制与高可用
RedisSentinel/ClusterRedis 高可用与集群方案
etcdRaft 共识 + 3/5 节点etcd 运维详解
Kafka副本 + ISR + Controller
Elasticsearch副本分片 + 跨 AZ

第二层:快速故障转移

健康检查与自动切换

# K8s 探针配置
livenessProbe:          # 存活探针:失败重启 Pod
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 10
  failureThreshold: 3   # 3 次失败才重启

readinessProbe:         # 就绪探针:失败摘除流量
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 1   # 1 次失败就摘除

startupProbe:           # 启动探针:慢启动保护
  httpGet:
    path: /health
    port: 8080
  failureThreshold: 30
  periodSeconds: 10      # 最多等 5 分钟启动

多层故障转移

故障转移层次(从快到慢):

L1: Pod 级(秒级)
  ├── K8s livenessProbe → 重启 Pod
  └── K8s readinessProbe → 摘除流量

L2: 节点级(10-30 秒)
  ├── 节点 NotReady → Pod 迁移
  └── Pod Disruption Budget 保护

L3: AZ 级(分钟级)
  ├── AZ 故障 → 跨 AZ 流量切换
  └── topologySpreadConstraints 保证跨 AZ 分布

L4: Region 级(分钟-小时级)
  ├── Region 故障 → DNS 切换到备 Region
  └── 全局负载均衡(GSLB)

L5: 数据级(取决于 RPO)
  ├── 主从切换
  ├── PITR 恢复
  └── 异地备份恢复

DNS 故障转移

# 基于健康检查的 DNS 故障转移
# 主 Region: cn-beijing
# 备 Region: cn-shanghai

# Route53 / 阿里云 DNS 配置
dns_failover:
  primary:
    region: cn-beijing
    endpoint: api-beijing.example.com
    health_check:
      type: HTTPS
      resource_path: /health
      interval: 10
      failure_threshold: 3
  
  secondary:
    region: cn-shanghai
    endpoint: api-shanghai.example.com
    auto_failback: true      # 主 Region 恢复后自动切回
    failback_delay: 300     # 5 分钟稳定后才切回

第三层:数据可靠性

数据保护层次

L1: 实时复制(RPO ≈ 0)
  ├── 同步复制(MySQL 半同步 / etcd Raft)
  └── 适用于核心数据

L2: 异步复制(RPO = 秒级)
  ├── MySQL 异步 binlog 复制
  ├── Redis 主从异步复制
  └── 适用于准核心数据

L3: 定期备份(RPO = 小时/天级)
  ├── 全量备份(每天)
  ├── 增量备份(每小时)
  └── 适用于非核心数据

L4: 异地备份(RPO = 天级,防 Region 级故障)
  ├── 跨 Region 备份同步
  └── 冷备份归档

MySQL 数据保护示例

# MySQL PITR(Point-in-Time Recovery)流程
# RPO 目标:1 分钟

# 1. 每日全量备份
mysqldump --single-transaction --master-data=2 \
  --all-databases > backup_$(date +%Y%m%d).sql

# 2. binlog 实时复制到异地
# my.cnf 配置
# [mysqld]
# log_bin=mysql-bin
# binlog_format=ROW
# binlog_expire_days=7
# sync_binlog=1

# 3. 恢复流程
#   a. 恢复最近全量备份
#   b. 回放 binlog 到指定时间点
mysqlbinlog --start-datetime="2026-08-03 14:00:00" \
  --stop-datetime="2026-08-03 14:05:00" \
  mysql-bin.000123 | mysql -u root -p

第四层:降级与容错

依赖降级策略

# 降级策略示例
class DegradationManager:
    """服务降级管理器"""
    
    def __init__(self):
        self.degradation_level = "normal"  # normal / partial / minimal
    
    def check_dependencies(self) -> str:
        """检查依赖健康度,决定降级级别"""
        checks = {
            "redis": self._check_redis(),
            "mysql": self._check_mysql(),
            "downstream_api": self._check_downstream(),
            "search_engine": self._check_es(),
        }
        
        failed = [k for k, v in checks.items() if not v]
        
        if "mysql" in failed:
            return "critical"   # 核心依赖挂了,整体降级
        elif "redis" in failed:
            return "partial"    # 缓存挂了,降级到直查 DB + 限流
        elif "search_engine" in failed:
            return "partial"    # 搜索挂了,降级到 DB like 查询
        elif "downstream_api" in failed:
            return "partial"    # 下游挂了,返回兜底数据
        else:
            return "normal"
    
    def apply_degradation(self, level: str):
        if level == "partial":
            # 关闭非核心功能(搜索/推荐/统计)
            self._disable_features(["search", "recommend", "analytics"])
            # 开启限流保护
            self._enable_rate_limit(threshold=0.7)  # 降到 70% 流量
        elif level == "critical":
            # 只保留核心链路
            self._enable_only_core_path()
            # 极限限流
            self._enable_rate_limit(threshold=0.3)

熔断器模式

import time
from functools import wraps

class CircuitBreaker:
    """熔断器:连续失败 N 次后断开,一段时间后半开探测"""
    
    def __init__(self, failure_threshold=5, recovery_timeout=30):
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.state = "closed"  # closed / open / half_open
        self.last_failure_time = None
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if self.state == "open":
                if time.time() - self.last_failure_time > self.recovery_timeout:
                    self.state = "half_open"
                else:
                    raise CircuitBreakerOpen("Circuit breaker is open")
            
            try:
                result = func(*args, **kwargs)
                if self.state == "half_open":
                    self.state = "closed"
                    self.failure_count = 0
                return result
            except Exception as e:
                self.failure_count += 1
                self.last_failure_time = time.time()
                if self.failure_count >= self.failure_threshold:
                    self.state = "open"
                raise
        
        return wrapper

高可用架构成熟度模型

级别特征RTORPO典型架构
L1单机房多副本分钟级分钟级K8s 多副本
L2跨 AZ 部署分钟级秒级多 AZ + 自动故障转移
L3跨 Region 主备分钟级分钟级主备 Region + DNS 切换
L4跨 Region 双活秒级秒级多活 + 全局负载均衡
L5全球多活接近 00单元化部署 + 就近接入

设计 Checklist

## 高可用架构设计 Checklist

### 消除单点
- [ ] 无单点服务(所有服务 >= 2 副本)
- [ ] 无单点中间件(DB/Cache/MQ 有主从/集群)
- [ ] 无单点网络(多 AZ/多网卡)
- [ ] 无单点 DNS(多 DNS 服务商)

### 故障转移
- [ ] 健康检查覆盖所有服务
- [ ] 自动故障转移机制(K8s 探针 + 自动切换)
- [ ] 跨 AZ 流量切换预案
- [ ] 跨 Region DNS 切换预案

### 数据可靠性
- [ ] 核心数据实时复制(RPO ≈ 0)
- [ ] 定期全量 + 增量备份
- [ ] 异地备份
- [ ] 备份恢复演练(至少季度一次)

### 降级容错
- [ ] 依赖降级策略(非核心依赖可降级)
- [ ] 熔断器保护下游
- [ ] 限流保护自身
- [ ] 优雅降级(返回兜底数据而非报错)

### 容量预留
- [ ] 核心服务峰值 + 50% 余量
- [ ] 弹性伸缩配置
- [ ] 大促/活动预扩容预案

常见问题 / 坑点

问题原因解决方案
多副本但同节点Pod 没配反亲和配 podAntiAffinity + topologySpreadConstraints
故障转移太慢探针参数不合理调优 initialDelay/period/failureThreshold
跨 AZ 但跨 Region以为跨 AZ 就够了AZ 故障和 Region 故障概率不同,需分层防护
备份没验证过备份了但没恢复过定期做恢复演练(至少季度一次)
降级策略只在文档里没有自动化执行代码实现降级管理器,自动检测 + 自动降级
双活但数据冲突双写无冲突解决机制用 CRDT / 最后写胜 / 分片分域

关联知识

参考资源

  • Google SRE Book: Things That Go Wrong
  • AWS Well-Architected Framework: Reliability Pillar
  • Martin Kleppmann: Designing Data-Intensive Applications

学习时间

内容日期状态
高可用架构总览2026-08-03完成:RTO/RPO、冗余设计、故障转移、数据可靠性、降级容错

状态

  • RTO/RPO 核心概念
  • 冗余设计模式对比
  • 多层故障转移
  • 数据保护层次
  • 降级与容错策略
  • 成熟度模型
  • 设计 Checklist