Spring Cloud Gateway限制API速率 - tanzu

banq發表於2021-04-27

軟體架構師的當務之急之一是保護API和服務端點免受有害事件(例如拒絕服務攻擊,級聯故障或資源過度使用)的危害。速率限制是一種用於控制使用API​​或服務的速率的技術,它反過來可以保護您免受可能導致服務突然停止的這些事件的侵害。在分散式系統中,沒有比集中配置和管理使用者與API互動的速率更好的選擇了。只有在規定速率內的那些請求才可以進入API。否則將返回HTTP 429(“請求過多”)錯誤。

Spring Cloud Gateway是一個簡單輕巧的元件,可用於限制API使用率。
在原始的Spring Boot應用程式中包括Spring Boot Cloud依賴項:org.springframework.cloud:spring-cloud-starter-gateway,無需任何程式碼即可在架構中包含Spring Cloud Gateway。
可以使用配置的路由定義將Spring Cloud Gateway從前端服務接收到的請求路由到後端服務,這將使閘道器清楚地知道應如何將請求路由到後端端點。路由配置通常基於可從HTTP請求中提取的資訊(例如路徑和標頭)來定義條件。
下面的程式碼段列出了一個YAML節,用於配置將請求路由到後端服務的條件;它表明當路徑中用“ / backend”命中閘道器時,請求應該以後端服務為目標。在配置中,為路由提供了一個識別符號和後端服務URL。

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend

 

RequestRateLimiter定義key
RequestRateLimiter是Spring Cloud Gateway提供的眾多閘道器過濾器之一;它確定是允許進行請求還是已超過請求的限制。它還允許您(可選)插入key以限制對不同服務的請求數量。
在實現如何自定義key解析的同時,閘道器附帶了一個利用使用者Principal名的閘道器。需要一個安全的閘道器來解析使用者的主體名稱,但是您可以選擇實現該KeyResolver介面以代替解析來自ServerWebExchange不同的key。
您可以使用表示式(例如,名為customKeyResolver)SPEL #{@customKeyResolver}指向配置中的自定義KeyResolverbean。下面顯示了KeyResolver介面:

public interface KeyResolver {
    Mono<String> resolve(ServerWebExchange exchange);
}

如果沒有key,閘道器將拒絕請求。要讓閘道器不解析key,可以設定以下屬性:

spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key=false

您還可以透過設定以下屬性,指定閘道器在找不到key時應報告的狀態程式碼:

spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code=
 

速率限制器
假設閘道器透過使用Redis控制API消耗的限制。Redis使用令牌桶演算法。要啟用它,您需要在閘道器應用程式中包括Spring Boot啟動程式依賴項spring-boot-starter-data-redis。
基本上,令牌桶演算法使用餘額令牌作為維持累積使用預算的一種方式。該演算法假定令牌將以一定速率新增到儲存桶中,而對API的呼叫會消耗儲存桶中的令牌。一個API呼叫可以執行許多操作,以便組成一個響應,從而滿足請求(基於GraphQL的API的想法)。在這種情況下,該演算法可幫助Spring Cloud Gateway識別出一次呼叫可能花費一個API多個令牌。
提供的Redis實現使您可以定義請求速率,使用者可以在特定時間段內以該速率進行呼叫。這也使得有可能適應零散的需求,同時受到定義的消耗率的限制。
例如,配置可以透過設定redis-rate-limiter.replenishRate=500屬性來定義每秒500個請求的補充速率,並且可以透過設定屬性redis-rate-limiter.burstCapacity=1000來定義每秒1,000個請求的突發容量。這樣先會將消耗限制為每秒500個請求,如果請求數量突然增加,則僅允許1,000個請求。但是,由於這超出了我們定義的每秒500個請求的限制,因此閘道器將在下一秒才會路由其他500個請求。
該配置還允許您透過設定屬性redis-rate-limiter.requestedTokens來定義一個請求將花費多少個令牌。通常,它設定為1。
要使用具有請求限制功能的閘道器,需要使用RequestRateLimiter閘道器過濾器對其進行配置。該配置可以指定引數來定義補充率,突發容量和請求花費的令牌數量。下面的示例說明了如何使用這些引數配置閘道器:

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend
          filters:
          - name: RequestRateLimiter
            args:
              redis-rate-limiter.replenishRate: 500
              redis-rate-limiter.burstCapacity: 1000
              redis-rate-limiter.requestedTokens: 1


Spring Cloud Gateway可以靈活地定義您自己的自定義速率限制器實現;它提供了一個RateLimiter實現和定義bean的介面。可以使用SPEL表示式來配置速率限制器bean ,就像在自定義key解析器中一樣。
例如,您可以定義一個名為beancustomRateLimiter的自定義速率限制器和一個名為customKeyResolver的自定義金鑰解析器,並配置如下所示的路由:

@Bean
public KeyResolver customKeyResolver {
    return exchange -> ....  // returns a Mono of String
}
spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend
          filters:
          - name: RequestRateLimiter
            args:
              rate-limiter: "#{customRateLimiter}"
              key-resolver: "#{customKeyResolver}"


GitHub找到程式碼。

相關文章