Fork me on GitHub

Spring Cloud Gateway限流詳解

目錄

Spring Cloud Gatway內置的 RequestRateLimiterGatewayFilterFactory 提供限流的能力,基于令牌桶算法實現。目前,它內置的 RedisRateLimiter ,依賴Redis存儲限流配置,以及統計數據。當然你也可以實現自己的RateLimiter,只需實現 org.springframework.cloud.gateway.filter.ratelimit.RateLimiter 接口,或者繼承 org.springframework.cloud.gateway.filter.ratelimit.AbstractRateLimiter

漏桶算法

想象有一個水桶,水桶以一定的速度出水(以一定速率消費請求),當水流速度過大水會溢出(訪問速率超過響應速率,就直接拒絕)。

漏桶算法的兩個變量:

  • 水桶漏洞的大小:rate
  • 最多可以存多少的水:burst

令牌桶算法

系統按照恒定間隔向水桶里加入令牌(Token),如果桶滿了的話,就不加了。每個請求來的時候,會拿走1個令牌,如果沒有令牌可拿,那么就拒絕服務。

TIPS

  • Redis Rate Limiter的實現基于這篇文章: Stripe
  • Spring官方引用的令牌桶算法文章: Token Bucket Algorithm ,有興趣可以看看。

寫代碼

  • 加依賴:

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
  • 寫配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    spring:
    cloud:
    gateway:
    routes:
    - id: after_route
    uri: lb://user-center
    predicates:
    - TimeBetween=上午0:00,下午11:59
    filters:
    - AddRequestHeader=X-Request-Foo, Bar
    - name: RequestRateLimiter
    args:
    # 令牌桶每秒填充平均速率
    redis-rate-limiter.replenishRate: 1
    # 令牌桶的上限
    redis-rate-limiter.burstCapacity: 2
    # 使用SpEL表達式從Spring容器中獲取Bean對象
    key-resolver: "#{@pathKeyResolver}"
    redis:
    host: 127.0.0.1
    port: 6379
  • 寫代碼:按照X限流,就寫一個針對X的KeyResolver。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Configuration
    public class Raonfiguration {
    /**
    * 按照Path限流
    *
    * @return key
    */
    @Bean
    public KeyResolver pathKeyResolver() {
    return exchange -> Mono.just(
    exchange.getRequest()
    .getPath()
    .toString()
    );
    }
    }
  • 這樣,限流規則即可作用在路徑上。

    1
    2
    3
    例如:
    # 訪問:http://${GATEWAY_URL}/users/1,對于這個路徑,它的redis-rate-limiter.replenishRate = 1,redis-rate-limiter.burstCapacity = 2;
    # 訪問:http://${GATEWAY_URL}/shares/1,對這個路徑,它的redis-rate-limiter.replenishRate = 1,redis-rate-limiter.burstCapacity = 2;

測試

持續高速訪問某個路徑,速度過快時,返回 HTTP ERROR 429

拓展

你也可以實現針對用戶的限流:

1
2
3
4
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

針對來源IP的限流:

1
2
3
4
5
6
7
8
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest()
.getHeaders()
.getFirst("X-Forwarded-For")
);
}

相關文章

相關文章

評論系統未開啟,無法評論!

欢乐彩注册-首页