Gateway整合Sentinel
? 前面使用過Sentinel組件對(duì)服務(wù)提供者、服務(wù)消費(fèi)者進(jìn)行流控、限流等操作。除此之外,Sentinel還支持對(duì)Gateway、Zuul等主流網(wǎng)關(guān)進(jìn)行限流。
? 自sentinel1.6.0版開始,Sentinel提供了Gateway的適配模塊,能針對(duì)路由(route)和自定義API分組兩個(gè)維度進(jìn)行限流。
路由維度
路由維度是指配置文件中的路由條目,資源名是對(duì)應(yīng)的routeId,相比自定義API維度,這是比較粗粒度的??聪氯绾螌?shí)現(xiàn):
-
導(dǎo)入Sentinel組件為Gateway提供的適配依賴包,在pom.xml中導(dǎo)入依賴
<!--sentinel為gateway提供的適配包--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>
-
增加配置類
SentinelRouteConfiguration
,實(shí)例化SentinelGatewayFilter
和SentinelBlockExceptionHandler
對(duì)象,初始化限流規(guī)則@Configuration // 配置類 public class SentinelRouteConfiguration { // 路由限流規(guī)則配置類 private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public SentinelRouteConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } @PostConstruct public void initGatewayRules() { // 初始化限流規(guī)則 Set<GatewayFlowRule> rules = new HashSet<>(); GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("user_route"); // 資源名(gateway中的路由id) gatewayFlowRule.setCount(1); // 限流閾值 gatewayFlowRule.setIntervalSec(1); // 統(tǒng)計(jì)時(shí)間窗口,默認(rèn)1s rules.add(gatewayFlowRule); GatewayRuleManager.loadRules(rules); // 載入規(guī)則 } @PostConstruct public void initBlockHandlers() { // 限流后的響應(yīng) BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> { Map<String, Object> result = new HashMap<>(); result.put("code", "0"); result.put("message", "您已被限流"); return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(result)); }; GatewayCallbackManager.setBlockHandler(blockRequestHandler); // 設(shè)置限流響應(yīng) } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { // 初始化限流過濾器 return new SentinelGatewayFilter(); } }
注意:Gateway限流是通過Filter實(shí)現(xiàn)的,主要是注入SentinelGatewayFilter實(shí)例和SentinelGatewayBlockExceptionHandler實(shí)例
-
在yml中,設(shè)置兩個(gè)route,
user_route
和shop_route
,上面主要是對(duì)user_route
限流了,著重看下server: port: 8083 spring: application: name: gateway # 服務(wù)名 cloud: nacos: discovery: server-addr: localhost:8848 # nacos地址 gateway: routes: # 路由,可配置多個(gè) - id: user_route # 路由id,唯一即可,默認(rèn)UUID uri: lb://user # 路由地址(匹配成功后的服務(wù)地址) user是用戶服務(wù)的服務(wù)名稱 order: 1 # 路由優(yōu)先級(jí),默認(rèn)0,越低優(yōu)先級(jí)越高 predicates: - Path=/user/** # 斷言,匹配規(guī)則 - id: shop_route # 路由id,唯一即可,默認(rèn)UUID uri: lb://shop # 路由地址(匹配成功后的服務(wù)地址) shop是用戶服務(wù)的服務(wù)名稱 order: 1 # 路由優(yōu)先級(jí),默認(rèn)0,越低優(yōu)先級(jí)越高 predicates: - Path=/shop/** # 斷言,匹配規(guī)則
-
啟動(dòng)服務(wù)開始調(diào)試
成功完成路由級(jí)別的限流,那么后面看看
API維度
的限流
自定義API維度
? 上面那種限流方式可以看出靈活性不夠高。自定義的API維度可以利用Sentinel提供的API自定義分組來進(jìn)行限流。相比路由維度,這是一種更加細(xì)粒度的限流方式。
實(shí)現(xiàn)
-
導(dǎo)入Gateway的適配包
<!--sentinel為gateway提供的適配包--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>
-
依然是實(shí)例化
SentinelGatewayFilter
和SentinelBlockExceptionHandler
對(duì)象,初始化限流規(guī)則,定義API分組@Configuration // 配置類 public class SentinelRouteConfiguration { // 路由限流規(guī)則配置類 private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public SentinelRouteConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } @PostConstruct public void initGatewayRules() { // 初始化限流規(guī)則 Set<GatewayFlowRule> rules = new HashSet<>(); GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("user_api"); // 資源名,api分組的名稱(自定義) gatewayFlowRule.setCount(1); // 限流閾值 gatewayFlowRule.setIntervalSec(1); // 統(tǒng)計(jì)時(shí)間窗口,默認(rèn)1s rules.add(gatewayFlowRule); GatewayRuleManager.loadRules(rules); // 載入規(guī)則 } @PostConstruct public void initCustomizedApis() { Set<ApiDefinition> apiDefinitions = new HashSet<>(); ApiDefinition apiDefinition = new ApiDefinition("user_api") // 定義 api分組 .setPredicateItems(new HashSet<ApiPredicateItem>() {{ add(new ApiPathPredicateItem() .setPattern("/user/group/**") // 路徑匹配規(guī)則 .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); // 匹配策略,前綴匹配 }}); apiDefinitions.add(apiDefinition); GatewayApiDefinitionManager.loadApiDefinitions(apiDefinitions); // 載入API分組定義 } @PostConstruct public void initBlockHandlers() { // 限流后的響應(yīng) BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> { Map<String, Object> result = new HashMap<>(); result.put("code", "0"); result.put("message", "您已被限流"); return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(result)); }; GatewayCallbackManager.setBlockHandler(blockRequestHandler); // 設(shè)置限流響應(yīng) } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { // 初始化限流過濾器 return new SentinelGatewayFilter(); } }
唯一要注意的是:路由匹配規(guī)則如果是單一的一個(gè)具體接口,不是匹配符,那么后面的匹配策略就沒有必要再去配置了(setMatchStrategy()方法)
-
定義一個(gè)
/user/group/findById
接口@RequestMapping("/user/group/findById") public String findGById(@RequestParam("id") Integer id) { return userInfo.getOrDefault(id, null); }
-
啟動(dòng)調(diào)用測(cè)試
可以看到配置的沒有問題,滿足
/user/group/**
規(guī)則的請(qǐng)求,有被限流到
超時(shí)配置
Gateway默認(rèn)沒有超時(shí)的限制,也就是數(shù)據(jù)什么時(shí)候返回,就等待到什么時(shí)候。如果不想等待,可以增加對(duì)超時(shí)的配置
gateway:
httpclient:
connect-timeout: 5000 # 建立連接時(shí)間限制,單位毫秒
response-timeout: 4s # 響應(yīng)時(shí)間的時(shí)間限制
嘗試下,接口睡眠5s,再次調(diào)用
curl localhost:8083/user/group/findById?id=1
{"timestamp":"2023-09-02T00:59:47.184+00:00","path":"/user/group/findById","status":504,"error":"Gateway Timeout","requestId":"7f5ff558-1"}
被告知504,超時(shí)了~
CORS配置
涉及到前后端分離的跨域請(qǐng)求時(shí),瀏覽器訪問后端地址通常提示No Access-Control-Allow-Origin header is present on the requested resource
可以在gateway中增加跨域配置,或者前端去配置都可以,自行協(xié)商。文章來源:http://www.zghlxwxcb.cn/news/detail-691629.html
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos地址
gateway:
httpclient:
connect-timeout: 5000 # 建立連接時(shí)間限制,單位毫秒
response-timeout: 4s # 響應(yīng)時(shí)間的時(shí)間限制
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*" # 允許的來源
allowedMethods: "*" # 允許的方法
allowedHeaders: "*" # 允許的請(qǐng)求頭 *表示所有
通常情況下,也可以不是按照全部允許來做,按照你的項(xiàng)目實(shí)際開發(fā)需求搞就行了。文章來源地址http://www.zghlxwxcb.cn/news/detail-691629.html
到了這里,關(guān)于SpringCloudAlibaba Gateway(三)-整合Sentinel功能路由維度、API維度進(jìn)行流控的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!