SpringCloud Alibaba微服務實戰十二 - 網關限流

導讀:經過前面的章節咱們在微服務層作了限流,而且集成了SpringCloud Gateway,本章主要內容是將限流功能從微服務遷移到網關層。java

SpringCloud Gateway 原生限流

Springcloud Gateway 原生限流主要基於過濾器實現,咱們能夠直接使用內置的過濾器RequestRateLimiterGatewayFilterFactory,目前RequestRateLimiterGatewayFilterFactory的實現依賴於 Redis,因此咱們還要引入spring-boot-starter-data-redis-reactivereact

POM依賴

<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>
複製代碼

限流配置

spring:
 cloud:
 gateway:
 routes:
 - id: account-service
 uri: lb://account-service
 order: 10000
 predicates:
 - Path=/account-service/**
 filters:
 - name: RequestRateLimiter
 args:
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 3
 key-resolver: "#{@ipKeyResolver}" 
複製代碼

主要是配置三個主要參數:redis

  • redis-rate-limiter.replenishRate :
    容許用戶每秒處理多少個請求
  • redis-rate-limiter.burstCapacity :
    令牌桶的容量,容許在一秒鐘內完成的最大請求數
  • key-resolver :
    用於限流的鍵的解析器的 Bean 對象的名字。它使用 SpEL 表達式根據#{@beanName}從 Spring 容器中獲取 Bean 對象。

配置Beanspring

/** * 自定義限流標誌的key,多個維度能夠從這裏入手 * exchange對象中獲取服務ID、請求信息,用戶信息等 */
@Bean
KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
複製代碼

Sentinel 限流

咱們以前的章節已經講過Sentinel的使用方法,若是有不清楚的能夠翻看以前的章節,這裏主要說一下與SpringCloud gateway的整合。json

Sentinel從 1.6.0 版本開始提供了 Spring Cloud Gateway 的適配模塊,能夠提供兩種資源維度的限流:bootstrap

  • route 維度:即在 Spring 配置文件中配置的路由條目,資源名爲對應的 routeId自定義
  • API 維度:用戶能夠利用 Sentinel 提供的 API 來自定義一些 API 分組

下面是咱們的整合步驟後端

POM依賴

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
複製代碼

因爲須要使用 nacos做爲sentinel的配置中心,因此也引入了sentinel-datasource-nacosapp

Bootstrap配置

...
spring:
 cloud:
 sentinel:
 transport:
 dashboard: 10.0.10.48:8858
 eager: true
 datasource:
 ds:
 nacos:
 server-addr: 10.0.10.48:8848
 data-id: gateway-sentinel-flow
 group-id: DEFAULT_GROUP
 rule-type: gw-flow
...
複製代碼

這裏主要是sentinel的相關配置,從nacos配置中心獲取 gateway-sentinel-flow 配置文件,限流類型是網關類型gw-flow。ide

限流配置

在nacos配置管理public頁面創建 data-idgateway-sentinel-flow 的配置文件(json格式),給account-serviceproduct-service添加限流規則。spring-boot

[
  {
    "resource": "account-service",
    "count": 5,
    "grade": 1,
    "paramItem": {
        "parseStrategy": 0
    }
  },
  {
    "resource": "product-service",
    "count": 2,
    "grade": 1,
    "paramItem": {
        "parseStrategy": 0
    }
  }
]
複製代碼

配置完成之後啓動網關項目,登陸sentinel控制檯,查看限流規則:

image.png

配置說明:

以客戶端IP做爲限流因子
public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;
以客戶端HOST做爲限流因子
public static final int PARAM_PARSE_STRATEGY_HOST = 1;
以客戶端HEADER參數做爲限流因子
public static final int PARAM_PARSE_STRATEGY_HEADER = 2;
以客戶端請求參數做爲限流因子
public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;
以客戶端請求Cookie做爲限流因子
public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;
複製代碼

限流測試

屢次經過網關訪問account-service服務進行測試 http://localhost:8090/account/getByCode/javadaily 查看限流效果:

自定義響應異常

SpringCloud-gateway限流異常默認的實現邏輯爲SentinelGatewayBlockExceptionHandler,能夠查看源碼發現異常響應的關鍵代碼以下

因爲服務後端都是返回JSON的響應格式,因此咱們須要修改原異常響應,將其修改爲ResultData類的響應格式。要實現這個功能只須要寫個新的異常處理器而後在SpringCloud GateWay配置類中注入新的異常處理器便可。

  • 自定義異常處理器CustomGatewayBlockExceptionHandler
public class CustomGatewayBlockExceptionHandler implements WebExceptionHandler {
	...
    /** * 重寫限流響應,改形成JSON格式的響應數據 * @author javadaily * @date 2020/1/20 15:03 */
    private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
        ServerHttpResponse serverHttpResponse = exchange.getResponse();
        serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        ResultData<Object> resultData = ResultData.fail(ReturnCode.RC200.getCode(), ReturnCode.RC200.getMessage());
        String resultString = JSON.toJSONString(resultData);
        DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(resultString.getBytes());
        return serverHttpResponse.writeWith(Mono.just(buffer));
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        } else {
            return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> this.writeResponse(response, exchange));
        }
    }
   ...
}
複製代碼

你們能夠直接複製 SentinelGatewayBlockExceptionHandler 類,而後修改 writeResponse方法接口

  • 修改Gateway配置類,注入CustomGatewayBlockExceptionHandler
@Configuration
public class GatewayConfiguration {
	...
    /** * 注入自定義網關異常 */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public CustomGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the custom block exception handler .
        return new CustomGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
	...
}
複製代碼
  • 在bootstrap.yml文件中新增配置
spring:
 main:
 allow-bean-definition-overriding: true
複製代碼
  • 從新測試,限流響應結果以下
{
	"message": "服務開啓限流保護,請稍後再試!",
	"status": 200,
	"success": false,
	"timestamp": 1579509123946
}
複製代碼

限流不生效

各位在使用過程當中若是發現網關層限流不生效,能夠以debug模式啓動網關服務,而後對網關過濾器 SentinelGatewayFilter 中的filter方法進行調試,我發現sentinel獲取到的網關id並非咱們配置的account-service,而是加了CompositeDiscoveryClient_前綴,以下圖所示:

因此咱們須要修改 gateway-sentinel-flow 的配置,給咱們的resource 也加上前綴,修改完的配置以下:

[{
	"resource": "CompositeDiscoveryClient_account-service",
	"count": 5,
	"grade": 1,
	"paramItem": {
		"parseStrategy": 0
	}
}, {
	"resource": "CompositeDiscoveryClient_product-service",
	"count": 2,
	"grade": 1,
	"paramItem": {
		"parseStrategy": 0
	}
}]
複製代碼

經過使用jemter對接口進行測試,發現網關能正常限流

通過以上幾步,咱們能夠將後端微服務層的限流配置去掉,讓網關層承擔限流的功能。

好了,各位朋友們,本期的內容到此就所有結束啦,能看到這裏的同窗都是優秀的同窗,下一個升職加薪的就是你了! 若是以爲這篇文章對你有所幫助的話請掃描下面二維碼加個關注。

"轉發" 加 "在看",養成好習慣!我們下期再見!

SpringCloud Alibaba 系列文章

相關文章
相關標籤/搜索