高并发系统设计-熔断

一、概述

1.1 什么是熔断

熔断(Circuit Breaker)的核心思想来自电路保险丝:

当电流过大时,保险丝会断开,保护整个电路。

在分布式系统中:

服务A → 服务B → 服务C → 数据库

如果服务C异常:

  • 超时
  • 报错
  • 响应缓慢

那么如果不做控制:

A 等 BB 等 CC 卡住→ 线程全部阻塞→ 请求堆积→ 系统雪崩

熔断的作用就是:

当下游服务异常时,直接停止调用它,快速失败。

1.2 为什么需要熔断

在高并发系统中,最危险的问题不是“服务失败”,而是:

失败被放大并传播

例如:

数据库慢查询
所有请求阻塞
连接池耗尽
Redis压力上升
Gateway超时
全链路崩溃

这就是:

级联故障(Cascade Failure)

1.3 熔断解决的问题

熔断解决三类问题:

1. 防止线程阻塞

避免请求一直等待下游:

请求 → 卡住 → 不释放资源

2.防止错误放大

错误不会扩散到上游系统:

错误服务 → 不再调用

1.4 企业典型场景

场景1:支付服务异常

订单服务 → 支付服务(异常)

不熔断:
→ 一直等待
→ 订单线程堆积

熔断后:
→ 直接返回“支付处理中”

场景2:库存服务不可用

库存服务挂了

熔断:
→ 不再调用库存
→ 返回“库存未知”

场景3:第三方接口超时

例如:

  • 短信平台
  • 邮件服务
  • 地图API

熔断避免拖垮主系统。

二、原理

2.1 熔断的核心思想

熔断本质是一个:

状态机 + 失败统计 + 自动恢复机制

2.2 三种状态模型

熔断器包含三个状态:

        +---------+
        | CLOSED   |
        +---------+
             |
        失败率过高
        +---------+
        | OPEN     |
        +---------+
             |
        冷却时间
        +--------------+
        | HALF-OPEN    |
        +--------------+

2.3 状态解释

1.CLOSED(关闭状态)

正常状态:请求正常通过

此时:

  • 记录成功/失败次数
  • 监控错误率

2.OPEN(熔断状态)

触发条件:失败率 > 阈值

行为:

  • 直接拒绝请求
  • 不再访问下游
  • 快速返回 fallback

3.HALF-OPEN(半开状态)

作用:

用少量请求探测服务是否恢复

如果成功:恢复 CLOSED

如果失败:回到 OPEN

2.4 熔断触发条件

常用触发策略:

1. 失败率

如:失败率 > 50%

2.连续失败次数

如:连续失败 10 次

3. 慢调用

如:响应 > 2s 的请求比例过高

4.超时比例

如:超时率 > 30%

2.5 熔断恢复机制

恢复过程:

OPEN
  ↓(冷却时间)
HALF-OPEN
成功 → CLOSED
失败 → OPEN

三、实现

PHP 简易熔断器实现

class CircuitBreaker
{
    private int $failCount = 0;
    private int $successCount = 0;

    private int $threshold = 5;
    private string $state = 'CLOSED';
    private int $openTime = 0;
    private int $coolDown = 10;

    public function call(callable $callback)
    {
        if ($this->state === 'OPEN') {
            if (time() - $this->openTime < $this->coolDown) {
                throw new Exception("Circuit Open");
            }

            $this->state = 'HALF_OPEN';
        }

        try {
            $result = $callback();

            $this->onSuccess();

            return $result;
        } catch (\Throwable $e) {
            $this->onFailure();

            throw $e;
        }
    }

    private function onSuccess()
    {
        $this->failCount = 0;

        if ($this->state === 'HALF_OPEN') {
            $this->state = 'CLOSED';
        }
    }

    private function onFailure()
    {
        $this->failCount++;

        if ($this->failCount >= $this->threshold) {
            $this->state = 'OPEN';
            $this->openTime = time();
        }
    }
}

Redis 分布式熔断状态存储结构示例

circuit:user-service

{
  state: OPEN,
  fail: 10,
  success: 0,
  open_time: 123456
}