Spring Cloud微服务网关限流熔断实战:从Sentinel规则到自定义过滤器链设计

微服务网关的流量治理需求

微服务架构中,API网关是所有外部请求的统一入口。限流防止流量洪峰击穿下游服务,熔断在依赖服务故障时快速失败避免雪崩。Spring Cloud Gateway + Sentinel是目前Java生态中最主流的网关流量治理方案,本文从生产实践角度拆解配置、自定义扩展和故障排查。

Sentinel网关限流配置

Sentinel为Spring Cloud Gateway提供了专用模块sentinel-spring-cloud-gateway-adapter,支持按路由ID或API分组限流:

<!-- pom.xml -->
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
  <version>1.8.8</version>
</dependency>

配置限流规则:

@Configuration
public class GatewayConfig {

    @PostConstruct
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        
        // 按路由ID限流:用户服务QPS上限500
        rules.add(new GatewayFlowRule("user-service")
            .setCount(500)
            .setIntervalSec(1)
        );
        
        // 按路由+参数限流:单个IP每秒最多50次
        rules.add(new GatewayFlowRule("user-service")
            .setCount(50)
            .setIntervalSec(1)
            .setParamItem(new GatewayParamItem()
                .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_IP)
            )
        );
        
        // 订单服务突发限流:允许短暂突发
        rules.add(new GatewayFlowRule("order-service")
            .setCount(200)
            .setIntervalSec(1)
            .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
            .setMaxQueueingTimeoutMs(500)  // 排队等待500ms
        );
        
        GatewayRuleManager.loadRules(rules);
    }
}

限流触发时默认返回429,自定义响应:

@Configuration
public class GatewayBlockHandler {

    @PostConstruct
    public void initBlockHandler() {
        GatewayCallbackManager.setBlockHandler((exchange, t) -> {
            Map<String, Object> result = Map.of(
                "code", 429,
                "message", "请求过于频繁,请稍后重试",
                "timestamp", System.currentTimeMillis()
            );
            return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(result));
        });
    }
}

Sentinel熔断降级配置

熔断针对下游服务的异常响应。三种熔断策略:

// 慢调用比例熔断
DegradeRule slowCallRule = new DegradeRule("payment-service")
    .setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
    .setCount(1.0)           // 慢调用阈值:1秒
    .setSlowRatioThreshold(0.6)  // 慢调用比例60%触发熔断
    .setTimeWindow(30)       // 熔断持续30秒
    .setMinRequestAmount(10) // 最小请求数
    .setStatIntervalMs(10000); // 统计窗口10秒

// 异常比例熔断
DegradeRule errorRatioRule = new DegradeRule("payment-service")
    .setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
    .setCount(0.5)          // 异常比例50%触发
    .setTimeWindow(20)
    .setMinRequestAmount(5)
    .setStatIntervalMs(5000);

// 异常数熔断
DegradeRule errorCountRule = new DegradeRule("payment-service")
    .setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType())
    .setCount(10)           // 10次异常触发
    .setTimeWindow(60)
    .setMinRequestAmount(5)
    .setStatIntervalMs(10000);

DegradeRuleManager.loadRules(
    Arrays.asList(slowCallRule, errorRatioRule, errorCountRule)
);

自定义过滤器链:请求日志与链路追踪

网关过滤器链是实现横切关注点的核心机制。一个生产级的请求日志过滤器:

@Component
public class RequestLogFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(RequestLogFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String traceId = UUID.randomUUID().toString().replace("-", "");
        long startTime = System.currentTimeMillis();
        
        // 注入traceId到请求头,传递到下游
        ServerWebExchange mutatedExchange = exchange.mutate()
            .request(builder -> builder.headers(headers -> {
                headers.add("X-Trace-Id", traceId);
            }))
            .build();
        
        // 存储开始时间,用于响应后计算耗时
        mutatedExchange.getAttributes().put("startTime", startTime);
        
        return chain.filter(mutatedExchange)
            .doFinally(signalType -> {
                Long endTime = System.currentTimeMillis();
                Long duration = endTime - startTime;
                String path = exchange.getRequest().getURI().getPath();
                int status = exchange.getResponse().getStatusCode().value();
                
                log.info("traceId={}, path={}, status={}, duration={}ms",
                    traceId, path, status, duration);
                
                // 超过阈值告警
                if (duration > 3000) {
                    log.warn("SLOW_REQUEST traceId={}, path={}, duration={}ms",
                        traceId, path, duration);
                }
            });
    }

    @Override
    public int getOrder() {
        return -1; // 最高优先级
    }
}

动态路由与规则热更新

生产环境中限流规则需要动态调整,重启网关不可接受。Sentinel支持通过DataSource接入配置中心:

// Nacos数据源配置
@Bean
public ReadableDataSource<String, Set<GatewayFlowRule>> nacosGatewayRuleDataSource() {
    Properties properties = new Properties();
    properties.put(PropertyKeyConst.SERVER_ADDR, "nacos-cluster:8848");
    properties.put(PropertyKeyConst.NAMESPACE, "production");
    
    ReadableDataSource<String, Set<GatewayFlowRule>> nacosDs =
        new NacosDataSource<>(properties,
            "gateway-group",
            "gateway-flow-rules",
            source -> JSON.parseObject(source,
                new TypeReference<Set<GatewayFlowRule>>(){}.getType())
        );
    
    GatewayRuleManager.register2Property(nacosDs.getProperty());
    return nacosDs;
}

在Nacos控制台修改规则后,Sentinel在1-2秒内自动拉取并生效,无需重启。同样的方式适用于降级规则和系统保护规则。

网关层故障排查手册

常见问题及处理:

# 1. 限流误触发(正常流量被429)
# 检查:Sentinel Dashboard → 簇点链路 → 实时监控
# 原因:QPS统计窗口默认1秒,瞬时脉冲可能触发
# 方案:调大intervalSec或切换为匀速排队模式

# 2. 熔断后不恢复
# 检查:DegradeRule的timeWindow配置
# 原因:timeWindow设太长,半开状态探活不够
# 方案:timeWindow设为15-30秒,配合minRequestAmount=3

# 3. 路由匹配不生效
# 检查:Gateway路由优先级(order值越小优先级越高)
# 原因:通配路由抢占了精确路由
# 方案:给精确路由设置更小的order值

微服务网关的流量治理是分布式系统稳定性的第一道屏障。限流规则的设计需要区分全局阈值和单维度阈值,熔断策略需要根据下游服务的SLA差异化配置,自定义过滤器链要控制好优先级和异常边界。所有规则都应该接入配置中心实现热更新,才能在线上快速响应流量变化。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloud-wei-fu-wu-wang-guan-xian-liu-rong-duan-shi-zhan/

(0)
小编小编
上一篇 3小时前
下一篇 3小时前

相关推荐