想象你是一家火爆餐厅的店长。平日客流平稳时,后厨各司其职,上菜行云流水。可一到节假日,情况就变了:门口排起长队,外卖订单雪崩般涌来。更要命的是,负责炖汤的灶台突然坏了——所有点炖菜的订单都挤在出问题的灶台前,后厨越积越多,最终连其他灶台的厨师也没法干活,整家餐厅陷入瘫痪。 聪明的店长会给餐厅装上三重防护:第一道,给每个关键灶台装一个“保险丝”,出了问题自动断电,让厨师把精力留给还能做的菜;第二道,客流太大时启动“简化菜单”,砍掉做工繁琐的菜,主推几道拿手硬菜;第三道,在门口设置“排队围栏”,控制同时进店的顾客数量,防止挤爆大厅。这三重防护,对应到微服务世界里,就是我们今天要讲的主角:熔断(Circuit Breaker)、降级(Fallback)、限流(Rate Limiting)。 本文将从熔断器状态机、降级策略设计、限流算法等维度,用餐厅的日常故事,带你读懂微服务的三重防护。
熔断降级限流是保障 AI 微服务高可用性的核心技能。掌握这套防护体系,你就能在业务高峰和故障流中稳住系统,成为团队里值得托付的稳定性工程师。
可视化演示
分步展示熔断器状态机(Closed/Open/Half-Open)、限流算法(令牌桶/滑动窗口)与级联协同防护设计,交互切换理解三道防线。
本节配有交互动效(进入视口后自动加载,约 3KB)。
熔断器状态机设计原理 Closed正常放行,错误率超阈值切换至Open 错误率=失败数/总请求数 > 阈值(50%) Open等待冷却后进入Half-Open试探恢复。
熔断基础
餐厅的灶台保险丝,是熔断器最直观的类比。电路里电流过载时,保险丝率先烧断,保护整个电路不被烧毁。微服务里的熔断器也是同一个思路:当某个下游服务(比如商品详情服务)的调用失败率飙升时,熔断器“跳闸”,拦截所有后续请求,让它们快速失败,而不是继续在已经病入膏肓的服务上等待。
为什么要快速失败?想象故障灶台前围满了等待炖菜的顾客,如果每个顾客都傻等二十分钟,整个餐厅的座位就被“等待中的顾客”占满,真正想点其他菜的顾客反而进不来。同理,如果调用方不熔断,大量请求会堆积在下游服务的队列里,最终耗尽调用方的线程资源,引发连锁雪崩——一个服务挂了,拖垮所有依赖它的服务。
熔断器的巧妙之处在于半开试探。保险丝烧断后,电工不会永远不恢复供电,而是过一会儿试探性合闸。熔断器也一样:在断开状态停留一段时间后,会允许少量请求通过,如果这批试探请求成功了,说明服务恢复了,熔断器闭合;如果还是失败,熔断器继续断开,等待下一轮试探。这种设计避免了不健康的服务被瞬间涌入的流量再次击垮。
最后,用餐厅的故事给熔断下一个完整定义:熔断是一种保护调用方的机制,它假设“我不确定下游是否健康,但我要控制我自己不被拖垮”。它不像限流那样控制总量,也不像降级那样准备备选方案,它只管一件事——及时止损。理解了这个定位,后续的状态机和参数设计就顺理成章了。
状态机流转
现在我们把熔断器拆开,看它的内部构造——一个精密的状态机。餐厅的配电箱里,保险丝只有“通”和“断”两种状态,但微服务熔断器有三种:CLOSED(闭合)、OPEN(断开) 和 HALF-OPEN(半开)。
先看闭合态。这是正常运行时的状态,请求像顾客一样自由进出。但熔断器在后台悄悄盯着一个滑动窗口,统计最近一段时间内的调用次数和失败率。这与餐厅店长每隔五分钟统计一次翻台率一样——如果窗口期内失败率超过阈值(比如 50%),熔断器就会“跳闸”,从闭合态转入断开态。
断开态是一个“冷却期”。在这个状态下,所有请求立即返回错误,不真正发起调用。这就是快速失败——与其让请求在三秒钟后超时,不如让它们在 3 毫秒内失败,把宝贵的线程资源留给其他健康服务。断开状态持续一段时间(比如 10 秒)后,熔断器转入半开态。
半开态是一个“试探窗口”。熔断器放行少量请求(比如 5 个),看看下游服务是否恢复了。如果这些试探请求全部成功,说明服务已经健壮,熔断器闭合、恢复正常流量;只要有试探请求失败,熔断器立刻回到断开态,再等一个冷却周期。
用一个滑动窗口的统计公式来精确描述熔断器的判断逻辑:假设窗口周期为 T,窗口内的总请求数为 N,失败请求数为 F,则失败率估算为:
这个状态机的精妙之处在于,它用“冷却—试探—恢复”的节奏,实现了故障的自动感知与自动恢复。回到餐厅比喻:保险丝烧断后等待冷却,然后派一个厨师去试探灶台能否正常工作,能修好就重新开工,修不好继续休息。整套流程无需店长(人工)介入,系统实现了一定程度的自愈。
- 失败率表示下游服务最近一段时间的健康程度,值越高越不健康。当失败率超过配置的阈值(比如 50%)时,熔断器打开。
- 滑动窗口用一个时间窗口(如最近 10 秒)内的数据来评估状态,避免用瞬时数据导致抖动。
超时重试
熔断器解决了“要不要继续调用”的问题,超时和重试则解决“一次调用等多久、失败了要不要再来一次”的问题。回到餐厅:顾客点了一份炖菜,后厨说需要 20 分钟。但如果前一个灶台已经坏了,这 20 分钟很可能白等。聪明的做法是,提前告诉服务员——“如果 5 分钟没上菜,就别等了,顾客不会怪你的”。
这就是超时预算(Timeout Budget)。每个调用都设置一个超时时间,比如 500ms。一旦超过这个时间,调用方就主动放弃,而不是无限期等下去。为什么要设置超时?因为下游服务可能不是宕机,而是“假死”——进程还在,但响应极慢。如果没有超时,所有请求都会堆积在等待队列里,最终耗尽你的线程池,拖垮自己。
再来看重试放大问题。假设下游服务有 1% 的概率超时,你配置了失败后重试 2 次。看起来每次请求的实际失败率会降低,但系统整体负载变成了原来的 3 倍——如果下游服务本来就有问题,重试会放大流量,把它彻底压垮。这就是重试放大效应,也是初学者最容易踩的坑。
正确的做法是退避策略(Backoff):重试时不要立即发起,而是等待一段随机时间。最简单的退避是指数退避:
回到餐厅比喻:超时是“别傻等,先上别的菜”,重试是“让服务员过一会儿再去催一次”,而退避策略是“催了一次没上,就等更久再去催,不要全班服务员挤在传菜口一起催”。超时、重试与熔断器协同工作,构成了对下游调用的一层层保护屏障。
- Base初始等待时间,比如 100ms。
- random随机抖动,防止多个请求在同一时刻重试,形成周期性的流量峰值。
服务降级设计
熔断是“及时止损”,降级是“另辟蹊径”。当上游调用失败时,降级策略给系统一个优雅的“备选方案”,避免用户看到冷冰冰的错误页。这就像餐厅里有人点了招牌葱油饼,但恰好葱用完了,厨师不会直接拒绝顾客,而是推荐“葱油拌面”——虽然不是招牌菜,但顾客还是能吃饱。
降级的核心思想是:优雅降级,有损服务。在大流量冲击或依赖故障时,主动牺牲部分非核心功能或数据精度,保住整体系统的可用性。
自动降级开关是降级设计的第一环。系统实时监控依赖的健康度,当故障触发时自动切换逻辑分支,无需人工介入。这要求每个依赖都要准备好兜底方案,而且兜底方案要足够健壮——如果兜底方案也需要依赖同一个故障服务,那就没意义了。
默认值兜底是最常见的降级策略。比如首页推荐模块调用推荐引擎失败时,可以返回“热门榜单”(比如缓存中的静态数据);下单时调用风控服务超时,可以先放行订单,事后异步补跑风控。这就是用“可用性优于一致性”的原则,换取系统的整体稳定。
降级的维度可以有很多种。从数据角度看,可以降级为缓存数据、默认值或空值;从功能角度看,可以牺牲非核心功能,保留核心功能;从服务质量看,可以降低响应精度或数据刷新频率。举一个具体例子:电商大促时,如果用户画像服务故障,推荐系统可以降级为基于商品热度的通用推荐,而不是报错。
回到餐厅比喻:降级是厨师长在高峰期写好的“应急预案菜单”,并提前把预案存在传菜口。一旦某个食材断供,服务员拿过预案菜单就能兑现“让顾客吃饱”的承诺。降级的本质是在系统还没被压垮之前,提前想好退路,这与熔断的“事后止损”形成互补。
常见限流算法
限流是给系统的“入口”装上一道闸门,控制单位时间内进入系统的请求数量。它不像熔断那样关注下游健康,而是不管下游资源充裕与否,先在入口拦住超标的流量。前面三层防护就好比餐厅的排队围栏——不管大厅里有哪些菜做不出来,先控制进来的人数,防止挤爆。
我们来看四种经典限流算法,从简单到复杂。
固定窗口(Fixed Window)是最朴素的方法:把时间切成一个个固定窗口,比如每秒一个窗口,每个窗口最多允许 100 个请求。它的缺点很直观——窗口切换的边界处可能出现“双倍突发”。比如第 0.9 秒到第 1.1 秒之间,两个窗口各允许 100 个请求,实际瞬时通过了 200 个请求,这就是临界问题。
滑动窗口(Sliding Window)解决了临界问题。它不再使用固定窗口,而是让时间窗口“滑动”,比如当前时间是 1.1 秒,就统计 0.1 秒到 1.1 秒这 1 秒内的请求数。滑动窗口通常用多个细分格子(如 10 个小格子组成 1 秒窗口)来实现逼近滑动效果。
再来看漏桶算法。想象一个底部漏水的水桶,水(请求)可以以任意速度倒入桶中,但桶底的小孔只能以固定速率漏水。漏桶的核心是强制平滑——无论上游流量多猛,出桶的速率始终是固定的。但它的缺点也明显:无法应对突发流量。即使桶还没满,输出速率也被死死限制在恒定值。
令牌桶算法则更灵活。它允许一定程度的突发流量:系统以固定速率往桶里发放令牌,请求必须拿到令牌才能通过,桶中最多存放 N 个令牌(突发上限)。如果一个瞬间来了 100 个请求,只要桶里恰好有 100 个令牌,就能全部通过;而漏桶则无论如何都会把这些请求排队到后面。令牌桶是工业界最常用的算法,因为它兼顾了平均速率限制和突发流量容忍。
用公式表述令牌桶的填充逻辑:
回到餐厅比喻:漏桶是“不管外面排多长队,每次都只放一个人进店”,令牌桶是“每小时放出 50 张餐券,但允许客人提前囤券,高峰时一口气核销”。选哪种算法,取决于你的业务需要——是追求绝对平滑(漏桶),还是允许一定冲刺(令牌桶)。
- Capacity桶的最大容量,决定了允许的最大突发流量。
- Rate令牌补充速率,即系统长期允许的平均请求速率。
- Δt当前请求距离上次补充的时间间隔,通过这个时间差计算应补充的令牌数。
协同配置
最后,我们把三重防护放到一个系统里,看它们如何协同作战。餐厅的店长会这样安排:门口放排队围栏(限流)控制总客流;点餐时说韭菜盒子没了换韭菜饺子(降级);发现炖锅坏了立刻关掉,不让顾客干等(熔断)。三层保护各司其职,却又环环相扣。
在三者协同中,限流是第一道关,在请求入口处挡住超标的流量;降级是第二道关,在单个服务不可用时提供兜底逻辑;熔断是第三道关,在连锁故障发生时切断对故障依赖的调用。三者之间是叠加防护的关系,而非互斥。一个请求可能同时触发限流拒绝和降级兜底。
协同配置的关键在于动态调参。不同业务场景的最佳参数差别很大,参数必须以可配置、可动态调整的方式下发。例如,通过配置中心动态调整熔断阈值、超时时间和限流速率。配置调整后,系统能自动感知并热加载,无需重启服务。这在餐厅里相当于厨房有一个总控面板,店长可以在客流高峰前提前调低限流阈值、缩短超时时间,而不是等到挤爆了再去改流程。
配置一套合理的初始参数后,还需要监控与告警来验证效果。熔断器打开次数、降级发生次数、限流拒绝数,这三大指标是稳定性运营的核心观测对象。当熔断频繁打开时,也许不是依赖服务的问题,而是超时配置太激进;当限流拒绝率过高时,也许触发了保护阈值,需要对容量进行评估扩容。通过这些指标,你可以持续调优参数,形成“监控—调优—再监控”的闭环。
回顾整个故事:限流管住入口,降级守住底线,熔断斩断病根。微服务的稳定性,正是靠这三重防护的默契配合。下次当你设计的服务被流量冲“挂”时,不妨想想这家餐厅——你是否给了它一套足够聪明的防护体系?
AI 应用场景
场景一:大促秒杀系统的流量闸门
阶段:模型推理服务的高并发入口防护
解决的问题:AI 推荐模型作为微服务被大量调用时,如果 QPS 从 1000 飙升到 100000,推理服务会因 CPU、内存耗尽而崩溃,连带拖垮下游的商品服务、用户服务。传统做法是盲目扩容,但成本高且扩容速度跟不上流量峰值。通过限流算法(令牌桶)在入口控住流量,配合降级策略(返回热门商品兜底)、熔断机制(保护下游依赖),系统即使在大促峰值也能保持稳定响应。
具体案例:某电商平台大促时,推荐系统调用量突增 50 倍。团队在 API 网关层配置了令牌桶限流(RPS 上限按容量的 80% 设置),在推荐服务内部配置了熔断器(错误率 > 20% 时打开,冷却 30 秒),并为下游商品服务配置了降级方案(返回缓存的热门商品数据)。大促期间,推荐服务可用性保持在 99.99%,而下游商品服务的负载保持平稳。
场景二:AI 模型推理服务的自动降级
阶段:模型推理阶段的高可用保障
解决的问题:一个在线翻译服务依赖 GPU 推理集群。当 GPU 集群过载或单卡故障时,如果没有降级策略,用户请求会长时间等待直至超时。通过降级策略,系统可以快速返回“翻译服务繁忙,请稍后再试”的提示,或者切换到一个轻量级模型(准确率略低但足够应对紧急请求)。
具体案例:某 AI 写作助手在流量高峰期,核心的大模型推理服务响应时间从 800ms 恶化到 8s。团队配置了超时时间 2s + 熔断器(5 秒窗口内失败率 > 30% 打开)+ 降级方案(切换至 GPT 小模型,响应时间 200ms)。切换后整体功能可用,只是答案质量略有下降,用户无感。
场景三:AI 微服务依赖链路的熔断保护
阶段:AI 服务依赖外部数据服务的调用链路
解决的问题:一个智能客服系统依赖用户画像服务、订单服务、知识库服务三个下游。当知识库服务出现故障时,若没有熔断机制,所有查询请求都会堆积在等待队列中,导致线程池耗尽,最终把整个智能客服系统击垮。通过熔断器 + 降级兜底,知识库故障只影响“知识问答”这一项功能,其余功能不受影响。
具体案例:某金融企业的智能客服接入新的知识库服务后,因数据格式不兼容,知识库接口错误率飙升到 80%。熔断器在 10 秒内打开,智能客服自动降级为“只有常见问题回复”,坐席系统保持可用。避免了一次因下游对接故障导致的客服系统整体瘫痪事故。
Python 演示
# -*- coding: utf-8 -*-import timeimport random class TokenBucket: """令牌桶限流器""" def __init__(self, rate, capacity): self.rate = rate self.capacity = capacity self.tokens = capacity self.last_refill = time.time() def allow(self): now = time.time() self.tokens = min(self.capacity, self.tokens + (now - self.last_refill) * self.rate) self.last_refill = now if self.tokens >= 1: self.tokens -= 1 return True return False class CircuitBreaker: """熔断器""" def __init__(self, fail_threshold=0.5, reopen_timeout=3): self.fail_threshold = fail_threshold self.reopen_timeout = reopen_timeout self.fail_count = 0 self.total_count = 0 self.state = 'CLOSED' self.open_since = 0 def call(self, func): if self.state == 'OPEN': if time.time() - self.open_since >= self.reopen_timeout: self.state = 'HALF_OPEN' else: return '熔断: 快速失败', None try: result = func() self._record(False) if self.state == 'HALF_OPEN': self.state = 'CLOSED' self.fail_count = 0 self.total_count = 0 return '成功', result except Exception as exc: self._record(True) if self.state == 'HALF_OPEN': self.state = 'OPEN' self.open_since = time.time() return '失败', str(exc) def _record(self, failed): if self.state != 'CLOSED': return self.total_count += 1 if failed: self.fail_count += 1 if self.total_count >= 10: rate = self.fail_count / self.total_count if rate >= self.fail_threshold: self.state = 'OPEN' self.open_since = time.time() def caller(): """模拟有故障的下游依赖: 30% 概率抛异常""" if random.random() < 0.3: raise RuntimeError("downstream error") return "ok" def fallback(): """降级方案: 返回兜底数据""" return "fallback data" LIMITER = TokenBucket(rate=5, capacity=10)BREAKER = CircuitBreaker() for i in range(40): if not LIMITER.allow(): print("限流拒绝") continue status, data = BREAKER.call(caller) if status == "失败": print("降级兜底 ->", fallback()) else: print(status, data) time.sleep(0.05)
self.tokens = min(self.capacity, self.tokens + (now - self.last_refill) * self.rate)按时间差补发令牌,但不超过桶容量,实现限流器核心逻辑。if self.state == 'OPEN': return '熔断: 快速失败', None熔断器打开时直接快速失败,不发起真实调用,及时止损。if rate >= self.fail_threshold: self.state = 'OPEN'滑动窗口内失败率超阈值,熔断器从闭合跳转为断开。if self.state == 'HALF_OPEN': self.state = 'CLOSED'半开状态下试探请求成功,熔断器自动恢复闭合。status, data = BREAKER.call(caller)每次调用前,熔断器先行检查当前状态,决定是否放行。if status == "失败": print("降级兜底 ->", fallback())调用失败时降级到兜底数据,保证调用方不因异常而崩溃。
常见误区
误区“熔断和降级都是服务出问题时兜底,不就是同一个东西吗?”
正解它们是两条不同的防线。熔断关注的是“调用还能不能发”——通过状态机快速失败,保护调用方不被拖垮;降级关注的是“拿什么替代”——当调用失败后,用默认值或缓存结果兜底。一个类比是:门店着火(熔断)是切断燃气总闸,防止爆炸;而给顾客开备用菜单(降级)是疏散后安排就餐。实际中,熔断触发后通常会配合降级方案一起使用。
为何常见:两者经常在同一个故障场景中同时发生,工程师看到“熔断降级”连在一起写,就误以为是同一个概念。它们的触发条件、执行位置和关注点都不同。
误区“限流是为了防攻击和流量突增,阈值设置得大一点,宁可多承担一点风险也不要误伤正常用户。”
正解限流的核心目的不是防攻击,而是保护系统本身的容量上限。无论业务多重要,服务能处理的请求量都有物理上限——线程池、数据库连接池、带宽都是有限资源。超过容量上限的请求即使放行,也会在排队中大量超时,连累其他正常请求,最终导致整体服务质量雪崩。正确做法是先做容量压测,再按上限的 70%~80% 设置阈值,留出裕量。
为何常见:对限流的定位理解不到位,把限流等同于“应对恶意的 DDoS 攻击”而不是“保护自身容量的常规手段”,因此总想着放行更多请求。
误区“下游服务慢的时候,把超时时间调大,给下游更多处理时间,成功率不就上来了吗?”
正解超时时间过大,会让调用方线程大量阻塞在等待上,最终耗尽线程池,引发雪崩。一个服务 99% 请求在 200ms 内完成,超时时间设置为 5s,等于允许 1% 的慢请求占用相当于 25 倍正常请求的时间资源。正确的超时设置应参考慢响应分布(P95/P99),而非最大值,同时配合熔断器使用,让超时后的失败请求快速失败。
为何常见:直觉上“长超时 = 更多成功机会”,忽略了系统资源是有限的,一个慢请求占用的资源,可能让多个正常请求无资源可用。
误区“固定窗口那么简单,为什么非要用滑动窗口和令牌桶?”
正解固定窗口有严重的临界问题,窗口切换边界可能出现突发流量,打爆下游。比如每秒限流 100,实际在窗口切换的瞬间可能通过 200 个请求。对于下游的数据库或第三方 API,这种瞬时突发足以导致超时或封禁。滑动窗口通过细粒度格子逼近精确控制,令牌桶则直接解决了“允许突发但控制平均速率”的问题。
为何常见:初学时只看算法表面,没有仔细推演时间边界处的行为。在面试和实际生产中发现落地方案时,才意识到固定窗口的边界缺陷。
误区“限流、熔断、降级各配置各的,各自有一个阈值就够了。”
正解三重防护需要在同一个请求的完整生命周期内协同。比如:限流拒绝了请求,就不该再有熔断的计数;熔断打开后,调用应直接走降级方案,而不是再进入限流排队。配置上要统一考虑,一个典型的防护链路是:网关限流(入口)→ 服务熔断(拦截对下游的调用)→ 降级兜底(失败时返回备选方案)。参数调整要联动,比如调低超时时间后,应观察熔断打开频率是否过高、限流拒绝率是否异常。
为何常见:初学者分模块学习时为每个机制单独设了一套参数,没有从全局视角审视各机制之间的交互关系和依赖顺序。
面试题
Q1. 熔断器从断开状态(OPEN)恢复到闭合状态(CLOSED),中间必须要经过哪个状态?
- A.直接恢复,无需中间状态
- B.半开状态(HALF-OPEN)← 正确答案
- C.限流等待状态
- D.降级服务状态
答案:B。熔断器必须经过半开状态(HALF-OPEN)进行试探性访问,在确认服务恢复后才闭合,避免因一次性放行大量请求导致服务再次被压垮。半开状态是熔断器实现自动恢复的关键设计。
Q2. 熔断器打开(OPEN)后,对请求的处理方式是?
- A.直接转发到下游服务
- B.排队等待重试
- C.快速失败,不发起实际调用← 正确答案
- D.放大请求量试探
答案:C。熔断器打开时,所有请求直接快速失败,不再发起真实调用。这避免了请求继续堆积,保护调用方线程资源不被耗尽,也防止故障服务雪上加霜。
Q3. 以下哪些属于熔断器状态机中的状态?
- A.CLOSED(闭合)← 正确答案
- B.OPEN(断开)← 正确答案
- C.HALF-OPEN(半开)← 正确答案
- D.DELAYED(延迟)
答案:ABC。熔断器状态机由闭合(正常)、断开(故障)、半开(试探)三种状态组成。闭合时流量正常通过,断开时快速失败,半开时放行少量试探请求。DELAYED 不是熔断器状态。
Q4. 某服务设置熔断阈值为 50%(窗口内失败率),窗口内总共 100 个请求,其中失败了 40 个。此时熔断器?
- A.立即打开
- B.处于半开状态
- C.继续闭合← 正确答案
- D.进入降级状态
答案:C。失败率为 40%(40/100),未超过 50% 的阈值,熔断器保持在闭合状态。熔断器只在失败率超出阈值时才打开,阈值的精确计算对误判和漏判都很关键。
Q5. 关于超时与重试的关系,以下哪个说法是正确的?
- A.重试次数越多越好,总能成功
- B.重试可能放大流量,需要配合退避策略← 正确答案
- C.超时时间越长越能提高成功率
- D.重试不需要考虑超时时间
答案:B。无限制重试会放大下游压力,甚至形成重试风暴。合理的做法是设置退避策略,每次重试间隔递增并增加随机抖动,避免所有请求同时重试。超时和重试需要从预算角度统一规划。
Q6. 服务降级策略常见的实施方式有哪些?
- A.返回缓存数据或默认值← 正确答案
- B.异步化非核心流程
- C.完全停止对外服务
- D.关闭非核心功能保留核心功能← 正确答案
答案:AD。降级的本质是“有损但可用”。常见手段是返回缓存或默认兜底数据、牺牲非核心功能保住核心链路。异步化是提升性能的手段而非降级本身;完全停服是降级失败的后果,不是降级策略。
Q7. 固定窗口限流在窗口切换的临界点可能出现什么问题?
- A.请求全部被拒绝
- B.瞬时突发流量突破限流限制← 正确答案
- C.服务自动降级
- D.限流器自动重启
答案:B。固定窗口在边界处,上一个窗口的剩余配额和下一个窗口的完整配额在极短时间内都可以使用,导致瞬时流量达到两倍限流值。滑动窗口通过细分时间格解决了这一问题。
Q8. 令牌桶算法中,若桶容量为 10,当前桶内有 5 个令牌,补充速率为每秒 2 个令牌,距离上次补充已过去 3 秒,此时桶内令牌数为?
- A.10(到达容量上限)← 正确答案
- B.11(超过容量上限)
- C.8(5+2×3-1)
- D.7(5+2×3-2)
答案:A。先计算补充令牌数 2×3=6,加上已有 5 个共 11 个。但因为桶容量上限为 10,取 min(10,11) 得到 10。令牌桶的容量上限决定了最大突发量,补充再多也不会超出容量。
Q9. 漏桶算法与令牌桶算法最核心的区别是什么?
- A.漏桶允许突发流量,令牌桶完全平滑
- B.漏桶强制平滑流量,令牌桶允许一定突发← 正确答案
- C.两者没有区别
- D.漏桶更节省内存
答案:B。漏桶无论上游流量多猛,输出速率恒定不变,强制平滑;令牌桶通过调节桶容量和补充速率,允许不超过容量的一定程度突发,同时限制平均速率。这是两者的本质区别。
Q10. 某电商大促场景中,网关 QPS 峰值达到容量的 3 倍,以下哪些组合策略能有效保证系统稳定?
- A.网关层配置令牌桶限流,控制入口流量← 正确答案
- B.推荐服务配置熔断器,防止依赖故障拖垮自身← 正确答案
- C.无限增加重试次数,保证请求成功
- D.核心服务配置降级预案,依赖故障时返回兜底数据← 正确答案
答案:ABD。正确的防护组合是“网关限流 + 服务熔断 + 降级兜底”三层叠加。限流拦截超量流量,熔断切断故障依赖的调用,降级提供兜底方案。无限重试会放大流量、加剧故障,是错误做法。