分布式系统设计模式:你真正需要掌握的六种模式

不是所有模式都值得学

分布式系统有几十种设计模式,但真正在日常开发中反复出现的,就这六种。每个都带代码示例,不空谈理论。

模式一:Circuit Breaker(熔断器)

问题:下游服务挂了,你的服务一直在重试,耗尽线程池。

方案:像一个电路保险丝——失败超过阈值就"断开",快速失败。

class CircuitBreaker:
    def __init__(self, fail_threshold=5, timeout=60):
        self.fail_count = 0
        self.state = 'CLOSED'  # CLOSED / OPEN / HALF_OPEN
        self.threshold = fail_threshold
        self.timeout = timeout
        self.last_fail_time = None
    
    def call(self, func, *args):
        if self.state == 'OPEN':
            if time.time() - self.last_fail_time > self.timeout:
                self.state = 'HALF_OPEN'  # 试探性恢复
            else:
                raise Exception('Circuit breaker is OPEN')
        
        try:
            result = func(*args)
            if self.state == 'HALF_OPEN':
                self.state = 'CLOSED'  # 恢复了
                self.fail_count = 0
            return result
        except Exception:
            self.fail_count += 1
            self.last_fail_time = time.time()
            if self.fail_count >= self.threshold:
                self.state = 'OPEN'
            raise

适用场景:任何调用外部服务的场景。几乎所有微服务框架都内置了(Hystrix、Resilience4j、Polly)。

模式二:Bulkhead(舱壁隔离)

问题:一个慢接口拖垮整个线程池。

方案:为不同下游服务分配独立的线程池。

# Java 示例
ThreadPoolExecutor userPool = new ThreadPoolExecutor(10, 10, ...);
ThreadPoolExecutor orderPool = new ThreadPoolExecutor(5, 5, ...);
ThreadPoolExecutor reportPool = new ThreadPoolExecutor(2, 2, ...);

// 即使 reportPool 满了,userPool 和 orderPool 也不受影响

模式三:CQRS(命令查询职责分离)

问题:同一套数据模型既要满足高并发写入,又要满足复杂的聚合查询。

方案:读写分离——写走主库,读走专为查询优化的读模型。

写路径(Command):
POST /orders → MySQL(范式化,快速写入)

读路径(Query):
GET /reports → Elasticsearch(反范式化,快速聚合)

同步:CDC (Change Data Capture) → Debezium → Kafka → ES

关键:接受读写之间的短暂延迟(最终一致性),换性能。

模式四:Saga(分布式事务的务实方案)

问题:一个操作跨多个服务,需要全部成功或全部回滚。

核心思想:每个服务有自己的本地事务 + 补偿操作。

创建订单 Saga:
1. 订单服务:创建订单(状态=CREATED)        ← 补偿:标记为 CANCELLED
2. 库存服务:扣减库存                         ← 补偿:回滚库存
3. 支付服务:扣款                            ← 补偿:退款
4. 订单服务:更新状态(状态=CONFIRMED)

# 以编排(Orchestration)方式实现
class OrderSaga:
    def execute(self, order):
        steps = [
            (self.create_order, self.cancel_order),
            (self.reserve_stock, self.rollback_stock),
            (self.charge_payment, self.refund_payment),
        ]
        executed = []
        for step, compensate in steps:
            try:
                step(order)
                executed.append(compensate)
            except Exception:
                for c in reversed(executed):
                    c(order)
                raise

模式五:Event Sourcing(事件溯源)

问题:需要完整的操作审计日志,而且任何时候都能回溯到历史状态。

方案:不存当前状态,存所有事件。当前状态 = events.reduce(apply)。

# 不存这个:
{ "account": "A", "balance": 100 }

# 存这些事件:
[
  { "type": "AccountCreated", "account": "A" },
  { "type": "Deposited", "amount": 200 },
  { "type": "Withdrawn", "amount": 50 },
  { "type": "Deposited", "amount": 30 },
  { "type": "Withdrawn", "amount": 80 }
]

# 余额 = 200 - 50 + 30 - 80 = 100
# 而且能看到完整的账户变动历史

模式六:Sidecar(边车模式)

问题:每个服务都要集成日志收集、监控埋点、服务发现——重复代码。

方案:把这些横切关注点放到独立的 sidecar 进程中。Service Mesh 就是这个模式的终极应用。

Pod:
├── app-container (你的业务代码)
└── envoy-sidecar (处理流量、TLS、限流、监控)

你的代码只需要发请求到 localhost:15000,剩下的 Envoy 全包了。

模式选择决策树

请求失败率高 → Circuit Breaker
资源隔离需求 → Bulkhead
读写性能矛盾 → CQRS
跨服务事务   → Saga
需要审计回溯 → Event Sourcing
横切关注点多 → Sidecar

记住:模式是用来解决问题的,不是用来套的。没见过的问题不要硬找模式来套,简单的方案永远是更好的方案。