java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Gateway限流

Gateway实现限流的一些常见方式

作者:C18298182575

文章介绍了如何在SpringCloudGateway中实现限流,包括基于请求次数、令牌桶算法、IP地址和时间窗口等多种限流策略,通过配置RequestRateLimiter过滤器和KeyResolver,可以灵活地控制不同来源的请求频率,确保系统稳定性和可用性,感兴趣的朋友一起看看吧

Gateway怎么实现限流的

在API网关(如Spring Cloud Gateway、Kong、Nginx等)中实现限流是为了控制服务请求的频率,从而避免系统过载,确保稳定性和可用性。限流可以通过多种策略实现,常见的方法包括基于请求次数、时间窗口、IP地址等方式进行限制。下面是 Spring Cloud Gateway 实现限流的一些常见方式:

1.基于请求次数的限流

这种方法通过限制单位时间内的请求次数来防止过多的请求访问服务。例如,限制每秒钟只能处理最多100个请求。

spring:
  cloud:
    gateway:
      routes:
        - id: rate_limiter_route
          uri: http://example.com
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10  # 每秒钟请求的数量
                redis-rate-limiter.burstCapacity: 20  # 突发容量,即短时间内允许的最大请求数

2.基于令牌桶算法(Token Bucket)限流

令牌桶算法是一种平滑请求流量的算法,它通过固定的速率生成令牌并将其存放在桶中,请求到达时需要获取令牌才能处理,如果令牌桶为空,则请求被拒绝。

Spring Cloud Gateway实现:使用RequestRateLimiter实现基于令牌桶的限流。

示例配置:

spring:
  cloud:
    gateway:
      routes:
        - id: token_bucket_route
          uri: http://example.com
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10  # 每秒生成的令牌数
                redis-rate-limiter.burstCapacity: 20  # 令牌桶的容量

这里的配置和上面的请求次数限制类似,但背后实现的是令牌桶算法。

3.基于IP限流

可以根据客户端IP地址来限制每个IP的请求频率,避免某个客户端过度访问服务。通常使用Redis来实现基于IP的限流。

示例配置(使用Redis):

spring:
  cloud:
    gateway:
      routes:
        - id: ip_rate_limiter_route
          uri: http://example.com
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                redis-rate-limiter.requestedTokens: 1
                redis-rate-limiter.keyResolver: "#{@ipKeyResolver}"

在这个例子中,keyResolver 指定了如何基于客户端 IP 地址来限流,可以自定义一个IP解析器ipKeyResolver,这样每个IP的请求次数会被限制。

4.基于时间窗口的限流

时间窗口限流是按照固定的时间窗口(如每分钟、每小时等)来限制请求的数量。通过时间窗口来控制单位时间内的最大请求数。

示例配置:

spring:
  cloud:
    gateway:
      routes:
        - id: time_window_route
          uri: http://example.com
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 5  # 每秒钟请求的数量
                redis-rate-limiter.burstCapacity: 10  # 突发容量
                redis-rate-limiter.requestedTokens: 1  # 每次请求消耗的令牌数

这种方式将请求限制在一定的时间窗口内,如果在窗口内的请求数量超过限制,将拒绝额外的请求。

5.自定义限流策略

Spring Cloud Gateway 还允许通过自定义KeyResolverRateLimiter等来实现更灵活的限流策略。例如,基于用户的ID、API路径等来做不同的限流策略。

自定义KeyResolver示例:

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

这个例子通过客户端IP地址进行限流。

6.其他网关限流工具

除了Spring Cloud Gateway,其他网关如 KongNginx 等也提供了丰富的限流功能:

总结

Spring Cloud Gateway 中,常见的限流方式包括:

可以通过RequestRateLimiter过滤器实现这些策略,结合 Redis 等存储技术来共享和持久化限流状态。在选择限流策略时,需要根据业务需求、流量模式、以及系统的负载能力来决定。

分析Gateway 限流代码

 
@Component
public class RateLimitConfig {
    @Bean
    KeyResolver userKeyResolver() {
	return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("token"));
    }
    @Bean
    KeyResolver ipKeyResolver() {
	return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    @Bean
    KeyResolver apiKeyResolver() {
	return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }
    @Primary
    @Bean
    KeyResolver appIpKeyResolver() {
	return exchange -> {
	    Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
	    return Mono.just(exchange.getRequest().getRemoteAddress().getHostName().concat(route.getUri().getHost()));
	};
    }
}

这段代码实现了Spring Cloud Gateway的限流配置,具体的实现通过不同的KeyResolver来为请求提供唯一的标识,用于区分不同的请求来源或策略。KeyResolver是限流的核心组成部分,它决定了限流的“键”(即每个请求的唯一标识),从而确保不同的请求按照不同的规则被限流。

以下是对代码的详细分析:

1.KeyResolver的作用

KeyResolver 是 Spring Cloud Gateway 中限流机制的一部分,用来生成与请求相关的唯一“键”。在限流时,基于这些“键”来计算每个限流单元(例如每个用户、每个IP、每个API等)的请求次数。限流规则会依据这些键来进行流量控制。

2.userKeyResolver

@Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("token")); }

3.ipKeyResolver

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

4.apiKeyResolver

@Bean KeyResolver apiKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getPath().value()); }

5.appIpKeyResolver

@Primary
@Bean KeyResolver appIpKeyResolver()
{ 
    return exchange -> 
    { 
        Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); return Mono.just(exchange.getRequest().getRemoteAddress().getHostName().concat(route.getUri().getHost())); 
    };
    }

6.@Primary注解

@Primary @Bean KeyResolver appIpKeyResolver()
{ 
    ... 
}

总结

这段代码定义了多个 KeyResolver,并为不同的限流策略提供了可选择的实现:

@Primary 注解确保 appIpKeyResolver 是默认的限流键生成器,除非特别指定,否则会优先使用它。

这些 KeyResolver 会与 RequestRateLimiter 等限流功能配合使用,从而在 API 网关层实现精细化的限流控制。

怎么没有指定限流的量,每秒允许访问的量

在这段代码中,虽然定义了不同的 KeyResolver 来生成限流的标识符(如 tokenIPAPI路径),但确实没有指定实际的限流规则(例如每秒允许的访问量)。限流的具体控制是通过 Spring Cloud Gateway 的 RequestRateLimiter 过滤器来实现的,而这个过滤器是用来根据指定的规则对请求进行限流的。

要实现每秒允许的访问量,你需要配置 RequestRateLimiter 过滤器,并为它指定限流规则(如每秒最大访问量和最大突发流量)。

完整的限流配置示例

首先,你需要创建一个 RequestRateLimiter 过滤器,并在过滤器中配置限流策略。通常,你可以通过如下方式来配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.gateway.filter.ratelimit.RequestRateLimiter;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.config.GlobalFilterAutoConfiguration;
@Configuration
public class GatewayConfig {
    @Bean
    public RequestRateLimiter filter(KeyResolver keyResolver) {
        // 配置限流:每秒最多允许 10 次请求,突发流量最多为 20 次
        return new RequestRateLimiter()
                .setRateLimiter(new MyRateLimiter(10, 20))  // 每秒 10 次请求,突发流量最多 20 次
                .setKeyResolver(keyResolver); // 设置限流的 KeyResolver
    }
    // 自定义一个简单的 RateLimiter 实现类
    public static class MyRateLimiter implements RateLimiter {
        private final int replenishRate;
        private final int burstCapacity;
        public MyRateLimiter(int replenishRate, int burstCapacity) {
            this.replenishRate = replenishRate;
            this.burstCapacity = burstCapacity;
        }
        @Override
        public boolean isAllowed(String key) {
            // 此处实现你自己的限流逻辑,可以借助令牌桶算法、漏桶算法等
            return true;  // 只是示例,实际需要实现限流逻辑
        }
        // 配置每秒最大请求数(每秒 10 次)
        public int getReplenishRate() {
            return replenishRate;
        }
        // 配置突发容量
        public int getBurstCapacity() {
            return burstCapacity;
        }
    }
}

如何将限流规则与KeyResolver配合?

在这段代码中,RequestRateLimiter 的限流规则(如每秒允许 10 次请求,突发容量为 20)会与之前定义的 KeyResolver 配合,限制特定 token、IP 或 API 路径的访问频率。

示例配置:按token限流

假设你想基于 token 进行限流,你可以这样配置:

@Bean
public RequestRateLimiter filter(KeyResolver userKeyResolver) {
    return new RequestRateLimiter()
            .setRateLimiter(new MyRateLimiter(10, 20))  // 每秒 10 次请求,突发流量最多 20 次
            .setKeyResolver(userKeyResolver);  // 使用之前定义的基于 token 的 KeyResolver
}

限流的配置项

总结

这段代码本身只是定义了限流的标识符(通过 KeyResolver)。真正的限流控制需要通过 RequestRateLimiter 过滤器来实现,并在其中指定限流的具体限制量(如每秒允许多少次请求)。你可以使用 replenishRateburstCapacity 来配置每秒允许的访问量及突发流量。

到此这篇关于Gateway实现限流的一些常见方式的文章就介绍到这了,更多相关Gateway限流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文