分布式系统的弹性设计

熔断

熔断的目的是防止应用不断尝试可能会执行失败的操作,从而使得应用可以继续执行而不用等待异常情况的修复,或者浪费时间来等待长时间的超时操作。当异常已经修复的时候,应用会再次尝试执行操作。

熔断模式类似于容易失败操作的一种代理,它能够记录和统计最近执行失败的次数,然后决定是否继续执行,或者是立即返回错误。

实现熔断模式需要考虑以下三个状态:

  1. 闭合状态:熔断器会定义一个执行操作失败的计数器,在执行操作连续失败或者高频失败时,计数器数值会自增。如果计数器值大于某个阈值,则熔断器会切换到断开状态,同时熔断器会设置一个计时器,在经过一段时间之后会切换到半开状态;

  2. 断开状态:在断开状态下,应用执行操作会立即返回失败,或者可以在当本地缓存中没有数据时返回失败;

  3. 半开状态:在半开状态下,应用会被允许执行一次或者一些操作。如果这些操作执行成功,熔断器则会切换到闭合状态,同时会重置计数器。如果这些操作继续执行失败,熔断器则会重新切换到断开状态,同时会重置计时器。

限流

限流的目的是通过对并发访问进行限速。一般来说,限流的行为如下:

  1. 把多出来的请求拒绝掉;

  2. 关闭或者降级后端服务;

  3. 把有限资源分配给重要用户;

  4. 使用队列来削去请求高峰;

  5. 通过自动化运维的方式,实现服务的自动化伸缩。

限流的经典实现方式有基于计数器、漏斗算法、令牌桶算法。

计数器

使用计数器来实现限流的算法如下:

  1. 准备执行一个请求时,计数器加一;

  2. 执行完毕一个请求时,计数器减一;

  3. 当计数器值大于某个阈值时,开始限流。

在基于计数器的限流算法中,请求是以「次数」而不是以「频率」来被限制。

漏斗算法

漏斗算法的具体步骤如下:

  1. 用一个队列(在漏斗中接水)来堆积请求;

  2. Processor(从漏斗中出水)从队列中消费请求;

  3. 如果队列满了,则开始限流。

         +-----------+ accept  +-----------+
-------->| | | | | | |-------->| Processor |
         +-----------+         +-----------+
               |
               | rejected
               v
            Discard

在漏斗算法中,请求是以 Processor 最大消费能力的频率来执行的。

令牌桶算法

令牌桶算法的具体步骤如下:

  1. 以恒定的速率产生 token,放入至一个集合(承担令牌桶角色)中;

  2. 准备执行一个请求时,从集合中获取一个 token;

  3. 当集合中没有 token 时,则开始限流。

    +-----------+  add token
    | | | | | | |<-----------
    +-----------+
          ^
get token |
          | accept
          |        +-----------+
----------+------->| Processor |
          |        +-----------+
          | rejected
          v
       Discard

在令牌桶算法中,当令牌桶中有堆积的 token 时,请求可以被允许高频率地执行。

降级

降级的本质是为了解决在资源不足时,系统访问量过大的问题。当资源和访问量出现矛盾时,在资源有限的情况下,为了能够扛住大量的请求,而对系统进行降级操作。

一般来说,系统降级的策略有:

  1. 降低系统对一致性的要求;

  2. 完全停止次要功能,或者限制次要功能流量;

  3. 简化功能,例如只返回页面或者接口的部分信息。

一般来说,控制降级的形式是:

  1. 主动推送:开启系统配置;

  2. 由上游系统驱动:对外 API 的参数。

最后更新于