Spring Cloud Gateway限流熔断技术预研:基于Redis的分布式限流实现方案

D
dashen2 2025-09-06T15:50:25+08:00
0 0 223

Spring Cloud Gateway限流熔断技术预研:基于Redis的分布式限流实现方案

引言

随着微服务架构的广泛应用,API网关作为系统的统一入口,承担着流量控制、安全认证、路由转发等重要职责。在高并发场景下,如何有效控制流量、防止系统过载成为保障服务稳定性的关键问题。Spring Cloud Gateway作为Spring官方推出的第二代API网关,提供了强大的限流熔断功能,结合Redis等分布式缓存技术,能够实现高效的分布式限流策略。

本文将深入探讨Spring Cloud Gateway的限流熔断机制,重点分析基于Redis的分布式限流算法实现,并提供完整的代码示例和最佳实践方案。

Spring Cloud Gateway限流机制概述

限流的基本概念

限流(Rate Limiting)是一种流量控制技术,用于控制系统在单位时间内处理的请求数量,防止系统因突发流量而过载。在微服务架构中,限流可以保护后端服务,避免因某个服务的故障导致整个系统雪崩。

Spring Cloud Gateway限流实现方式

Spring Cloud Gateway提供了多种限流实现方式:

  1. 基于内存的本地限流:使用内存存储限流计数器,适用于单实例场景
  2. 基于Redis的分布式限流:使用Redis存储限流状态,适用于集群环境
  3. 自定义限流过滤器:通过实现GatewayFilter接口自定义限流逻辑

基于Redis的分布式限流实现

环境准备

首先需要在项目中引入相关依赖:

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

Redis配置

spring:
  redis:
    host: localhost
    port: 6379
    database: 0
    timeout: 2000ms
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: -1ms

令牌桶算法实现

算法原理

令牌桶算法是一种网络流量整形和速率限制算法。系统以恒定的速率向桶中添加令牌,请求需要消耗令牌才能被处理。当桶中没有足够令牌时,请求被拒绝或等待。

核心实现代码

@Component
@Slf4j
public class RedisRateLimiter {
    
    @Autowired
    private ReactiveRedisTemplate<String, String> redisTemplate;
    
    /**
     * 令牌桶限流实现
     * @param key 限流key
     * @param maxTokens 最大令牌数
     * @param refillTokens 每秒补充令牌数
     * @return 是否允许通过
     */
    public Mono<Boolean> tryAcquire(String key, int maxTokens, int refillTokens) {
        String script = buildTokenBucketScript();
        
        List<String> keys = Arrays.asList(key + ":tokens", key + ":timestamp");
        List<String> args = Arrays.asList(
            String.valueOf(maxTokens),
            String.valueOf(refillTokens),
            String.valueOf(System.currentTimeMillis()),
            "1" // 消耗的令牌数
        );
        
        return redisTemplate.execute(
            RedisScript.of(script, Long.class),
            keys,
            args.toArray(new String[0])
        ).map(result -> result > 0);
    }
    
    /**
     * 构建令牌桶Lua脚本
     */
    private String buildTokenBucketScript() {
        return """
            local tokens_key = KEYS[1]
            local timestamp_key = KEYS[2]
            
            local max_tokens = tonumber(ARGV[1])
            local refill_tokens = tonumber(ARGV[2])
            local current_time = tonumber(ARGV[3])
            local requested_tokens = tonumber(ARGV[4])
            
            local last_tokens = tonumber(redis.call("GET", tokens_key)) or max_tokens
            local last_refreshed = tonumber(redis.call("GET", timestamp_key)) or 0
            
            local delta = math.max(0, current_time - last_refreshed)
            local filled_tokens = math.min(max_tokens, last_tokens + (delta / 1000) * refill_tokens)
            local allowed = filled_tokens >= requested_tokens
            local new_tokens = filled_tokens
            if allowed then
                new_tokens = filled_tokens - requested_tokens
            end
            
            redis.call("SET", tokens_key, new_tokens)
            redis.call("SET", timestamp_key, current_time)
            
            return allowed and 1 or 0
            """;
    }
}

网关过滤器实现

@Component
@Slf4j
public class TokenBucketRateLimitGatewayFilter implements GatewayFilter, Ordered {
    
    @Autowired
    private RedisRateLimiter redisRateLimiter;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 获取限流配置
        String routeId = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
        String key = buildRateLimitKey(request, routeId);
        
        // 从请求头或配置中获取限流参数
        int maxTokens = getRateLimitConfig(routeId, "maxTokens", 100);
        int refillTokens = getRateLimitConfig(routeId, "refillTokens", 10);
        
        return redisRateLimiter.tryAcquire(key, maxTokens, refillTokens)
            .flatMap(allowed -> {
                if (allowed) {
                    return chain.filter(exchange);
                } else {
                    log.warn("Rate limit exceeded for key: {}", key);
                    return handleRateLimitExceeded(exchange);
                }
            });
    }
    
    private String buildRateLimitKey(ServerHttpRequest request, String routeId) {
        String clientIp = getClientIp(request);
        return "rate_limit:" + routeId + ":" + clientIp;
    }
    
    private String getClientIp(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("X-Forwarded-For");
        if (ip == null || ip.isEmpty()) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.isEmpty()) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip;
    }
    
    private Mono<Void> handleRateLimitExceeded(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"code\":429,\"message\":\"Too Many Requests\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    private int getRateLimitConfig(String routeId, String key, int defaultValue) {
        // 这里可以从配置中心或数据库获取配置
        // 简化实现,直接返回默认值
        return defaultValue;
    }
    
    @Override
    public int getOrder() {
        return -1000;
    }
}

滑动窗口限流算法

算法原理

滑动窗口算法通过维护一个时间窗口内的请求计数来实现限流。相比固定窗口算法,滑动窗口能够更精确地控制流量,避免边界效应。

实现代码

@Component
@Slf4j
public class SlidingWindowRateLimiter {
    
    @Autowired
    private ReactiveRedisTemplate<String, String> redisTemplate;
    
    /**
     * 滑动窗口限流实现
     * @param key 限流key
     * @param limit 限制请求数
     * @param windowSizeMs 窗口大小(毫秒)
     * @return 是否允许通过
     */
    public Mono<Boolean> tryAcquire(String key, int limit, long windowSizeMs) {
        String script = buildSlidingWindowScript();
        
        List<String> keys = Arrays.asList(key);
        List<String> args = Arrays.asList(
            String.valueOf(System.currentTimeMillis()),
            String.valueOf(windowSizeMs),
            String.valueOf(limit)
        );
        
        return redisTemplate.execute(
            RedisScript.of(script, Long.class),
            keys,
            args.toArray(new String[0])
        ).map(result -> result > 0);
    }
    
    private String buildSlidingWindowScript() {
        return """
            local key = KEYS[1]
            local current_time = tonumber(ARGV[1])
            local window_size = tonumber(ARGV[2])
            local limit = tonumber(ARGV[3])
            
            local window_start = current_time - window_size
            
            -- 移除过期的记录
            redis.call("ZREMRANGEBYSCORE", key, 0, window_start)
            
            -- 获取当前窗口内的请求数
            local current_count = redis.call("ZCARD", key)
            
            if current_count >= limit then
                return 0
            end
            
            -- 添加当前请求
            redis.call("ZADD", key, current_time, current_time)
            redis.call("EXPIRE", key, math.ceil(window_size / 1000) + 1)
            
            return 1
            """;
    }
}

熔断器配置与实现

Resilience4j集成

Spring Cloud Gateway集成了Resilience4j,可以方便地配置熔断器:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - name: CircuitBreaker
              args:
                name: userServiceCircuitBreaker
                fallbackUri: forward:/fallback/user-service
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY

熔断器配置

@Configuration
@EnableConfigurationProperties(CircuitBreakerProperties.class)
public class CircuitBreakerConfig {
    
    @Bean
    public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
            .circuitBreakerConfig(CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .slowCallRateThreshold(50)
                .waitDurationInOpenState(Duration.ofSeconds(10))
                .slowCallDurationThreshold(Duration.ofSeconds(2))
                .permittedNumberOfCallsInHalfOpenState(3)
                .minimumNumberOfCalls(10)
                .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED)
                .slidingWindowSize(10)
                .build())
            .timeLimiterConfig(TimeLimiterConfig.custom()
                .timeoutDuration(Duration.ofSeconds(3))
                .build())
            .build());
    }
}

熔断降级处理

@RestController
@Slf4j
public class FallbackController {
    
    @RequestMapping("/fallback/user-service")
    public Mono<ResponseEntity<Map<String, Object>>> userServiceFallback() {
        log.warn("User service circuit breaker fallback triggered");
        Map<String, Object> response = new HashMap<>();
        response.put("code", 503);
        response.put("message", "Service temporarily unavailable");
        response.put("timestamp", System.currentTimeMillis());
        return Mono.just(ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response));
    }
    
    @RequestMapping("/fallback/order-service")
    public Mono<ResponseEntity<Map<String, Object>>> orderServiceFallback() {
        log.warn("Order service circuit breaker fallback triggered");
        Map<String, Object> response = new HashMap<>();
        response.put("code", 503);
        response.put("message", "Order service is temporarily unavailable");
        response.put("timestamp", System.currentTimeMillis());
        return Mono.just(ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response));
    }
}

高级限流策略

多维度限流

@Component
@Slf4j
public class MultiDimensionRateLimitFilter implements GatewayFilter, Ordered {
    
    @Autowired
    private RedisRateLimiter redisRateLimiter;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String routeId = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
        
        // 用户级别限流
        String userKey = "rate_limit:user:" + getUserId(request);
        Mono<Boolean> userLimit = redisRateLimiter.tryAcquire(userKey, 100, 10);
        
        // IP级别限流
        String ipKey = "rate_limit:ip:" + getClientIp(request);
        Mono<Boolean> ipLimit = redisRateLimiter.tryAcquire(ipKey, 50, 5);
        
        // 接口级别限流
        String apiKey = "rate_limit:api:" + routeId;
        Mono<Boolean> apiLimit = redisRateLimiter.tryAcquire(apiKey, 1000, 100);
        
        return Mono.zip(userLimit, ipLimit, apiLimit)
            .flatMap(tuple -> {
                boolean userAllowed = tuple.getT1();
                boolean ipAllowed = tuple.getT2();
                boolean apiAllowed = tuple.getT3();
                
                if (userAllowed && ipAllowed && apiAllowed) {
                    return chain.filter(exchange);
                } else {
                    log.warn("Multi-dimension rate limit exceeded: user={}, ip={}, api={}", 
                            userAllowed, ipAllowed, apiAllowed);
                    return handleRateLimitExceeded(exchange);
                }
            });
    }
    
    private String getUserId(ServerHttpRequest request) {
        // 从JWT token或其他方式获取用户ID
        String authorization = request.getHeaders().getFirst("Authorization");
        if (authorization != null && authorization.startsWith("Bearer ")) {
            String token = authorization.substring(7);
            // 解析JWT获取用户ID
            return parseUserIdFromToken(token);
        }
        return "anonymous";
    }
    
    private String parseUserIdFromToken(String token) {
        try {
            // JWT解析逻辑
            return "user123"; // 简化实现
        } catch (Exception e) {
            return "anonymous";
        }
    }
    
    private String getClientIp(ServerHttpRequest request) {
        // 获取客户端IP的逻辑
        return request.getRemoteAddress().getAddress().getHostAddress();
    }
    
    private Mono<Void> handleRateLimitExceeded(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        String body = "{\"code\":429,\"message\":\"Rate limit exceeded\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -1001;
    }
}

动态限流配置

@Component
@Slf4j
public class DynamicRateLimitConfig {
    
    @Autowired
    private ReactiveRedisTemplate<String, String> redisTemplate;
    
    /**
     * 更新限流配置
     */
    public Mono<Void> updateRateLimitConfig(String routeId, RateLimitConfig config) {
        String key = "rate_limit_config:" + routeId;
        String configJson = JsonUtils.toJson(config);
        return redisTemplate.opsForValue().set(key, configJson)
            .then(Mono.fromRunnable(() -> log.info("Updated rate limit config for route: {}", routeId)));
    }
    
    /**
     * 获取限流配置
     */
    public Mono<RateLimitConfig> getRateLimitConfig(String routeId) {
        String key = "rate_limit_config:" + routeId;
        return redisTemplate.opsForValue().get(key)
            .map(json -> JsonUtils.fromJson(json, RateLimitConfig.class))
            .defaultIfEmpty(new RateLimitConfig()); // 返回默认配置
    }
    
    @Data
    public static class RateLimitConfig {
        private int maxTokens = 100;
        private int refillTokens = 10;
        private boolean enabled = true;
        private long windowSizeMs = 60000; // 60秒
        private int limit = 1000;
    }
}

性能优化与最佳实践

Redis连接池优化

spring:
  redis:
    lettuce:
      pool:
        max-active: 50
        max-idle: 20
        min-idle: 5
        max-wait: 2000ms
      cluster:
        refresh:
          adaptive: true
          period: 30s

Lua脚本优化

为了提高性能,建议将常用的Lua脚本预加载到Redis中:

@Component
public class LuaScriptLoader {
    
    @Autowired
    private ReactiveRedisTemplate<String, String> redisTemplate;
    
    @PostConstruct
    public void loadScripts() {
        // 预加载令牌桶脚本
        String tokenBucketScript = buildTokenBucketScript();
        redisTemplate.execute(RedisScript.of(tokenBucketScript, Long.class), 
            Collections.emptyList(), Collections.emptyList())
            .subscribe();
            
        // 预加载滑动窗口脚本
        String slidingWindowScript = buildSlidingWindowScript();
        redisTemplate.execute(RedisScript.of(slidingWindowScript, Long.class), 
            Collections.emptyList(), Collections.emptyList())
            .subscribe();
    }
}

监控与告警

@Component
@Slf4j
public class RateLimitMetrics {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    private final Counter rateLimitCounter;
    private final Timer rateLimitTimer;
    
    public RateLimitMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.rateLimitCounter = Counter.builder("gateway.rate_limit.exceeded")
            .description("Rate limit exceeded count")
            .register(meterRegistry);
        this.rateLimitTimer = Timer.builder("gateway.rate_limit.check")
            .description("Rate limit check duration")
            .register(meterRegistry);
    }
    
    public void recordRateLimitExceeded(String routeId, String clientIp) {
        rateLimitCounter.increment(
            Tags.of(
                Tag.of("route", routeId),
                Tag.of("client_ip", clientIp)
            )
        );
        log.warn("Rate limit exceeded for route: {}, client: {}", routeId, clientIp);
    }
    
    public Timer.Sample startTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordTimer(Timer.Sample sample, String routeId) {
        sample.stop(Timer.builder("gateway.rate_limit.check")
            .tag("route", routeId)
            .register(meterRegistry));
    }
}

故障处理与容错机制

Redis故障降级

@Component
@Slf4j
public class RedisFaultToleranceRateLimiter {
    
    @Autowired
    private RedisRateLimiter redisRateLimiter;
    
    @Autowired
    private LocalRateLimiter localRateLimiter;
    
    public Mono<Boolean> tryAcquire(String key, int maxTokens, int refillTokens) {
        return redisRateLimiter.tryAcquire(key, maxTokens, refillTokens)
            .onErrorResume(throwable -> {
                log.error("Redis rate limiter failed, fallback to local limiter", throwable);
                // Redis故障时降级到本地限流
                return localRateLimiter.tryAcquire(key, maxTokens, refillTokens);
            })
            .timeout(Duration.ofSeconds(1))
            .onErrorReturn(false); // 超时或异常时拒绝请求
    }
}

本地限流实现

@Component
public class LocalRateLimiter {
    
    private final Map<String, TokenBucket> buckets = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    
    public Mono<Boolean> tryAcquire(String key, int maxTokens, int refillTokens) {
        TokenBucket bucket = buckets.computeIfAbsent(key, k -> {
            TokenBucket tb = new TokenBucket(maxTokens, refillTokens);
            // 定期清理过期的bucket
            scheduler.scheduleAtFixedRate(() -> {
                if (tb.isExpired()) {
                    buckets.remove(k);
                }
            }, 60, 60, TimeUnit.SECONDS);
            return tb;
        });
        
        return Mono.just(bucket.tryAcquire());
    }
    
    private static class TokenBucket {
        private volatile int tokens;
        private final int maxTokens;
        private final int refillTokens;
        private volatile long lastRefillTime;
        private volatile long lastAccessTime;
        
        public TokenBucket(int maxTokens, int refillTokens) {
            this.maxTokens = maxTokens;
            this.refillTokens = refillTokens;
            this.tokens = maxTokens;
            this.lastRefillTime = System.currentTimeMillis();
            this.lastAccessTime = System.currentTimeMillis();
        }
        
        public synchronized boolean tryAcquire() {
            long now = System.currentTimeMillis();
            lastAccessTime = now;
            
            // 补充令牌
            long timePassed = now - lastRefillTime;
            int tokensToAdd = (int) (timePassed * refillTokens / 1000);
            if (tokensToAdd > 0) {
                tokens = Math.min(maxTokens, tokens + tokensToAdd);
                lastRefillTime = now;
            }
            
            // 尝试获取令牌
            if (tokens > 0) {
                tokens--;
                return true;
            }
            return false;
        }
        
        public boolean isExpired() {
            return System.currentTimeMillis() - lastAccessTime > 300000; // 5分钟未访问则过期
        }
    }
}

配置管理与动态调整

限流配置管理

@RestController
@RequestMapping("/admin/rate-limit")
@RequiredArgsConstructor
public class RateLimitConfigController {
    
    private final DynamicRateLimitConfig dynamicRateLimitConfig;
    
    @GetMapping("/{routeId}")
    public Mono<ResponseEntity<DynamicRateLimitConfig.RateLimitConfig>> getConfig(
            @PathVariable String routeId) {
        return dynamicRateLimitConfig.getRateLimitConfig(routeId)
            .map(config -> ResponseEntity.ok(config))
            .defaultIfEmpty(ResponseEntity.notFound().build());
    }
    
    @PutMapping("/{routeId}")
    public Mono<ResponseEntity<Void>> updateConfig(
            @PathVariable String routeId,
            @RequestBody DynamicRateLimitConfig.RateLimitConfig config) {
        return dynamicRateLimitConfig.updateRateLimitConfig(routeId, config)
            .then(Mono.just(ResponseEntity.ok().build()));
    }
    
    @DeleteMapping("/{routeId}")
    public Mono<ResponseEntity<Void>> deleteConfig(@PathVariable String routeId) {
        return dynamicRateLimitConfig.updateRateLimitConfig(routeId, new DynamicRateLimitConfig.RateLimitConfig())
            .then(Mono.just(ResponseEntity.ok().build()));
    }
}

测试与验证

单元测试

@SpringBootTest
@AutoConfigureWebTestClient
class RateLimitTest {
    
    @Autowired
    private WebTestClient webTestClient;
    
    @Test
    void testTokenBucketRateLimit() {
        // 模拟高并发请求
        List<Mono<ClientResponse>> requests = new ArrayList<>();
        for (int i = 0; i < 150; i++) {
            requests.add(webTestClient.get()
                .uri("/api/test")
                .exchange());
        }
        
        StepVerifier.create(Flux.concat(requests))
            .expectNextMatches(response -> 
                response.statusCode() == HttpStatus.OK || 
                response.statusCode() == HttpStatus.TOO_MANY_REQUESTS)
            .verifyComplete();
    }
}

性能测试

@Test
void testRateLimitPerformance() {
    ExecutorService executor = Executors.newFixedThreadPool(50);
    CountDownLatch latch = new CountDownLatch(1000);
    AtomicInteger successCount = new AtomicInteger();
    AtomicInteger failCount = new AtomicInteger();
    
    long startTime = System.currentTimeMillis();
    
    for (int i = 0; i < 1000; i++) {
        executor.submit(() -> {
            try {
                webTestClient.get()
                    .uri("/api/test")
                    .exchange()
                    .subscribe(response -> {
                        if (response.statusCode() == HttpStatus.OK) {
                            successCount.incrementAndGet();
                        } else {
                            failCount.incrementAndGet();
                        }
                        latch.countDown();
                    });
            } catch (Exception e) {
                failCount.incrementAndGet();
                latch.countDown();
            }
        });
    }
    
    try {
        latch.await(30, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    
    long endTime = System.currentTimeMillis();
    log.info("Performance test completed in {}ms, success: {}, fail: {}", 
        endTime - startTime, successCount.get(), failCount.get());
}

总结与展望

本文详细介绍了Spring Cloud Gateway基于Redis的分布式限流实现方案,包括令牌桶算法、滑动窗口算法、熔断器配置等核心技术。通过合理的架构设计和性能优化,可以构建一个高可用、高性能的限流系统。

关键要点

  1. 算法选择:根据业务场景选择合适的限流算法,令牌桶适合突发流量,滑动窗口适合精确控制
  2. 分布式支持:使用Redis实现分布式限流,确保集群环境下的一致性
  3. 容错机制:实现Redis故障降级,保证系统的可用性
  4. 监控告警:建立完善的监控体系,及时发现和处理问题
  5. 动态配置:支持运行时动态调整限流策略,提高系统灵活性

未来发展方向

  1. AI驱动的智能限流:基于机器学习算法动态调整限流策略
  2. 多级缓存架构:结合本地缓存和分布式缓存提高性能
  3. 更丰富的限流维度:支持用户、设备、地理位置等多维度限流
  4. 可视化管理平台:提供图形化的限流配置和监控界面

通过持续的技术创新和实践优化,Spring Cloud Gateway的限流熔断机制将在微服务治理中发挥越来越重要的作用,为构建稳定可靠的分布式系统提供有力保障。

相似文章

    评论 (0)