網關限流介紹及實現

網關可以做很多的事情,比如,限流,當我們的系統被頻繁的請求的時候,就有可能 將系統壓垮,所以 爲了解決這個問題,需要在每一個微服務中做限流操作,但是如果有了網關,那麼就可以在網關係統做限流,因爲所有的請求都需要先通過網關係統才能路由到微服務中。


令牌桶算法

令牌桶算法是比較常見的限流算法之一,大概描述如下:

1)所有的請求在處理之前都需要拿到一個可用的令牌纔會被處理;

2)根據限流大小,設置按照一定的速率往桶裏添加令牌;

3)桶設置最大的放置令牌限制,當桶滿時、新添加的令牌就被丟棄或者拒絕;

4)請求達到後首先要獲取令牌桶中的令牌,拿着令牌纔可以進行其他的業務邏輯,處理完業務邏輯之後,將令牌直接刪除;

5)令牌桶有最低限額,當桶中的令牌達到最低限額的時候,請求處理完之後將不會刪除令牌,以此保證足夠的限流

如下圖:



這個算法的實現,有很多技術,Guaua是其中之一,redis客戶端也有其實現。

網關限流代碼實現

(1)spring cloud gateway 默認使用redis的RateLimter限流算法來實現。所以我們要使用首先需要引入redis的依賴 (這裏需要使用響應式的redis依賴spring-boot-starter-data-redis-reactive)

<dependencies>
        <!--網管-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
        <!--熔斷器-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
        <!--eureka客戶端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
        <!--redis用於實現限流-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>
   </dependencies>

(2)定義KeyResolver

在GatewayApplicatioin引導類中添加如下代碼,KeyResolver用於計算某一個類型的限流的KEY也就是說,可以通過KeyResolver來指定限流的Key。

package com.changgou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author :gzy
 * @date :Created in 2019/8/15
 * @description :
 * @version: 1.0
 */
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class);
    }
    @Bean
    //KeyResolver用於計算某一個類型的限流的KEY也就是說,可以通過KeyResolver來指定限流的Key。
    public KeyResolver ipKeyResolver(){
        return new KeyResolver() {
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
            }
        };
    }
}

(3)application.yml配置

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      #與微服務名稱對應
      - id: goods
      # 路由地址(轉發地址),這裏根據服務名稱,採用lb協議,會從Eureka註冊中心獲取服務請求地址
      # 路由地址如果通過lb協議加服務名稱時,會自動使用負載均衡訪問對應服務
      # 規則:lb協議+服務名稱
        uri: lb://goods
        predicates:
        # 路由攔截地址(斷言),請求路徑要加goods,後面攔截器會自動去掉
        - Path=/goods/**
        #訪問地址自動去掉一個前綴
        filters:
        - StripPrefix= 1
      - id: system
        uri: lb://system
        predicates:
        - Path=/system/**
        filters:
        - StripPrefix= 1
        - name: RequestRateLimiter #請求數限流 名字不能隨便寫
          args:
           key-resolver: "#{@ipKeyResolver}"
           redis-rate-limiter.replenishRate: 1 #同一個IP在一秒中只能訪問一次
           redis-rate-limiter.burstCapacity: 1 #在突發情況下 一個IP在一秒中只能訪問一次
  redis:
    host: 192.168.200.128
server:
  port: 9101
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true

解釋:

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

通過在replenishRate和中設置相同的值來實現穩定的速率burstCapacity。設置burstCapacity高於時,可以允許臨時突發replenishRate。在這種情況下,需要在突發之間允許速率限制器一段時間(根據replenishRate),因爲2次連續突發將導致請求被丟棄(HTTP 429 - Too Many Requests)

key-resolver: "#{@userKeyResolver}" 用於通過SPEL表達式來指定使用哪一個KeyResolver.

如上配置:

表示 一秒內,允許 一個請求通過,令牌桶的填充速率也是一秒鐘添加一個令牌。

最大突發狀況 也只允許 一秒內有一次請求,可以根據業務來調整 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章