• Spring Cloud Gateway核心过滤器之请求限流详解


    环境:SpringBoot2.4.13 + Spring Cloud Gateway3.0.1


    概述

    RequestRateLimiter GatewayFilter工厂使用一个RateLimiter实现来确定当前请求是否允许继续。如果不是,返回HTTP 429 - Too Many Requests(默认情况下)的状态。

    该过滤器接受一个可选的keyResolver参数和特定于速率限制器的参数。该参数的作用就是用来根据你设定的规则生成key,比如在redis中使用什么key。

    keyResolver是一个实现KeyResolver接口的bean。在配置中,使用SpEL按名称引用bean。#{@userKeyResolver}是一个SpEL表达式,它引用了一个名为userKeyResolver的bean。KeyResolver接口如下所示:

    1. public interface KeyResolver {
    2. Mono<String> resolve(ServerWebExchange exchange);
    3. }

    默认情况下,如果KeyResolver没有找到key,请求将被拒绝。你可以通过设置
    spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true或false)和spring.cloud.gateway.filter.request-rate- limititer来调整这种行为。empty-key-status-code属性。

    注意:RequestRateLimiter不能用“快捷方式”表示法进行配置。以下示例无效:

    1. # INVALID SHORTCUT CONFIGURATION
    2. spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

    使用Redis限流

    Redis的实现是基于Stripe所做的工作。它需要使用
    spring-boot-starter-data-redis-reactive Spring Boot Starter。使用的算法是令牌桶算法。

    计数器算法:有时间临界问题。

    漏桶算法: 速率固定,有浪费资源问题。

    配置属性说明:

    1. redis-rate-limiter.replenishRate
    2. 允许用户在不丢弃任何请求的情况下每秒执行多少请求。这是令牌桶被填充的速率。
    3. redis-rate-limiter.burstCapacity
    4. 允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数量。将该值设置为零将阻止所有请求。
    5. redis-rate-limiter.requestedTokens
    6. 一个请求花费多少令牌。这是为每个请求从桶中提取令牌的数量,默认为1
    1. 一个稳定的速率是通过设置相同的值replenishRateburstCapacity
    2. 可以通过将burstCapacity设置为高于replenishRate来允许临时突发。

    速率限制器需要在突发之间留出一段时间(根据replenishRate补发率),因为两个连续的爆发将导致丢弃的请求(HTTP 429 - Too Many requests)。

    低于1个请求/秒的速率限制是通过以下方式实现的:将replenishRate设置为所需的请求数量,将requestedTokens设置为以秒为单位的时间跨度,将burstCapacity设置为replenishRaterequestedToken的乘积,例如,将replenishRate设为1,requestedTokens=60, burstCapability设置为60,将导致1 request/min的限制。

    配置示例:

    1. spring:
    2. cloud:
    3. gateway:
    4. default-filters:
    5. - StripPrefix=1
    6. routes:
    7. - id: o001
    8. uri: lb://order-service
    9. predicates:
    10. - Path=/api-a/**, /api-b/**
    11. filters:
    12. - name: RequestRateLimiter
    13. args:
    14. #每秒允许用户执行的请求数,而不丢弃任何请求。这是令牌桶的填充速率。
    15. redis-rate-limiter.replenishRate: 1
    16. #允许用户在一秒钟内完成的最大请求数。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。
    17. redis-rate-limiter.burstCapacity: 2
    18. #一个请求需要多少令牌。这是每个请求从存储桶中获取的令牌数,默认为1
    19. redis-rate-limiter.requestedTokens: 1
    20. keyResolver: "#{@userKeyResolver}"
    21. #自定义状态码
    22. #statusCode: INTERNAL_SERVER_ERROR
    1. @Configuration
    2. public class RedisRateConfig {
    3. @Bean
    4. public KeyResolver userKeyResolver() {
    5. // 以orderId限流
    6. // return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("orderId"));
    7. // 以ip限流
    8. return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()) ;
    9. }
    10. }

    解释:

    这定义了每个IP1个请求速率的限制。允许2个请求的突发,但是在下一秒,只有1个请求可用。KeyResolver是一个获取用户请求参数的简单方法(注意,不建议在生产环境中使用)。

    自定义限速器

    还可以将速率限制器定义为实现RateLimiter接口的bean。在配置中,您可以使用SpEL按名称引用bean。#{@userRateLimiter}是一个SpEL表达式,它引用了一个名为userRateLimiter的bean。下面的清单定义了一个使用上一个清单中定义的KeyResolver的速率限制器:

    1. spring:
    2. cloud:
    3. gateway:
    4. default-filters:
    5. - StripPrefix=1
    6. routes:
    7. - id: o001
    8. uri: lb://order-service
    9. predicates:
    10. - Path=/api-a/**, /api-b/**
    11. filters:
    12. - name: RequestRateLimiter
    13. args:
    14. rate-limiter: "#{@userRateLimiter}"
    15. keyResolver: "#{@userKeyResolver}"
    1. public class UserRateLimiter implements RateLimiter<UserRateLimiter.Config> {
    2. @Override
    3. public Map<String, Config> getConfig() {
    4. return null;
    5. }
    6. @Override
    7. public Class<Config> getConfigClass() {
    8. return null;
    9. }
    10. @Override
    11. public Config newConfig() {
    12. return null;
    13. }
    14. @Override
    15. public Mono<Response> isAllowed(String routeId, String id) {
    16. return null;
    17. }
    18. public static class Config {
    19. @Min(1)
    20. private int replenishRate;
    21. @Min(0)
    22. private int burstCapacity = 1;
    23. @Min(1)
    24. private int requestedTokens = 1;
    25. public int getReplenishRate() {
    26. return replenishRate;
    27. }
    28. public Config setReplenishRate(int replenishRate) {
    29. this.replenishRate = replenishRate;
    30. return this;
    31. }
    32. public int getBurstCapacity() {
    33. return burstCapacity;
    34. }
    35. public Config setBurstCapacity(int burstCapacity) {
    36. this.burstCapacity = burstCapacity;
    37. return this;
    38. }
    39. public int getRequestedTokens() {
    40. return requestedTokens;
    41. }
    42. public Config setRequestedTokens(int requestedTokens) {
    43. this.requestedTokens = requestedTokens;
    44. return this;
    45. }
    46. @Override
    47. public String toString() {
    48. return new ToStringCreator(this).append("replenishRate", replenishRate)
    49. .append("burstCapacity", burstCapacity).append("requestedTokens", requestedTokens).toString();
    50. }
    51. }
    52. }

    完毕!!!

    Spring Cloud Gateway核心过滤器之请求限流详解

    原创2022-11-21 08:20·Spring全家桶实战案例

    环境:SpringBoot2.4.13 + Spring Cloud Gateway3.0.1


    概述

    RequestRateLimiter GatewayFilter工厂使用一个RateLimiter实现来确定当前请求是否允许继续。如果不是,返回HTTP 429 - Too Many Requests(默认情况下)的状态。

    该过滤器接受一个可选的keyResolver参数和特定于速率限制器的参数。该参数的作用就是用来根据你设定的规则生成key,比如在redis中使用什么key。

    keyResolver是一个实现KeyResolver接口的bean。在配置中,使用SpEL按名称引用bean。#{@userKeyResolver}是一个SpEL表达式,它引用了一个名为userKeyResolver的bean。KeyResolver接口如下所示:

    1. public interface KeyResolver {
    2. Mono<String> resolve(ServerWebExchange exchange);
    3. }

    默认情况下,如果KeyResolver没有找到key,请求将被拒绝。你可以通过设置
    spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true或false)和spring.cloud.gateway.filter.request-rate- limititer来调整这种行为。empty-key-status-code属性。

    注意:RequestRateLimiter不能用“快捷方式”表示法进行配置。以下示例无效:

    1. # INVALID SHORTCUT CONFIGURATION
    2. spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

    使用Redis限流

    Redis的实现是基于Stripe所做的工作。它需要使用
    spring-boot-starter-data-redis-reactive Spring Boot Starter。使用的算法是令牌桶算法。

    计数器算法:有时间临界问题。

    漏桶算法: 速率固定,有浪费资源问题。

    配置属性说明:

    1. redis-rate-limiter.replenishRate
    2. 允许用户在不丢弃任何请求的情况下每秒执行多少请求。这是令牌桶被填充的速率。
    3. redis-rate-limiter.burstCapacity
    4. 允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数量。将该值设置为零将阻止所有请求。
    5. redis-rate-limiter.requestedTokens
    6. 一个请求花费多少令牌。这是为每个请求从桶中提取令牌的数量,默认为1
    1. 一个稳定的速率是通过设置相同的值replenishRateburstCapacity
    2. 可以通过将burstCapacity设置为高于replenishRate来允许临时突发。

    速率限制器需要在突发之间留出一段时间(根据replenishRate补发率),因为两个连续的爆发将导致丢弃的请求(HTTP 429 - Too Many requests)。

    低于1个请求/秒的速率限制是通过以下方式实现的:将replenishRate设置为所需的请求数量,将requestedTokens设置为以秒为单位的时间跨度,将burstCapacity设置为replenishRaterequestedToken的乘积,例如,将replenishRate设为1,requestedTokens=60, burstCapability设置为60,将导致1 request/min的限制。

    配置示例:

    1. spring:
    2. cloud:
    3. gateway:
    4. default-filters:
    5. - StripPrefix=1
    6. routes:
    7. - id: o001
    8. uri: lb://order-service
    9. predicates:
    10. - Path=/api-a/**, /api-b/**
    11. filters:
    12. - name: RequestRateLimiter
    13. args:
    14. #每秒允许用户执行的请求数,而不丢弃任何请求。这是令牌桶的填充速率。
    15. redis-rate-limiter.replenishRate: 1
    16. #允许用户在一秒钟内完成的最大请求数。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。
    17. redis-rate-limiter.burstCapacity: 2
    18. #一个请求需要多少令牌。这是每个请求从存储桶中获取的令牌数,默认为1
    19. redis-rate-limiter.requestedTokens: 1
    20. keyResolver: "#{@userKeyResolver}"
    21. #自定义状态码
    22. #statusCode: INTERNAL_SERVER_ERROR
    1. @Configuration
    2. public class RedisRateConfig {
    3. @Bean
    4. public KeyResolver userKeyResolver() {
    5. // 以orderId限流
    6. // return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("orderId"));
    7. // 以ip限流
    8. return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()) ;
    9. }
    10. }

    解释:

    这定义了每个IP1个请求速率的限制。允许2个请求的突发,但是在下一秒,只有1个请求可用。KeyResolver是一个获取用户请求参数的简单方法(注意,不建议在生产环境中使用)。

    自定义限速器

    还可以将速率限制器定义为实现RateLimiter接口的bean。在配置中,您可以使用SpEL按名称引用bean。#{@userRateLimiter}是一个SpEL表达式,它引用了一个名为userRateLimiter的bean。下面的清单定义了一个使用上一个清单中定义的KeyResolver的速率限制器:

    1. spring:
    2. cloud:
    3. gateway:
    4. default-filters:
    5. - StripPrefix=1
    6. routes:
    7. - id: o001
    8. uri: lb://order-service
    9. predicates:
    10. - Path=/api-a/**, /api-b/**
    11. filters:
    12. - name: RequestRateLimiter
    13. args:
    14. rate-limiter: "#{@userRateLimiter}"
    15. keyResolver: "#{@userKeyResolver}"
    1. public class UserRateLimiter implements RateLimiter<UserRateLimiter.Config> {
    2. @Override
    3. public Map<String, Config> getConfig() {
    4. return null;
    5. }
    6. @Override
    7. public Class<Config> getConfigClass() {
    8. return null;
    9. }
    10. @Override
    11. public Config newConfig() {
    12. return null;
    13. }
    14. @Override
    15. public Mono<Response> isAllowed(String routeId, String id) {
    16. return null;
    17. }
    18. public static class Config {
    19. @Min(1)
    20. private int replenishRate;
    21. @Min(0)
    22. private int burstCapacity = 1;
    23. @Min(1)
    24. private int requestedTokens = 1;
    25. public int getReplenishRate() {
    26. return replenishRate;
    27. }
    28. public Config setReplenishRate(int replenishRate) {
    29. this.replenishRate = replenishRate;
    30. return this;
    31. }
    32. public int getBurstCapacity() {
    33. return burstCapacity;
    34. }
    35. public Config setBurstCapacity(int burstCapacity) {
    36. this.burstCapacity = burstCapacity;
    37. return this;
    38. }
    39. public int getRequestedTokens() {
    40. return requestedTokens;
    41. }
    42. public Config setRequestedTokens(int requestedTokens) {
    43. this.requestedTokens = requestedTokens;
    44. return this;
    45. }
    46. @Override
    47. public String toString() {
    48. return new ToStringCreator(this).append("replenishRate", replenishRate)
    49. .append("burstCapacity", burstCapacity).append("requestedTokens", requestedTokens).toString();
    50. }
    51. }
    52. }

    完毕!!!

    图片

  • 相关阅读:
    yolov3map、召回率随轮次增加下降
    unique_ptr的大小探讨
    如何根据镜像反向生成Dockerfile内容?这三种方式总有一个适合你
    外观设计的基本功能与产品特点
    AWTK 支持可独立安装的小应用程序 (applet)
    靠近用户侧和数据,算网融合实现极致协同
    力扣-459.重复的子字符串
    计算机毕业设计选题推荐-springboot 网上手机销售系统
    C++stack&queue
    二叉树:dfs+回溯
  • 原文地址:https://blog.csdn.net/asoklove/article/details/128186258