Spring Cloud Gateway 之 限流

簡介

在高併發的系統中,每每須要在系統中作限流,一方面是爲了防止大量的請求使服務器過載,致使服務不可用,另外一方面是爲了防止網絡***。java

通常開發高併發系統常見的限流有:限制總併發數(好比數據庫鏈接池、線程池)、限制瞬時併發數(如 nginx 的 limit_conn 模塊,用來限制瞬時併發鏈接數)、限制時間窗口內的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模塊,限制每秒的平均速率);其餘還有如限制遠程接口調用速率、限制 MQ 的消費速率。另外還能夠根據網絡鏈接數、網絡流量、CPU 或內存負載等來限流。react

限流算法

計數器

簡單的作法是維護一個單位時間內的 計數器,每次請求計數器加1,當單位時間內計數器累加到大於設定的閾值,則以後的請求都被拒絕,直到單位時間已通過去,再將 計數器 重置爲零。此方式有個弊端:若是在單位時間1s內容許100個請求,在10ms已經經過了100個請求,那後面的990ms,只能眼巴巴的把請求拒絕,咱們把這種現象稱爲「突刺現象」。nginx

經常使用的更平滑的限流算法有兩種:漏桶算法令牌桶算法。下面介紹下兩者。程序員

漏桶算法

漏桶算法思路很簡單,水(請求)先進入到漏桶裏,漏桶以必定的速度出水(接口有響應速率),當水流入速度過大會直接溢出(訪問頻率超過接口響應速率),而後就拒絕請求,能夠看出漏桶算法能強行限制數據的傳輸速率。redis

Spring Cloud Gateway 之 限流

可見這裏有兩個變量,一個是桶的大小,支持流量突發增多時能夠存多少的水(burst),另外一個是水桶漏洞的大小(rate)。由於漏桶的漏出速率是固定的參數,因此,即便網絡中不存在資源衝突(沒有發生擁塞),漏桶算法也不能使流突發(burst)到端口速率。所以,漏桶算法對於存在突發特性的流量來講缺少效率。算法

令牌桶算法

令牌桶算法 和漏桶算法 效果同樣但方向相反的算法,更加容易理解。隨着時間流逝,系統會按恆定 1/QPS 時間間隔(若是 QPS=100,則間隔是 10ms)往桶裏加入 Token(想象和漏洞漏水相反,有個水龍頭在不斷的加水),若是桶已經滿了就再也不加了。新請求來臨時,會各自拿走一個 Token,若是沒有 Token 可拿了就阻塞或者拒絕服務。spring

Spring Cloud Gateway 之 限流

令牌桶的另一個好處是能夠方便的改變速度。一旦須要提升速率,則按需提升放入桶中的令牌的速率。通常會定時(好比 100 毫秒)往桶中增長必定數量的令牌,有些變種算法則實時的計算應該增長的令牌的數量。數據庫

限流實現

在 Spring Cloud Gateway 上實現限流是個不錯的選擇,只須要編寫一個過濾器就能夠了。有了前邊過濾器的基礎,寫起來很輕鬆。api

Spring Cloud Gateway 已經內置了一個RequestRateLimiterGatewayFilterFactory,咱們能夠直接使用。服務器

目前RequestRateLimiterGatewayFilterFactory的實現依賴於 Redis,因此咱們還要引入spring-boot-starter-data-redis-reactive。

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifatId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

application.yml

server:
  port: 8080
spring:
  cloud:
    gateway:
      routes:
        - id: limit_route
          uri: http://httpbin.org:80/get
          predicates:
          - After=2019-02-26T00:00:00+08:00[Asia/Shanghai]
          filters:
          - name: RequestRateLimiter
            args:
              key-resolver: '#{@hostAddrKeyResolver}'
              redis-rate-limiter.replenishRate: 1
              redis-rate-limiter.burstCapacity: 3
  application:
    name: gateway-limiter
  redis:
    host: localhost
    port: 6379
    database: 0

在上面的配置文件,配置了 redis的信息,並配置了RequestRateLimiter的限流過濾器,該過濾器須要配置三個參數:

  • burstCapacity:令牌桶總容量。
  • replenishRate:令牌桶每秒填充平均速率。
  • key-resolver:用於限流的鍵的解析器的 Bean 對象的名字。它使用 SpEL 表達式根據#{@beanName}從 Spring 容器中獲取 Bean 對象。

IP限流

獲取請求用戶ip做爲限流key。

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

用戶限流

獲取請求用戶id做爲限流key。

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

接口限流

獲取請求地址的uri做爲限流key。

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

歡迎關注個人公衆號《程序員果果》,關注有驚喜~~
Spring Cloud Gateway 之 限流

相關文章
相關標籤/搜索