Gateway 网关流控与限流架构指南

Gateway 网关流控与限流架构指南

1. 整体架构概述

项目中搭建一套完整的基于 Sentinel + Nacos 动态规则 的 Gateway 流控体系,主要作用是保护微服务,防止瞬时高并发流量压垮系统。网关层的流控生效在所有请求进入具体微服务之前。

流控架构由以下三个核心部分组成:

  • 拦截生效层 :依靠 spring-cloud-alibaba-sentinel-gateway,自动将所有的 Gateway 路由(Route)注册为 Sentinel 保护的资源。
  • 配置持久层:依靠 Nacos 配置中心,持久化存储各种流控规则(如限流 QPS、排队等待策略等)。
  • 动态同步层 :依靠 sentinel-datasource-nacos,Gateway 启动时会连接 Nacos,并监听对应的 Data ID。一旦在 Nacos 修改流控规则,Gateway 不需重启即可实时生效。

2. 核心基础设施

2.1 引入的核心依赖

在 Gateway 模块的 pom.xml 中,已引入完整的 Sentinel 环境支持:

  • spring-cloud-starter-alibaba-sentinel:Sentinel 核心框架。
  • spring-cloud-alibaba-sentinel-gateway:专门适配 Spring Cloud Gateway 的模块。
  • sentinel-datasource-nacos:提供从 Nacos 动态拉取规则的功能。

2.2 核心配置说明

application.properties 中,已经做好了针对各环境(DEV、UAT、PROD)的无缝动态规则配置:

sql 复制代码
# 1. 禁用原生的基于 Servlet Filter 的过滤,因为 Gateway 基于 WebFlux
spring.cloud.sentinel.filter.enabled=false

# 2. 网关流控触发降级时的默认响应模式:返回 Response
spring.cloud.sentinel.scg.fallback.mode=response

# 3. Sentinel Dashboard 控制台通信端口配置
spring.cloud.sentinel.transport.port=${SENTINEL_TRANSPORT_PORT:8719}
spring.cloud.sentinel.transport.dashboard=${SENTINEL_TRANSPORT_DASHBOARD:localhost:8780}
# 启动时即刻初始化与控制台的连接,而不等待第一个流量到来
spring.cloud.sentinel.eager=${SENTINEL_EAGER:true}

# 4. ⭐ 核心配置:Nacos 动态数据源设置
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=${NACOS_SERVER_ADDR}
# Rule 文件在 Nacos 中的 Data ID,例如 gateway-gw-flow-sentinel
spring.cloud.sentinel.datasource.ds1.nacos.data-id=${spring.application.name}-gw-flow-sentinel
# Rule 文件的 Group ID (例如 DEV_GROUP / PROD_GROUP) 在各环境特有的 properties 中指定
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
# 指定拉取的数据是用于网关流控配置 (GatewayFlowRule)
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=gw-flow

3. 如何配置流控规则(操作指引)

网关流控是完全热更新的,不需要修改或发版任何代码 ,只需在 Nacos 配置中心 进行操作:

  1. 登录 Nacos 管理控制台。
  2. 进入【配置管理】 -> 【配置列表】。
  3. 选择当前对应环境的 Namespace
  4. 创建配置:
    • Data ID${项目名}-gw-flow-sentinel(例如 gateway-gw-flow-sentinel)。
    • Group :DEV环境选 DEV_GROUP,PROD选 PROD_GROUP(依据各环境 application-{env}.properties spring.cloud.sentinel.datasource.ds1.nacos.group-id 定义)。
    • 配置格式 :选择 JSON
  5. 在配置内容中填入流控规则数组(详见下一小节)。
  6. 点击发布,Gateway 服务会立即热加载该规则并生效。
json 复制代码
[
  {
    "resource": "user-center",
    "resourceMode": 0,
    "grade": 1,
    "count": 100,
    "intervalSec": 1,
    "controlBehavior": 0,
    "burst": 0,
    "maxQueueingTimeoutMs": 500,
    "paramItem": null
  }
]

核心字段说明

字段 含义 值说明
resource 匹配的资源名 对应 routes[].id,例如 user-center、product
resourceMode 资源模式 0=Route ID(按路由), 1=API Group(按自定义 API 分组)
grade 限流类型 1=QPS, 0=线程数
count 阈值 QPS=100 表示每秒最多100个请求
intervalSec 统计时间窗口 默认 1(秒)
controlBehavior 限流策略 0=快速失败, 1=匀速排队, 2=预热
burst 额外允许的突发量 配合快速失败使用
maxQueueingTimeoutMs 排队最大等待时间 配合匀速排队使用
paramItem 参数级热点限流 见下方高级用法

4. 实战流控规则配置(JSON 格式)

Sentinel Gateway 流控规则采用 JSON 数组格式,一个 JSON 对象代表一条针对网关资源的规则。

场景一:按 Route ID(路由)限流

这是最常见的情况,如限制进入 user-center 服务的请求不超过 200 QPS。

json 复制代码
[
  {
    "resource": "user-center",   // 对应 application.properties 中 gateway.routes[0].id
    "resourceMode": 0,           // 0 代表 Route ID 模式,1 代表自定义 API 分组模式
    "grade": 1,                  // 1 代表根据 QPS 限流,0 代表根据线程数限流
    "count": 200,                // QPS 阈值为 200
    "intervalSec": 1,            // 统计时间窗口 1 秒
    "controlBehavior": 0         // 控制行为:0 表示快速失败(直接返回降级响应)
  }
]

场景二:按自定义 API 路径限流

仅限制某个特定的微服务接口,比如登录接口,需先在 Java 代码(如 GatewayConfig)中建立 API 分组(GatewayApiDefinitionManager.loadApiDefinitions(...)),再在 Nacos 中映射该分组名称:

json 复制代码
[
  {
    "resource": "login-api",  // 对应 Java 代码里面定义的自定义 API 分组名
    "resourceMode": 1,              // 使用自定义 API 模式
    "grade": 1,
    "count": 50,
    "intervalSec": 1,
    "controlBehavior": 0
  }
]
java 复制代码
@Configuration
public class SentinelGatewayConfig {
    
    @PostConstruct
    public void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        
        // 定义一个 API 分组:login-api
        ApiDefinition loginApi = new ApiDefinition("login-api")
            .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                add(new ApiPathPredicateItem()
                    .setPattern("/api/user-center/main/login")      // 精确匹配
                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT));
                add(new ApiPathPredicateItem()
                    .setPattern("/api/user-center/main/login**")     // 前缀匹配
                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
            }});
        
        definitions.add(loginApi);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }
}

场景三:匀速排队策略(削峰填谷)

如果后端服务处理能力死板,不想快速拒绝请求,可以开启匀速排队策略

json 复制代码
[
  {
    "resource": "trade-center",
    "resourceMode": 0,
    "grade": 1,
    "count": 50,                  // 每秒精确通过 50 个请求(相当于每 20ms 执行一次请求)
    "intervalSec": 1,
    "controlBehavior": 1,         // 控制行为:1 代表匀速排队
    "maxQueueingTimeoutMs": 2000  // 如果在队列中等待超过 2000ms 还没轮到,才进行拒绝抛出异常
  }
]

场景四:基于参数(热点 IP/Header)限流

如果想要限制同一个 IP 对某个服务的疯狂调用:

json 复制代码
[
  {
    "resource": "user-center",
    "resourceMode": 0,
    "grade": 1,
    "count": 20,                // 每一个 IP 在 1 秒内针对 user-center 只能发 20 个请求
    "intervalSec": 1,
    "controlBehavior": 0,
    "paramItem": {
      "parseStrategy": 0        // 0 代表按照客户端真实 IP 进行统计 (依赖于 Gateway 的 RemoteAddressResolver 解析)
    }
  }
]

parseStrategy 其他可用值包括:2(按 Header 限流)、3(按 URL 参数限流)、4(按 Cookie 限流)。当值为 2/3/4 时,需要配合属性 fieldName 指定具体的 Header、参数名称。

5. 自定义触发限流后的响应

默认响应的是 Sentinel 原生自带的如 Blocked by Sentinel (flow limiting) 文字。推荐后续在 Gateway 项目下增加一个专门的 BlockRequestHandler 来统一个团队风格的 JSON 输出报文。

例如,实现 BlockRequestHandler 并交由 Spring 托管,当触发限流后返回:

json 复制代码
{
  "code": 429,
  "msg": "系统繁忙,请求被限流,请稍后重试",
  "data": null
}

或者用代码方式(更灵活):

java 复制代码
@Configuration
public class SentinelFallbackConfig {
    
    @PostConstruct
    public void initBlockHandler() {
        GatewayCallbackManager.setBlockHandler((exchange, throwable) -> {
            Map<String, Object> result = new HashMap<>();
            result.put("code", 429);
            result.put("message", "系统繁忙,请稍后重试");
            result.put("timestamp", System.currentTimeMillis());
            
            return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(result));
        });
    }
}
相关推荐
zhangfeng11331 小时前
国产GPU与ROCm架构的关系 国产GPU架构总结 ROCm 7.1 在 PyTorch 官网上被划掉(横线)直接支持
人工智能·pytorch·架构
范桂飓2 小时前
OpenClaw 架构解析
人工智能·架构
唯一世2 小时前
Open Feign最佳实践
java·spring cloud
认真的柯南2 小时前
深入解析服务器内存架构:从DRAM颗粒到NUMA模式
服务器·架构·numa
Predestination王瀞潞3 小时前
MVC 架构→分层架构→微服务架构 架构演进
微服务·架构·mvc
前端不太难3 小时前
鸿蒙 AI App 的技术架构解析
人工智能·架构·harmonyos
WJSKad12353 小时前
ResNet层级联架构改进YOLOv26深度特征提取与瓶颈扩展双重突破
yolo·目标跟踪·架构
威联通网络存储3 小时前
数据驱动精密智造:威联通 ZFS 存储架构的合规实践
python·架构
无级程序员4 小时前
k8s v1.35配置gateway, istio通过metalb vip访问
kubernetes·gateway·istio