物聯網架構成長之路(55)-Gateway+Sentinel實現限流、熔斷


0. 前言
  之前有一篇博客講到入門Sentinel,這次就將Sentinel引入到實際項目中進行演示。

1.啟動Sentinel
  具體可以參考這篇博客
  https://www.cnblogs.com/wunaozai/p/12404712.html

java -jar sentinel-dashboadr-1.7.1.jar --server.port=8858

  項目中pom.xml引入

 1         <dependency>
 2             <groupId>com.alibaba.cloud</groupId>
 3             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
 4         </dependency>
 5         <dependency>
 6             <groupId>com.alibaba.csp</groupId>
 7             <artifactId>sentinel-datasource-nacos</artifactId>
 8         </dependency>
 9         <dependency>
10             <groupId>com.alibaba.csp</groupId>
11             <artifactId>sentinel-transport-simple-http</artifactId>
12         </dependency>
13         <dependency>
14             <groupId>com.alibaba.csp</groupId>
15             <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
16         </dependency>

  以下配置追加到xxx-story-gateway-dev.properties的配置中,表示集成Sentinel

1 spring.cloud.sentinel.transport.dashboard=127.0.0.1:8858
2 spring.cloud.sentinel.datasource.ds.nacos.server-addr=127.0.0.1:8848
3 spring.cloud.sentinel.datasource.ds.nacos.data-id=gateway-sentinel.properties
4 spring.cloud.sentinel.datasource.ds.nacos.namespace=0e152861-1efa-62ea-9125-e569abc29691
5 spring.cloud.sentinel.datasource.ds.nacos.group-id=DEFAULT_GROUP
6 spring.cloud.sentinel.datasource.ds.nacos.data-type=json
7 spring.cloud.sentinel.datasource.ds.nacos.rule-type=flow

 

2. 動態修改Nacos上的Sentinel配置

 1 [
 2     {
 3         "resource": "/hello",
 4         "limitApp": "default",
 5         "grade": 1,
 6         "count": 5,
 7         "strategy": 0,
 8         "controlBehavior": 0,
 9         "clusterMode": false
10     },
11     {
12         "resource": "/aiml/v1/ai/chat",
13         "limitApp": "default",
14         "grade": 1,
15         "count": 2,
16         "strategy": 0,
17         "controlBehavior": 0,
18         "clusterMode": false
19     }
20 ]

 

3. 配置Sentinel Configuration
  在對流量進行限流和熔斷過程中,需要一些自定義操作。此時就需要增加一個GatewayConfiguration配置類。因為默認提示異常是【Blocked by Sentinel: FlowException】,所以最好是能,自定義異常提示。
  GatewayConfiguration.java

 1 package com.wunaozai.demo.story.gateway.config;
 2 
 3 import java.util.Collections;
 4 import java.util.List;
 5 
 6 import org.springframework.beans.factory.ObjectProvider;
 7 import org.springframework.cloud.gateway.filter.GlobalFilter;
 8 import org.springframework.context.annotation.Bean;
 9 import org.springframework.context.annotation.Configuration;
10 import org.springframework.core.Ordered;
11 import org.springframework.core.annotation.Order;
12 import org.springframework.http.codec.ServerCodecConfigurer;
13 import org.springframework.web.reactive.result.view.ViewResolver;
14 
15 import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
16 
17 @Configuration
18 public class GatewayConfiguration {
19 
20     private final List<ViewResolver> views;
21     private final ServerCodecConfigurer configurer;
22     
23     public GatewayConfiguration(ObjectProvider<List<ViewResolver>> views,
24             ServerCodecConfigurer config) {
25         this.views = views.getIfAvailable(Collections::emptyList);
26         this.configurer = config;
27     }
28     
29     /**
30      * 配置SentinelGatewayBlockExceptionHandler,限流后異常處理
31      * @return
32      */
33     @Bean
34     @Order(Ordered.HIGHEST_PRECEDENCE)
35     public JsonSentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
36         //return new SentinelGatewayBlockExceptionHandler(views, configurer);
37         return new JsonSentinelGatewayBlockExceptionHandler(views, configurer);
38     }
39     
40     /**
41      * Sentinel 過濾器
42      * @return
43      */
44     @Bean
45     @Order(-1)
46     public GlobalFilter sentinelGatewayFilter() {
47         return new SentinelGatewayFilter();
48     }
49     
50 }

  JsonSentinelGatewayBlockExceptionHandler.java

 1 package com.wunaozai.demo.story.gateway.config;
 2 
 3 import java.nio.charset.StandardCharsets;
 4 import java.util.List;
 5 
 6 import org.springframework.core.io.buffer.DataBuffer;
 7 import org.springframework.http.codec.HttpMessageWriter;
 8 import org.springframework.http.codec.ServerCodecConfigurer;
 9 import org.springframework.http.server.reactive.ServerHttpResponse;
10 import org.springframework.web.reactive.function.server.ServerResponse;
11 import org.springframework.web.reactive.result.view.ViewResolver;
12 import org.springframework.web.server.ServerWebExchange;
13 import org.springframework.web.server.WebExceptionHandler;
14 
15 import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
16 import com.alibaba.csp.sentinel.slots.block.BlockException;
17 import com.alibaba.csp.sentinel.util.function.Supplier;
18 
19 import reactor.core.publisher.Mono;
20 
21 /**
22  * Sentinel 限流后自定義異常
23  * @author wunaozai
24  * @Date 2020-03-17
25  */
26 public class JsonSentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
27 
28     private List<ViewResolver> viewResolvers;
29     private List<HttpMessageWriter<?>> messageWriters;
30 
31     public JsonSentinelGatewayBlockExceptionHandler(
32             List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
33         this.viewResolvers = viewResolvers;
34         this.messageWriters = serverCodecConfigurer.getWriters();
35     }
36     /**
37      * 自定義返回
38      * @param response
39      * @param exchange
40      * @return
41      */
42     private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
43         ServerHttpResponse resp = exchange.getResponse();
44         resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
45         String json = "{\"code\": -1, \"data\": null, \"msg\": \"系統限流\"}";
46         DataBuffer buffer = resp.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
47         return resp.writeWith(Mono.just(buffer));
48     }
49 
50     @Override
51     public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
52         if (exchange.getResponse().isCommitted()) {
53             return Mono.error(ex);
54         }
55         if (!BlockException.isBlockException(ex)) {
56             return Mono.error(ex);
57         }
58         return handleBlockedRequest(exchange, ex)
59             .flatMap(response -> writeResponse(response, exchange));
60     }
61     private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
62         return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
63     }
64     private final Supplier<ServerResponse.Context> contextSupplier = () -> new ServerResponse.Context() {
65         @Override
66         public List<HttpMessageWriter<?>> messageWriters() {
67             return JsonSentinelGatewayBlockExceptionHandler.this.messageWriters;
68         }
69         @Override
70         public List<ViewResolver> viewResolvers() {
71             return JsonSentinelGatewayBlockExceptionHandler.this.viewResolvers;
72         }
73     };
74 }


 

 

4. 熔斷機制
  上面介紹的是限流,可以從 spring.cloud.sentinel.datasource.ds.nacos.rule-type=flow 看出來。但是根據 org.springframework.cloud.alibaba.sentinel.datasource.RuleType 這個枚舉,Sentinel還提供了熔斷機制。

  修改之前的配置,增加多一個數據源,一個是限流,一個是熔斷

 1 #Sentinel
 2 spring.cloud.sentinel.transport.dashboard=127.0.0.1:8858
 3 spring.cloud.sentinel.datasource.ds1.nacos.server-addr=127.0.0.1:8848
 4 spring.cloud.sentinel.datasource.ds1.nacos.data-id=gateway-sentinel.properties
 5 spring.cloud.sentinel.datasource.ds1.nacos.namespace=0e152861-1efa-62ea-9125-e569abc29691
 6 spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
 7 spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
 8 spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow
 9 
10 spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
11 spring.cloud.sentinel.datasource.ds2.nacos.data-id=gateway-sentinel-degrade.properties
12 spring.cloud.sentinel.datasource.ds2.nacos.namespace=0e152861-1efa-62ea-9125-e569abc29691
13 spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP
14 spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
15 spring.cloud.sentinel.datasource.ds2.nacos.rule-type=degrade

  這個配置的意思是,如果請求xxx-story-res這個微服務是,當資源的平均響應時間超過閾值100ms后,資源進入准降級狀態。如果接下來1秒內持續進入多個請求的RT時間都持續超過這個閾值,那么在接下來的時間窗口(timeWindow)30(秒)之內。對該方法的調用都會自動熔斷。直接返回錯誤。這里會直接返回上面配置的 {"code": -1, "data": null, "msg": "系統限流"} 錯誤。

1 [
2   {
3     "resource": "xxx-story-res",
4     "count": 100,
5     "grade": 0,
6     "timeWindow": 30
7   }
8 ]

  現在測試,就是不斷的請求對應的接口,從圖中可以看到,每隔30秒,就會放一些請求到后面的服務。其他時間的請求,都是快速失敗。返回限流。

 

5. 附錄各個在Nacos上的配置 

 

參考資料:
  https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
  https://www.cnblogs.com/yinjihuan/p/10772558.html
  https://www.cnblogs.com/zhangpan1244/p/11228020.html

本文地址:https://www.cnblogs.com/wunaozai/p/12512850.html
本系列目錄: https://www.cnblogs.com/wunaozai/p/8067577.html
個人主頁:https://www.wunaozai.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM