❓什么是限流控制单位时间请求数量❓为什么需要限流防止系统被打爆防止依赖服务DB / Redis / LLM被压垮❓限流一般在哪几层网关层Nginx / Gateway服务层Controller / Service依赖层DB / LLM限流算法1️⃣ 固定窗口最简单特点每秒最多 N 次实现简单问题边界突刺瞬间翻倍在时间边界处流量会“瞬间翻倍”2️⃣ 滑动窗口改进版不再按固定时间段切特点更平滑精度更高问题实现复杂3️⃣ 令牌桶最常用 ⭐特点支持突发流量工程上最常用4️⃣ 漏桶平滑流量请求进入桶队列 → 按固定速率处理漏水特点匀速输出不允许突发为什么令牌桶更常用❗一句话结论令牌桶 同时满足“抗突发 控速率 体验好”的最优平衡1.网关层面的ip限流gateway怎么使用IP限流1.向 Spring 容器注册一个 KeyResolver 类型的 BeanBean public KeyResolver keyResolver() { return exchange - Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()); }作用获取用户的ip地址2.配置文件中进行配置spring: redis: host: localhost port: 6379 application: name: ratelimiter-example cloud: gateway: routes: - id: route1 uri: http://localhost:8080/hello predicates: - Path/hello filters: - name: RequestRateLimiter args: # 每秒往令牌桶里补充 20 个令牌 # 可以理解为“长期平均每秒最多允许 20 次请求” redis-rate-limiter.replenishRate: 20 # 令牌桶最大容量是 40 # 可以理解为“最多允许积攒 40 个令牌”用于应对突发流量 redis-rate-limiter.burstCapacity: 40 # 每个请求要消耗 1 个令牌 # 如果改成 2就表示一次请求要拿走 2 个令牌 redis-rate-limiter.requestedTokens: 1你可以把它想成这样1.请求先到网关2.KeyResolver 先判断“这个请求属于谁”3.限流器根据这个 key 去 Redis 里找对应的桶4.有令牌就放行没有令牌就拦截IP限流的优点是什么•实现简单不依赖登录态。•对匿名接口也能用。•适合做第一层粗粒度防刷、防爬、防恶意流量。•网关层很容易接入不需要业务代码参与。IP限流遇到的问题是什么•IP 不稳定用户切网络、重连后可能变化。•多个人可能共用一个出口 IP容易误伤。•同一个用户可能有多个 IP限制不够精确。如果经过 Nginx / 网关代理IP 会不会不准会而且这是按 IP 限流最常见的问题之一。因为 getRemoteAddress() 取到的是“直接连到你这个服务的那一跳”的地址。如果请求路径是用户 - Nginx - Spring Cloud Gateway那你在 Gateway 里拿到的很可能是 Nginx 的 IP而不是真实用户 IP。❓如果一个系统的核心接口在高并发下出现下游资源如数据库、缓存或外部服务扛不住的情况你会如何设计一套限流与资源保护方案第一层放在网关层做入口限流。我会按userId 接口标识作为限流维度对匿名流量按 IP 兜底。算法上优先用令牌桶因为问答接口属于实时交互场景需要允许一定程度的突发请求同时控制长期平均速率。分布式实现上可以用Redis Lua保证令牌补充、扣减和放行判断的原子性。第二层放在服务层用Sentinel对 LLM 调用做资源保护。因为即使网关做了限流也不能完全依赖网关真实场景里可能存在网关规则失效、内部调用绕过网关或者短时间内通过网关的请求仍然过多直接把 LLM 打爆。所以在真正调用 LLM 前我会把这段逻辑接入 Sentinel把 LLM 调用定义成受保护资源对它配置QPS 阈值、线程数阈值必要时再配合熔断降级。一旦达到阈值就直接触发 block 逻辑返回“系统繁忙请稍后再试”而不是继续把压力压给下游模型Sentinel 的 QPS 限流和线程数限制有什么区别1️⃣ QPS 限流速率控制每秒最多允许多少请求进入特点快速拦截请求不关心请求处理多久只看“进入速度”2️⃣ 线程数限制并发控制同时最多有多少请求正在执行特点关注“资源占用”强依赖请求耗时防止线程池 / 下游被打爆❓为什么实际工程中“令牌桶”比滑动窗口更常用滑动窗口虽然在限流精度上更高可以避免固定窗口的边界突刺问题但它的实现成本较高比如基于 Redis 的 ZSET 需要在每次请求时删除过期数据、统计数量并插入新数据在高并发场景下会带来较大的性能和内存开销。相比之下令牌桶只需要维护当前令牌数量和时间信息计算和存储成本都更低同时还能允许一定程度的突发流量更符合用户实际使用场景。因此在大多数工程实践中令牌桶在性能、资源消耗和用户体验之间取得了更好的平衡所以使用更广泛。网关层为什么用 Redis Lua而不是本地限流网关层之所以优先选择 Redis Lua而不是单纯本地限流是因为网关通常是多实例部署本地限流只能控制单机流量无法在集群范围内统一控制总量。Redis 作为共享状态存储可以让所有网关实例访问同一份限流数据从而实现分布式一致限流。Lua 脚本则用于保证限流过程中的判断、扣减、过期设置等操作原子执行避免高并发下状态不一致的问题。Sentinel 的 block 和 fallback 分别是什么block 是“被 Sentinel 规则拦住了”时的处理逻辑。fallback 是“业务方法自己出错了”时的兜底逻辑。SentinelResource( value llmCall, blockHandler handleBlock, fallback handleFallback ) public String callLLM(String prompt) { return llmService.call(prompt); }