简单学习 --> 限流和熔断

限流

限制请求流量,防系统被冲垮

类比:景区门口限流,一次只放一批人进。

  • 作用:挡住突发海量请求,保护服务不卡死
  • 常见方式:按 QPS、并发数、IP 拦截多余请求

限流简单实现

  1. 基于 SlowAPI 实现接口限流,

from slowapi import Limiter

limiter = Limiter(key_func=get_remote_address)

@app.post("/workflow/start")

@limiter.limit("10/minute") # 每分钟最多10次

async def start_workflow():

pass

熔断

下游崩了就直接断路,不再调用

类比:家里跳闸,短路直接断电,避免起火。

    • 触发:下游频繁超时、报错率飙升
    • 行为:直接拒绝调用,快速返回兜底结果
    • 恢复:隔段时间试探,好转再慢慢恢复调用

熔断简单实现

class ContentService:

熔断器装饰器:连续失败5次触发熔断,熔断冷却时长30秒

@circuit_breaker(fail_max=5, reset_timeout=30)

async def _call_llm(self, prompt: str):

"""真正的LLM调用,受熔断器保护"""

发起异步大模型请求,属于易出错的第三方调用

return await self.llm.ainvoke(prompt)

async def generate_article(self, topic: str):

"""对外暴露的方法,永远不会失败,对外统一稳定入口"""

try:

优先执行正常业务逻辑,调用大模型生成内容

return await self._call_llm(topic)

except CircuitBreakerOpen:

捕获熔断异常,此时不再请求故障服务

logger.warning(f"LLM熔断中,返回降级结果")

切换兜底降级策略,保障接口正常响应

return self._get_fallback(topic)

def _get_fallback(self, topic: str):

"""降级兜底方案,服务异常时返回友好占位数据"""

return {

"title": f"关于{topic}的精彩内容",

"content": "内容生成服务正在维护中,请稍后再试。",

"is_degraded": True # 标记当前为降级返回结果

}

熔断流程

用户请求 generate_article()

尝试调用 _call_llm() ← 被 @circuit_breaker 保护

正常 → 返回文章

失败 → 累计失败次数

失败达到 5 次 → 熔断器【打开】

接下来 30 秒内,直接抛出 CircuitBreakerOpen

代码捕获异常 → 走降级 _get_fallback()

返回友好提示,不崩溃、不雪崩

错误边界和降级策略

请求1 ──▶ 尝试主服务 ──▶ 失败(等了10秒) ──▶ 走备用 ──▶ 失败计数=1

请求2 ──▶ 尝试主服务 ──▶ 失败(等了10秒) ──▶ 走备用 ──▶ 失败计数=2

请求3 ──▶ 尝试主服务 ──▶ 失败(等了10秒) ──▶ 走备用 ──▶ 失败计数=3 ──▶ 触发熔断!

────────────────────────────────────────────────────────────────

请求4 ──▶ 熔断器拦截 ──▶ 直接走备用(0秒)

请求5 ──▶ 熔断器拦截 ──▶ 直接走备用(0秒)

请求6 ──▶ 熔断器拦截 ──▶ 直接走备用(0秒)

...

30秒内都不尝试主服务

────────────────────────────────────────────────────────────────

30秒后 ──▶ 半开状态 ──▶ 放一个请求试试 ──▶ 成功了!──▶ 恢复正常

熔断降级策略和普通降级区别

┌────────────────────────────────────────────────────────────────┐

│ │

│ 【简单降级】 │

│ │

│ 请求 ──▶ 主服务(每次都试) ──▶ 失败 ──▶ 备用服务 │

│ │ │

│ │ 超时10秒 │

│ ▼ │

│ 用户等了10秒才拿到结果 │

│ │

│ 问题:主服务挂了,每个用户都要等10秒 │

│ │

├────────────────────────────────────────────────────────────────┤

│ │

│ 【熔断降级】 │

│ │

│ 请求 ──▶ 熔断器检查 ──▶ 开着 ──▶ 直接备用服务 │

│ │ │

│ │ 0秒 │

│ ▼ │

│ 用户秒拿到结果 │

│ │

│ 好处:快速失败,不浪费时间 │

│ │

└────────────────────────────────────────────────────────────────┘

兜底方案简单实现

async def generate_content_with_fallback(topic: str):

try:

return await llm_primary.invoke(topic) # 主模型

except Exception:

logger.warning("Primary LLM failed, fallback to secondary")

return await llm_secondary.invoke(topic) # 备用模型

except Exception:

return get_cached_template(topic) # 兜底模板

熔断和限流的区别

用户请求 generate_article()

尝试调用 _call_llm() ← 被 @circuit_breaker 保护

正常 → 返回文章

失败 → 累计失败次数

失败达到 5 次 → 熔断器【打开】

接下来 30 秒内,直接抛出 CircuitBreakerOpen

代码捕获异常 → 走降级 _get_fallback()

返回友好提示,不崩溃、不雪崩

消息队列限流

消息队列 MQ,是限流的常用解决方案,同时还能削峰、解耦、异步缓冲

核心作用
  1. 削峰限流

    突发海量请求先存入队列,消费端按固定速率慢慢处理,不会瞬间压垮业务 / LLM 服务,把瞬时高峰流量拉平。

  2. 和原有熔断降级区别

  • 熔断:故障止损,下游坏了直接断路兜底

  • 限流 + MQ:流量缓冲,请求太多先排队排队消化

消息队列设计模式 : 生产者消费者模型

简单学习 --> 阻塞队列-CSDN博客

MQ 到底怎么实现限流
  1. 来多少请求,都先丢队列

  2. 队列有最大容量(20),满了直接拒绝 → 限流

  3. 后台只有一个消费者2 秒处理一个

  4. 不管你并发 10、100、1000,处理速度永远可控

  5. LLM 永远不会被瞬间流量冲垮

这就是 MQ 削峰限流 的本质!

MQ简易代码实现
复制代码
import asyncio
import logging
​
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
​
# ==================== MQ 核心 ====================
# 消息队列:用来缓冲、排队、限流
class ContentMQ:
    def __init__(self):
        # 异步队列 = 简易 MQ
        # maxsize=20 → 最多排队20个请求 → 限流
        self.queue = asyncio.Queue(maxsize=20)
​
    # 生产者:接收请求 → 扔进队列
    async def produce(self, topic: str, request_id: str):
        try:
            await self.queue.put((topic, request_id))
            logger.info(f"[{request_id}] 已加入队列 | 当前排队:{self.queue.qsize()}")
        except asyncio.QueueFull:
            # 队列满了 = 限流触发
            logger.warning(f"[{request_id}] 队列已满,触发限流!")
            raise Exception("系统繁忙,请稍后再试")
​
    # 消费者:**匀速、慢速** 从队列取任务处理
    # 这就是限流的关键!不管多少请求,都慢慢处理
    async def consume(self):
        while True:
            topic, request_id = await self.queue.get()
            logger.info(f"[{request_id}] 开始生成内容:{topic}")
            
            # 👇 你的 LLM 调用(慢任务)
            try:
                await asyncio.sleep(2)  # 模拟 LLM 耗时
                logger.info(f"[{request_id}] 生成成功!")
            except Exception as e:
                logger.error(f"[{request_id}] LLM 失败:{e}")
            finally:
                self.queue.task_done()
​
# ==================== 你的业务 ====================
class ContentService:
    def __init__(self):
        self.mq = ContentMQ()  # 服务自带 MQ
​
    # 对外接口:只入队,不处理 → 永远不卡
    async def generate_article(self, topic: str, request_id: str):
        await self.mq.produce(topic, request_id)
        return "任务已排队,正在生成中..."
​
    # 启动后台消费线程
    async def start_consumer(self):
        asyncio.create_task(self.mq.consume())
​
# ==================== 测试 ====================
async def main():
    service = ContentService()
    await service.start_consumer()
​
    # 模拟 30 个并发请求
    tasks = [service.generate_article(f"AI科普{i}", f"请求{i}") for i in range(30)]
    await asyncio.gather(*tasks, return_exceptions=True)
​
asyncio.run(main())
相关推荐
专注API从业者2 小时前
用 Open Claw + 淘宝商品接口,快速实现电商商品监控与智能选品(附完整代码)
大数据·前端·数据结构·数据库
kyraaa12 小时前
618智能灭蚊器什么牌子好?电灭蚊灯哪个牌子好用?综合测评希亦、绳池等10大热门灭蚊灯品牌!
大数据·人工智能·python
deephub2 小时前
推理 → 行动 → 观察:用 LangChain + Python 实现一个智能体循环
人工智能·python·langchain·大语言模型·agent
码界筑梦坊2 小时前
143-基于Python的景点热度分析数据可视化分析系统
python·信息可视化·数据分析·毕业设计·fastapi
独隅2 小时前
PyTorch转TFLite动态形状量化指南
人工智能·pytorch·python
尖枫5082 小时前
EPLAN生成设备符号宏、设备布局宏、设备3D宏及创建部件方法总结
学习
TDengine (老段)2 小时前
TDengine 虚拟表实现原理
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
隔壁大炮2 小时前
MNE-Python 第3天学习笔记:事件与标记处理
python·eeg·mne·脑电数据处理
吃好睡好便好2 小时前
用if…elseif…end语句输出成绩等级
开发语言·前端·javascript·数据库·学习·matlab·信息可视化