Spring Cloud Gateway网关限流熔断与动态路由配置实战

Spring Cloud Gateway核心架构

Spring Cloud Gateway是基于Spring WebFlux构建的API网关,采用Reactor响应式编程模型,底层依赖Netty实现非阻塞IO。相比Zuul 1.x的阻塞模型,Spring Cloud Gateway在并发性能上有数量级提升。其核心组件包括Route(路由定义,包含ID、目标URI、Predicate和Filter)、Predicate(断言工厂,匹配HTTP请求)、Filter(过滤器,修改请求和响应)。Gateway通过RoutePredicateFactory和GatewayFilterFactory的SPI机制扩展功能,内置30+种断言和过滤器,覆盖路径匹配、Header修改、限流、熔断等常见场景。

动态路由配置与热更新

生产环境中路由规则需要动态调整而不重启网关,Spring Cloud Gateway支持通过自定义RouteDefinitionRepository实现路由的动态加载。以下是基于Redis的动态路由实现:

// DynamicRouteDefinitionRepository.java
public class DynamicRouteDefinitionRepository implements RouteDefinitionRepository {

    private final StringRedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        Set<String> keys = redisTemplate.keys("gateway:routes:*");
        if (keys == null || keys.isEmpty()) {
            return Flux.empty();
        }
        List<RouteDefinition> routes = new ArrayList<>();
        for (String key : keys) {
            String json = redisTemplate.opsForValue().get(key);
            try {
                routes.add(objectMapper.readValue(json, RouteDefinition.class));
            } catch (Exception e) {
                log.error("Parse route definition failed: {}", key, e);
            }
        }
        return Flux.fromIterable(routes);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(r -> {
            String json = objectMapper.writeValueAsString(r);
            redisTemplate.opsForValue().set("gateway:routes:" + r.getId(), json);
            applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            redisTemplate.delete("gateway:routes:" + id);
            applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            return Mono.empty();
        });
    }
}

路由信息存储在Redis中,通过ApplicationEventPublisher发布RefreshRoutesEvent触发路由表热更新,无需重启网关进程。

RequestRateLimiter限流过滤器配置

Spring Cloud Gateway内置RequestRateLimiter过滤器,基于Redis + Lua脚本实现令牌桶限流,支持按用户、IP、路径等多维度限流。配置示例:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@userKeyResolver}"
            - StripPrefix=1

replenishRate是令牌填充速率(每秒100个),burstCapacity是桶容量(突发200个)。key-resolver定义限流维度,以下是基于用户ID的KeyResolver:

@Bean
KeyResolver userKeyResolver() {
    return exchange -> {
        String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
        if (userId == null) {
            userId = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        }
        return Mono.just(userId);
    };
}

按用户限流可防止单用户刷接口,按IP限流可防爬虫和DDoS,两者可组合使用。

Resilience4j熔断降级配置

Spring Cloud Gateway集成Resilience4j实现熔断和降级。配置CircuitBreaker过滤器:

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - name: CircuitBreaker
              args:
                name: orderServiceCB
                fallbackUri: forward:/fallback/orders

resilience4j:
  circuitbreaker:
    instances:
      orderServiceCB:
        sliding-window-size: 20
        minimum-number-of-calls: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 30s
        permitted-number-of-calls-in-half-open-state: 5
        sliding-window-type: COUNT_BASED

降级接口处理逻辑:

@RestController
public class FallbackController {

    @GetMapping("/fallback/orders")
    public Mono<ResponseEntity<Map<String, Object>>> orderFallback() {
        Map<String, Object> body = Map.of(
            "code", 503,
            "message", "订单服务暂时不可用,请稍后重试"
        );
        return Mono.just(ResponseEntity.status(503).body(body));
    }
}

熔断器在失败率达到50%时打开,30秒后进入半开状态探测,5个探测请求通过则关闭熔断器,否则继续保持打开。

网关性能调优与监控

Gateway基于WebFlux响应式模型,调优方向与传统Servlet容器不同。关键参数包括:reactor.netty.ioWorkerCount(IO线程数,默认CPU核心数*2)、spring.cloud.gateway.httpclient.connectTimeout、spring.cloud.gateway.httpclient.responseTimeout。监控方面通过Gateway内置的GlobalFilter记录请求指标,集成Micrometer+Prometheus暴露metrics端点,Grafana展示QPS、延迟分位数、错误率等核心指标。生产环境建议配合Nacos/Apollo做配置中心统一管理路由规则,实现多环境灰度发布。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloudgateway-wang-guan-xian-liu-rong-duan-yu-dong-tai/

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

相关推荐

Spring Cloud Gateway网关限流熔断与动态路由配置实战

Spring Cloud Gateway基于Spring WebFlux构建,提供路由转发、限流、熔断、鉴权等网关核心功能。作为微服务架构的统一入口,网关层承担流量控制和安全防护职责。本文讲解Gateway的限流熔断配置和动态路由实现方案。

网关基础配置与路由规则

引入Spring Cloud Gateway依赖:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

路由规则通过YAML配置或Java DSL定义。以下配置定义了两个路由:用户服务路由和订单服务路由:

# application.yml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
            - Method=GET,POST
          filters:
            - StripPrefix=2
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@userKeyResolver}"

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=2
            - name: CircuitBreaker
              args:
                name: orderCircuitBreaker
                fallbackUri: forward:/fallback/orders

lb://前缀表示使用负载均衡,Gateway通过服务发现(如Nacos/Eureka)解析具体实例地址。StripPrefix=2表示转发前移除路径前两段,/api/users/login变为/login。

Redis令牌桶限流实现

RequestRateLimiter过滤器基于Redis实现的令牌桶算法进行限流。replenishRate控制令牌补充速率(每秒令牌数),burstCapacity控制桶容量(最大突发流量)。

KeyResolver定义限流维度,可按用户、IP、接口等维度限流:

@Configuration
public class RateLimiterConfig {

    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> {
            String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
            if (userId != null) {
                return Mono.just(userId);
            }
            return Mono.just(exchange.getRequest().getRemoteAddress()
                    .getAddress().getHostAddress());
        };
    }

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
}

对于需要不同接口设置不同限流策略的场景,可通过自定义过滤器实现:

@Component
public class CustomRateLimitFilter implements GlobalFilter, Ordered {

    private final ReactiveRedisTemplate<String, String> redisTemplate;

    public CustomRateLimitFilter(ReactiveRedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().value();
        String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        RateLimitRule rule = getRuleForPath(path);
        String key = "rate_limit:" + path + ":" + ip;

        return redisTemplate.opsForValue()
            .increment(key)
            .flatMap(count -> {
                if (count == 1) {
                    return redisTemplate.expire(key, Duration.ofSeconds(rule.getTimeWindow()))
                        .then(checkLimit(count, rule, exchange, chain));
                }
                return checkLimit(count, rule, exchange, chain);
            });
    }

    private Mono<Void> checkLimit(Long count, RateLimitRule rule,
                                   ServerWebExchange exchange, GatewayFilterChain chain) {
        if (count > rule.getLimit()) {
            exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
            exchange.getResponse().getHeaders().add("Content-Type", "application/json");
            String body = "{\"code\":429,\"message\":\"\u8bf7\u6c42\u8fc7\u4e8e\u9891\u7e41\"}";
            DataBuffer buffer = exchange.getResponse().bufferFactory()
                .wrap(body.getBytes(StandardCharsets.UTF_8));
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }

    private RateLimitRule getRuleForPath(String path) {
        if (path.startsWith("/api/users/login")) {
            return new RateLimitRule(5, 60);
        }
        if (path.startsWith("/api/orders")) {
            return new RateLimitRule(50, 1);
        }
        return new RateLimitRule(100, 1);
    }

    @Override
    public int getOrder() { return -1; }
}

Resilience4j熔断器配置

CircuitBreaker过滤器集成Resilience4j实现熔断降级。熔断器在错误率达到阈值时打开,阻断后续请求直接返回降级响应:

# application.yml
resilience4j:
  circuitbreaker:
    configs:
      default:
        sliding-window-size: 100
        minimum-number-of-calls: 20
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s
        permitted-number-of-calls-in-half-open-state: 5
        sliding-window-type: COUNT_BASED
    instances:
      orderCircuitBreaker:
        base-config: default
      userCircuitBreaker:
        base-config: default
        failure-rate-threshold: 30

  timelimiter:
    configs:
      default:
        timeout-duration: 3s
    instances:
      orderCircuitBreaker:
        base-config: default

熔断降级接口实现:

@RestController
public class FallbackController {

    @GetMapping("/fallback/orders")
    public Mono<Map<String, Object>> orderFallback() {
        return Mono.just(Map.of(
            "code", 503,
            "message", "\u8ba2\u5355\u670d\u52a1\u6682\u65f6\u4e0d\u53ef\u7528",
            "timestamp", System.currentTimeMillis()
        ));
    }

    @GetMapping("/fallback/users")
    public Mono<Map<String, Object>> userFallback() {
        return Mono.just(Map.of(
            "code", 503,
            "message", "\u7528\u6237\u670d\u52a1\u6682\u65f6\u4e0d\u53ef\u7528"
        ));
    }
}

动态路由与配置热更新

静态路由配置需要重启网关才能生效。通过自定义RouteDefinitionRepository实现从数据库或Nacos加载路由规则,支持动态刷新:

@Component
public class DatabaseRouteDefinitionRepository implements RouteDefinitionRepository {

    private final RouteService routeService;

    public DatabaseRouteDefinitionRepository(RouteService routeService) {
        this.routeService = routeService;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(routeService.findAll()
            .stream()
            .map(this::toRouteDefinition)
            .collect(Collectors.toList()));
    }

    private RouteDefinition toRouteDefinition(RouteEntity entity) {
        RouteDefinition route = new RouteDefinition();
        route.setId(entity.getRouteId());
        route.setUri(URI.create(entity.getUri()));
        List<PredicateDefinition> predicates = new ArrayList<>();
        predicates.add(new PredicateDefinition("Path=" + entity.getPathPattern()));
        route.setPredicates(predicates);
        List<FilterDefinition> filters = new ArrayList<>();
        if (entity.getStripPrefix() > 0) {
            filters.add(new FilterDefinition("StripPrefix=" + entity.getStripPrefix()));
        }
        route.setFilters(filters);
        return route;
    }
}

路由变更后通过ApplicationEventPublisher发布RefreshRoutesEvent触发路由刷新:

@Service
public class RouteRefreshService {

    @Autowired
    private ApplicationEventPublisher publisher;

    public void refreshRoutes() {
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

全局过滤器与请求日志

GlobalFilter对全部路由生效,可用于鉴权、日志记录、请求头处理等:

@Component
@Order(0)
public class AuthGlobalFilter implements GlobalFilter {

    private final List<String> skipPaths = List.of("/api/users/login", "/api/users/register");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().value();
        if (skipPaths.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return unauthorized(exchange, "\u7f3a\u5c11\u8ba4\u8bc1\u4ee4\u724c");
        }
        try {
            Claims claims = JwtUtil.parseToken(token.substring(7));
            String userId = claims.getSubject();
            ServerHttpRequest request = exchange.getRequest().mutate()
                .header("X-User-Id", userId).build();
            return chain.filter(exchange.mutate().request(request).build());
        } catch (Exception e) {
            return unauthorized(exchange, "\u4ee4\u724c\u65e0\u6548\u6216\u5df2\u8fc7\u671f");
        }
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        exchange.getResponse().getHeaders().add("Content-Type", "application/json");
        String body = "{\"code\":401,\"message\":\"" + message + "\"}";
        DataBuffer buffer = exchange.getResponse().bufferFactory()
            .wrap(body.getBytes(StandardCharsets.UTF_8));
        return exchange.getResponse().writeWith(Mono.just(buffer));
    }
}

Spring Cloud Gateway通过组合限流、熔断、动态路由等能力,构建了完整的API网关解决方案。Redis令牌桶限流提供精确的流量控制,Resilience4j熔断器保障后端服务故障隔离,动态路由支持运行时规则调整,全局过滤器统一处理鉴权和日志。配合Nacos等配置中心,可实现路由规则的实时推送与热更新。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloudgateway-wang-guan-xian-liu-rong-duan-yu-dong-tai/

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

相关推荐