服务器与大带宽专家 · 持牌IDC/CDN/ISP服务商
简米科技官网JIANMI TECH
资讯 2026-09-04 更新于 2026-09-04 简米科技 6,513 字 16 分钟阅读

云主机部署API接口服务时如何做基础限流,限流算法有哪些

导读云主机部署 API 接口服务时做基础限流,最直接有效的方式是结合反向代理层限流与应用层计数器限流,优先选择 Nginx + Lua 或网关中间件,能在不改业务代码的前提下快速生效,为什么你的云主机 API 接口需要限流API 接口部署到云主机后,相当于把大门敞开在公网,没有限流,一个爬虫脚本或一次流量尖峰就能把……

云主机部署 API 接口服务时做基础限流,最直接有效的方式是结合反向代理层限流与应用层计数器限流,优先选择 Nginx + Lua 或网关中间件,能在不改业务代码的前提下快速生效。

为什么你的云主机 API 接口需要限流

API 接口部署到云主机后,相当于把大门敞开在公网,没有限流,一个爬虫脚本或一次流量尖峰就能把 CPU 打满,数据库连接耗尽,整个服务直接雪崩,尤其是轻量云服务器或单机部署场景,资源本身有限,接口一旦被刷,恢复时间比大集群慢得多。

业内专家指出,多数中小规模 API 服务遭遇的非正常流量占比相当可观,而限流是保障可用性的第一道防线,你不需要一开始就上 Sentinel 或 Kong 这类重型方案,从云主机自身能力出发,先做基础限流,就能挡住八成的风险。

云主机部署 API 接口服务限流方案对比

选限流方案前,先看你的部署形态,同样是云主机,有的用 Docker 跑 Spring Boot,有的直接用 Nginx 反代到 Node 服务,还有的干脆在代码里写过滤器,不同场景适合不同方案,对比一下就能定位。

限流位置 实现方式 优势 劣势 适用场景
反向代理层 Nginx + limit_req 性能损耗极小,配置简单 只能做粗粒度 IP/QPS 限流 所有用 Nginx 的部署
应用网关层 Spring Cloud Gateway / APISIX 支持路径、参数、用户维度限流 引入额外组件,部署复杂度高 微服务架构,多服务共享限流
应用代码层 Guava RateLimiter / Redisson 可定制规则,结合业务逻辑 侵入业务代码,多实例需分布式锁 单实例小型服务
云服务商自带 安全组 + WAF + CDN 防护 不占用云主机资源 粒度粗,通常只防 DDoS 级别 对外暴露公网入口的所有云主机

如果你只部署了一台云主机,推荐第一行,Nginx 是绝大多数云镜像自带的,改配置文件就能用,至少能快速挡住同一 IP 的连续请求。

Nginx 内置 limit_req 模块的实操步骤

Nginx 的 ngx_http_limit_req_module 是官方内置模块,不需要额外编译,配置分两步:先在 http 块定义限流规则,再在 serverlocation 块引用。

第一步,在 nginx.confhttp {} 内添加:

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

这行代码的含义是:以客户端 IP 为 key,开辟 10MB 共享内存,限制每秒 10 个请求,10MB 大约能存储 16 万个 IP 地址,对云主机完全够用。

第二步,在需要限流的 location 块内启用:

location /api/ {
    limit_req zone=api_limit burst=20 nodelay;
    proxy_pass http://backend_server;
}

burst=20 表示允许队列积压 20 个请求,超过后立即返回 503。nodelay 让排队请求不等待,直接转发给后端,这里的关键参数是 rateburst 的比例,比如你的接口平均响应时间 200ms,可以放每 IP 每秒 5 个请求,burst 给到 10,既能防刷又不误伤正常调用。

云主机部署API接口服务时如何做基础限流,限流算法有哪些

配置完成后,nginx -t 检查语法,nginx -s reload 生效,你可以在云主机上执行 curl -i http://你的IP/api/test 连续快速请求,看到部分响应返回 503 就说明限流生效了。

应用层集中限流怎么做

Nginx 层限流只能按 IP 维度,如果攻击者换了 IP 池,或者多个用户共享一个出口 IP(比如公司 NAT),就容易误伤或者绕过,这时候需要在应用代码里做一层更细的限流。

以 Java 的 Spring Boot 为例,最常见的做法是使用 Google Guava 的 RateLimiter,不依赖外部存储,适合单机场景。

private final RateLimiter rateLimiter = RateLimiter.create(20.0); // 每秒允许 20 个请求
public Response handleRequest(Request request) {
    if (!rateLimiter.tryAcquire()) {
        return Response.status(429).build(); // 返回 Too Many Requests
    }
    // 业务逻辑
}

注意 Guava 的限流是进程内单机版,如果你的云主机只跑一个实例,完全够用,但假如你在同一台云主机上用 Docker 跑了多个容器实例,每个容器都有独立的 RateLimiter,总限流数就会变成 20 乘以容器数,这种情况下,需要把计数移到 Redis 上,用 INCREXPIRE 命令实现滑动窗口限流。

Redis 滑动窗口限流的代码示例

Redis 方案的核心思想是:用当前时间戳作为 key 的分片,计数并设置过期时间,比如限制每 IP 每分钟 60 次,伪代码如下:

import time
import redis
r = redis.Redis(host='127.0.0.1', port=6379, db=0)
def is_allowed(user_id):
    key = f"rate:{user_id}:{int(time.time() // 60)}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, 60)
    return count <= 60

这里有一个容易被忽略的坑:时间窗口是固定的 60 秒,如果用户在 59.5 秒时发了 60 个请求,下一秒窗口重置又可以发 60 个,实际效果相当于每分钟允许 60 个,但极端情况下每 1.5 秒就能打满 60 个,要想更平滑,可以用 Redis 的 ZSET 记录每个请求的时间戳,做真正的滑动窗口,但基础限流阶段,固定窗口的误差可以接受,先把服务保下来再谈精度。

基于云主机安全组和防火墙的粗粒度限流

很多云厂商的控制台提供安全组和防火墙规则,如果你发现某个 IP 在疯狂刷接口,最快的方式不是改代码,而是登录云控制台,在安全组入方向添加一条拒绝规则,这是最低成本的限流手段,但只适合处理已知恶意 IP。

更进一步的方案是使用云服务商自带的 Web 应用防火墙(WAF)或 DDoS 防护,比如简米云、酷番云的云主机都支持在控制台开启 WAF 的 IP 黑名单、地域封禁、频次控制功能,这些功能虽然带"WAF"名称,但大部分按请求次数计费,对个人开发者来说价格可能不太友好,如果你只部署了一个小型 API,建议先把 Nginx 和应用层限流做好,暂时不买 WAF。

云主机限流配置后的验证与调优

限流配置不是写完就不管了,你需要确认两件事:限流是否生效,以及是否误伤了正常用户。

验证方法很简单,在云主机上执行压测命令:

ab -n 100 -c 20 http://你的域名/api/test

上面的命令表示模拟 100 个请求,20 并发,观察结果中的 Failed requests

云主机部署API接口服务时如何做基础限流,限流算法有哪些

数量,如果配置了 rate=10r/s,且没有 burst,100 个请求中应该有相当一部分返回 503,如果全部返回 200,说明配置没生效,检查 limit_req_zone 是否写在了 server 块内(必须放在 http 块)。

另一个需要调优的地方是错误码,Nginx 默认返回 503,但很多客户端对 503 的处理是直接重试,反而加重服务负担,建议统一返回 429(Too Many Requests),并且加上 Retry-After 响应头,告诉客户端多久后再试,修改方法在 location 块内添加:

error_page 503 =429 @rate_limit;
location @rate_limit {
    add_header Retry-After 2 always;
    return 429;
}

这样客户端收到 429 后,会根据 Retry-After 的秒数等待再发起请求,限流本身就成了一个平滑的流量控制机制。

使用微服务网关时的限流配置要点

如果你的云主机上已经部署了 Spring Cloud Gateway 或 APISIX,就不需要再单独写 Nginx 限流了,这些网关本身内置了限流过滤器,以 Spring Cloud Gateway 为例,使用 RequestRateLimiter 过滤器,需要结合 Redis 实现。

application.yml 中的配置片段:

spring:
  cloud:
    gateway:
      routes:
        - id: api_route
          uri: lb://backend-service
          predicates:
            - Path=/api/
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@userKeyResolver}"

这里 replenishRate 是每秒填充的令牌数,burstCapacity 是令牌桶容量。key-resolver 可以自定义,比如按用户 ID 或请求参数限流,而不是单纯的 IP,网关限流的好处是规则集中管理,多个服务共享一个限流配置,对于个人开发者的小项目,如果已经引入了网关,用这个方案比 Nginx 更灵活。

限流与云主机资源消耗的平衡

很多人在限流时忽略一个问题:限流本身也要消耗资源,Nginx 的 limit_req_zone 共享内存是预分配的,10MB 对云主机来说不算什么,但应用层使用 Guava 或 Redis 限流,会增加 CPU 和网络开销,据统计,在低配云主机(1核2G)上,每秒钟处理 1000 次 Redis 计数操作会增加约 5% 的 CPU 使用率,如果你的服务本身已经高负载,限流逻辑就需要精简。

一个实操建议是:把限流判断放在业务逻辑之前,用短路方式尽早返回,同时将 Redis 操作合并成 pipeline,减少网络往返。

pipe = r.pipeline()
pipe.incr(key)
pipe.expire(key, 60)
result = pipe.execute()

云主机上的监控工具(如 Prometheus + Grafana)可以记录被限流的请求数,把这些指标作为告警项,当限流触发次数突然增多时,通常意味着你遇到了攻击或者某个客户端出现了异常,这时候再去调大 burst 或者检查代码,比盲目调参更高效。

API 接口限流中常见的配置误区和解决方案

不少人在云主机上做完限流后,发现接口性能反而下降,或者正常用户频繁被拦截,这些问题多半源于以下几个误区。

  • 限流维度选错:只按 IP 限流,忽略了多设备共享 IP 的情况,如果用户的网关和服务器之间没有保留 IP 传递,所有用户看起来都像同一个 IP,限流就会误伤,解决办法是在 Nginx 中配置

    云主机部署API接口服务时如何做基础限流,限流算法有哪些

    $http_x_forwarded_for 或者使用云厂商的 X-Forwarded-For 头获取真实 IP。

  • burst 设置太小:面对瞬时的并发请求,比如前端发起的 5 个并行请求,burst 小于这个数,就会被拦截,一般情况下,burst 至少设置成 rate 的 2 倍,具体根据你的前端页面同时发起的请求数调整。
  • 没有区分读接口和写接口:查询接口可以放宽限流,写接口(如提交订单、发送短信)需要收紧,最佳实践是在 Nginx 层做粗粒度 IP 限流,在应用层按接口路径做精细限流,/api/order 限每用户每分钟 10 次,/api/search 限每 IP 每秒 20 次。
  • 限流后没有归因日志:被限流的请求到底来自哪个客户端,限流规则是否生效,这些如果完全没有日志记录,你很难判断问题,在 Nginx 的 log_format 中加入 $limit_rate 变量,被限流的请求会记录为 503,通过分析 Nginx access.log 就能定位。

云主机限流的技术选型建议

结合 2026 年的技术趋势,云主机部署 API 服务时,最稳妥的路径是"Nginx 粗限流 + 应用层细限流 + Redis 集群状态"三层组合,如果你的云主机配置很低(1核1G),建议只保留 Nginx 层限流,不要引入 Redis 和网关,因为额外进程会挤占宝贵的内存,等业务量上来,再平滑迁移到云厂商的 API 网关产品或容器化部署。

对于国内云主机的用户,还可以考虑在云控制台直接开启"DDoS 原生防护"的 IP 清洗功能,这个功能按防护带宽计费,基础版本的价格大约每月几十元到上百元不等,具体取决于购买的防护套餐,API 经常被攻击,这笔费用省不得,因为它能帮你挡住攻击流量,保证限流规则不会因为流量过大而本身失效。

常见问题解答

云主机上做了 Nginx 限流后,为什么接口还是被大量请求打挂了?

Nginx 的 limit_req 只能限制基于 IP 的请求速率,如果你的攻击者使用了大量代理 IP,或者请求本身占用的后端资源极大(比如一个请求就需要 3 秒 CPU 计算),Nginx 层即使限制到每秒 10 个请求,后端依然会被这 10 个请求拖垮,你需要结合应用层的超时控制,给接口设置合理的超时时间(2 秒),并在代码中实现熔断机制,当错误率超过阈值时直接拒绝新请求。

限流时返回 429 还是 503 更合适?

行业共识是尽量使用 429(Too Many Requests)表示速率限制,因为 503 通常被客户端理解为服务端故障,会触发重试或告警,429 有专门的语义,还可以附带 Retry-After 头,让客户端明确知道何时可以再次请求,如果你使用云服务商的负载均衡,还需要确认它不会自动拦截 429 响应,否则客户端可能看到的是 502。

Redis 限流在云主机上部署需要注意什么?

Redis 实例最好和 API 服务部署在同一台云主机上,或部署在同可用区的内网环境,避免公网访问 Redis 带来的延迟和带宽费用,使用 redis-cli ping 验证延迟,如果延迟超过 1ms,建议把 Redis 迁移到内网或者使用 UnixSocket,另外定时对 Redis 进行 bgsave 持久化,防止云主机重启导致计数器丢失,从而让限流在一段时间内失效。

分享本文
本文为 简米科技官网 原创,已由运维技术专家审核。转载请注明来源:原文链接
售前咨询 服务热线 售后 邮箱