# 如何保证系统的高可用?

# 限流(把好入口)
限流是指在一段时间内,限制系统的输入/输出流量,以达到保护系统的目的。如果流量超过设定阈值,则采取拒绝、排队或降级等策略
# 限流算法
# 固定窗口计数器算法
这是最简单的限流算法。它将时间划分为固定的周期(窗口),并在每个周期内限制请求的数量。
原理:设定一个单位时间(如 1 分钟)和一个最大请求量(如 100 次)。当一个窗口开始时,计数器清零,每来一个请求计数器加 1。如果计数器超过 100,则拒绝后续请求。等到下一个 1 分钟开始,计数器再次清零。
缺点:存在临界突刺(临界窗口问题)。如果 100 个请求集中在第一分钟的最后 1 秒,另外 100 个请求集中在第二分钟的开始 1 秒,系统会在短短 2 秒内承受 200 个请求,瞬间并发量翻倍,可能导致系统崩溃。
适用场景:对流量精度要求不高、实现简单的场景。
# 滑动窗口计数器算法
为了解决固定窗口的“临界突刺”问题,滑动窗口算法应运而生。它是微服务网关(如 Sentinel)常用的限流方式。
原理:将时间窗口切分得更细(例如把 1 分钟分为 6 个 10 秒的小格子)。随着时间的推移,窗口像平滑滑块一样向右移动。每次有请求进来时,计算当前时间点往前推 1 分钟内所有小格子的请求总数,如果超限则拒绝。
优点:完美解决了固定窗口的临界问题,窗口划分越细,限流越平滑。
缺点:需要存储更多的数据(每个小格子的计数),内存开销和计算成本比固定窗口高。
# 漏桶算法

漏桶算法强行限制了数据的输出速率,主要用于流量整形。
原理:可以想象一个底部有小孔的桶。水(请求)可以以任意速率流入桶中,但水(请求)只能以恒定的速率从小孔漏出,交给业务系统处理。如果流入的水量超过了桶的容量,多余的水就会直接溢出(请求被拒绝)。
优点:能保证系统接收到的流量绝对平滑,完全消除突发流量。
缺点:缺乏灵活性。如果系统本身有应对突发流量的能力,漏桶算法也会强行让请求排队,导致系统资源利用率不高,无法处理突发的高并发。
# 令牌桶算法

令牌桶算法是目前互联网大厂最常用的限流算法(如 Guava 的 RateLimiter )。它不仅能限流,还能应对一定程度的突发流量。
原理:系统有一个存放令牌的桶,以恒定的速率往桶里放入令牌,桶满时令牌溢出。当请求到来时,必须先从桶里获取一个令牌,拿到令牌才能通过,拿不到则被拒绝。
优点:当没有突发流量时,桶内会积攒一定量的令牌。一旦突发流量到来,请求可以瞬间拿走桶里的所有令牌,这意味着它允许短时间内的突发高并发,之后又会恢复到恒定速率。
缺点:实现相对漏桶稍微复杂一些,需要维护令牌数量。
# 技术实现方案
| 层级 | 方案 |
|---|---|
| 网关层限流 | 在 Nginx、Spring Cloud Gateway、Kong 等网关处统一限制。Nginx 原生提供了基于漏桶算法的 limit_req 模块 |
| 单机限流 | Guava 的 RateLimiter(基于令牌桶) Resilience4j 的 AtomicRateLimiter (基于令牌桶) |
| 分布式限流 | Redisson 的 RRateLimiter(基于令牌桶结合滑动窗口的思想实现的) |
# 降级(弃车保帅的艺术)
降级是指在系统由于高并发或故障导致资源不足时,主动屏蔽/关停一部分非核心功能,将宝贵的资源留给核心业务
降级通常与限流、熔断配合使用(作为限流被拦截后、或者熔断打开后的后备方案),也可以人工主动触发
按触发时机分类
自动降级:当触发限流、熔断、网络超时、资源异常(如线程池满)时,代码自动捕捉异常并执行预设的 Fallback 方法(例如:返回内存缓存数据、返回空列表、或者返回友好提示“系统繁忙,请稍后再试”)。
人工降级:在双十一等大促前,通过配置中心(如 Nacos、Apollo)下发开关,主动关闭非核心业务(如暂停历史订单查询、暂停写评论功能、关闭某些推荐算法)。
# 熔断(防止级联雪崩)
熔断机制借鉴了电网中的“保险丝”。当某个下游服务由于网络故障、数据库死锁等原因出现高延迟或大量报错时,上游服务继续调用它只会导致线程积压,最终引发雪崩效应。熔断的目的就是及时切断故障调用
# 状态机模型
熔断器内部维护了一个状态机,包含三个状态:

Closed(关闭状态):正常状态。所有请求都放行。熔断器会统计这一期间的错误率(或慢调用比例),如果达到设定阈值,则转换为 Open 状态。
Open(打开状态):熔断状态。所有请求直接被拦截,不再调用下游服务,而是直接触发降级逻辑(Fallback)。同时开启一个时间窗口(如 5 秒)。
Half-Open(半开状态):时间窗口到期后,熔断器进入半开状态,允许少量请求通过去尝试调用下游服务:
如果这些请求成功,说明下游服务已恢复,熔断器回到 Closed 状态。
如果这些请求依然失败,说明服务未恢复,熔断器重新回到 Open 状态,并重新计时。
# 关键配置项
| 配置项 | 作用 |
|---|---|
| 滑动窗口大小 | 统计过去多少个请求或多少秒内的数据。 |
| 错误率/慢调用比例阈值 | 如错误率达到 50%,或者耗时超过 2 秒的慢调用比例达到 40% |
| 最小请求数 | 在滑动窗口内,必须至少有多少个请求才会触发熔断计算(防止样本太少导致误判) |
# 技术方案实现
| 框架 | 介绍 |
|---|---|
| Resilience4j | 基于 Java 8 函数式编程 |
| Sentinel | 支持熔断降级,可配置慢调用比例或异常比例 |
| Hystrix | 已停止维护,不推荐新项目,曾经的标杆 |