導讀:經過前面的章節咱們在微服務層作了限流,而且集成了SpringCloud Gateway,本章主要內容是將限流功能從微服務遷移到網關層。java
Springcloud Gateway 原生限流主要基於過濾器實現,咱們能夠直接使用內置的過濾器RequestRateLimiterGatewayFilterFactory
,目前RequestRateLimiterGatewayFilterFactory
的實現依賴於 Redis
,因此咱們還要引入spring-boot-starter-data-redis-reactive
。react
<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
配置Beanspring
/** * 自定義限流標誌的key,多個維度能夠從這裏入手 * exchange對象中獲取服務ID、請求信息,用戶信息等 */
@Bean
KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
複製代碼
咱們以前的章節已經講過Sentinel的使用方法,若是有不清楚的能夠翻看以前的章節,這裏主要說一下與SpringCloud gateway的整合。json
Sentinel從 1.6.0 版本開始提供了 Spring Cloud Gateway 的適配模塊,能夠提供兩種資源維度的限流:bootstrap
下面是咱們的整合步驟後端
<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-nacos
app
...
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-id
爲 gateway-sentinel-flow
的配置文件(json格式),給account-service
與product-service
添加限流規則。spring-boot
[
{
"resource": "account-service",
"count": 5,
"grade": 1,
"paramItem": {
"parseStrategy": 0
}
},
{
"resource": "product-service",
"count": 2,
"grade": 1,
"paramItem": {
"parseStrategy": 0
}
}
]
複製代碼
配置完成之後啓動網關項目,登陸sentinel控制檯,查看限流規則:
配置說明:
以客戶端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
方法接口
CustomGatewayBlockExceptionHandler
@Configuration
public class GatewayConfiguration {
...
/** * 注入自定義網關異常 */
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public CustomGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the custom block exception handler .
return new CustomGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
...
}
複製代碼
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 系列文章