当前位置:   article > 正文

SpringCloud Alibaba Sentinel 使用方式及限流规则持久化_spring-cloud-alibaba-sentinel-gateway使用

spring-cloud-alibaba-sentinel-gateway使用

目录

一、SpringCloud Alibaba Sentinel 概述及控制台的搭建

1、SpringCloud Alibaba Sentinel 概述

2、Sentinel 控制台的搭建

2.1、下载地址

2.2、启动sentinel

2.3、访问sentinel

3、 SpringCloud Alibaba Sentinel 控制台有哪些能力

4、常见的限流方案

5、流控规则高级说明

5.1、流控模式

5.2、流控效果

二、项目中使用sentinel的限流功能 

1、添加依赖

2、yml配置(spring:cloud下)

3、编写限流controller接口

4、编写自定义通用的限流处理逻辑

三、使用sentinel 保护 RestTemplate 服务间调用

1、配置RestTemplate 

1.1、yml配置文件配置

1.2、代码配置

2、配置服务异常降级之后的处理方法和限流后的处理方法

3、使用 Sentinel 保护 RestTemplate 服务间调用

四、使用sentinel 对 fegin 熔断降级支持

1、配置fegin

2、编写fegin client 

3、编写Sentinel 对 OpenFeign 接口的降级策略

4、编写controller测试使用fegin的熔断降级

五、使用sentinel 对 RestTemplate 熔断降级支持 

1、编写服务熔断降级后的策略(controller中fallback中的方法和类中的方法参数必须一致)

2、编写controller测试使用RestTemplate的熔断降级

五、Sentinel 结合 Nacos 实现限流规则持久化

1、SpringCloud Alibaba Sentinel 配置信息

2、 整合nacos实现限流规则持久化

2.1、添加依赖

2.2、编写限流接口

2.3、yml配置(spring:cloud下)

2.4、在nacos上编写指定限流接口的配置

3、 整合nacos实现熔断规则持久化

3.1、添加依赖

3.2、yml配置

3.3、在nacos上编写熔断规则。

3.4、熔断策略讲解

 3.5、编写fegin client 

3.6、编写Sentinel 对 OpenFeign 接口的降级策略

3.7、编写controller测试使用fegin的熔断降级

六、Gateway集成Sentinel实现网关限流(不论那种方式硬编码中的样板代码必须添加在Gateway)

1、引入依赖

2、编写配置文件(spring:cloud下)

3、硬编码方式实现

4、本地文件方式实现

4.1、编写路由规则

4.2、编写路由规则分组 

4.3、编写配置文件

5、nacos方式实现

 5.1、nacos上编写路由规则

5.2、nacos上编写路由规则分组 

5.3、编写yml配置文件


一、SpringCloud Alibaba Sentinel 概述及控制台的搭建

1、SpringCloud Alibaba Sentinel 概述

2、Sentinel 控制台的搭建

2.1、下载地址

        Releases · alibaba/Sentinel · GitHub

2.2、启动sentinel

  1. java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:77
  2. 77 -Dproject.name=zhangkechen-sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar

2.3、访问sentinel

地址:http://localhost:7777/

3、 SpringCloud Alibaba Sentinel 控制台有哪些能力

4、常见的限流方案

  • 静态窗口限流(每个自然秒中可接受的请求数量,0-1,1-2,不能解决突发的问题)
  • 动态窗口限流(滑动窗口,比如现在2.5秒,他计算的范围为1.5-2.5秒,不能解决突发的问题)
  • 漏桶限流(把请求放到桶(队列)里面,规定一秒钟消费多少个请求,桶有上线,超过容量全部拒绝)
  • 令牌桶限流(桶中放令牌,有上线,进:某个程序定时给桶中生成令牌,生成是会判断桶是否达到上限,请求进来后拿到令牌执行业务,否则失败。)
  • 令牌大闸:(开始时就初始化令牌个数,请求进来后拿到令牌执行业务,否则失败。)

5、流控规则高级说明

5.1、流控模式

  • 直接:默认,指的是直接对当前资源做限流。
  • 关联:对目标的限流是有条件的,需要关联的资源限流时,目标才会限流。两个接口的关联是实时的,当关联的资源限流时,目标资源同步开启限流。
  • 链路:当入口资源为配置的资源名称进来的请求,才会开始目标资源的限流。需要在配置文件配置Sping.cloud.sentinel.web-context-unify=false。流控模式时链路时必须关闭这个开关,默认是true,为true时可以在控制台-簇点链路界面看到所有请求都在一个链路下面。

5.2、流控效果

  • 快速失败-》表示达到单机阈值的话直接拒绝请求。
  • Warm Up-》预热,规则是coldFactor为3,即请求QPS从(闽值 /3)开始,经多少预热时长才逐渐升至设定的QPS闽值,假设单机阈值为100,预热时长为10,则表示从33开始经过十秒上升到100。
  • 排队等待-》编写等待时长,单位毫秒。假设单机阈值为10,等待时长为500,当进来100个请求是,90个是等待状态,这些请求等待500毫秒,在500毫秒内如果满足单机阀值的要求(单机阀值小于10),就可以执行,否则拒绝。

二、项目中使用sentinel的限流功能 

1、添加依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>

2、yml配置(spring:cloud下)

  1. sentinel:
  2. # 配置 sentinel dashboard 地址
  3. transport:
  4. dashboard: 127.0.0.1:7777
  5. port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
  6. # 服务启动直接建立心跳连接
  7. eager: true
  8. datasource:

3、编写限流controller接口

  1. /**
  2. * <h1>基于 Sentinel 控制台配置流控规则</h1>
  3. * Sentinel 是懒加载的, 先去访问一下, 就可以在 Sentinel Dashboard 看到了
  4. * */
  5. @Slf4j
  6. @RestController
  7. @RequestMapping("/dashboard")
  8. public class RateLimitController {
  9. /**
  10. * <h2>在 dashboard 中 "流控规则" 中按照资源名称新增流控规则</h2>
  11. * */
  12. @GetMapping("/by-resource")
  13. @SentinelResource(
  14. value = "byResource",
  15. blockHandler = "qinyiHandleBlockException",
  16. blockHandlerClass = QinyiBlockHandler.class
  17. )
  18. public CommonResponse<String> byResource() {
  19. log.info("coming in rate limit controller by resource");
  20. return new CommonResponse<>(0, "", "byResource");
  21. }
  22. /**
  23. * <h2>在 "簇点链路" 中给 url 添加流控规则</h2>
  24. * */
  25. @GetMapping("/by-url")
  26. @SentinelResource(value = "byUrl")
  27. public CommonResponse<String> byUrl() {
  28. log.info("coming in rate limit controller by url");
  29. return new CommonResponse<>(0, "", "byUrl");
  30. }
  31. }

4、编写自定义通用的限流处理逻辑

  1. /**
  2. * <h1>自定义通用的限流处理逻辑</h1>
  3. * */
  4. @Slf4j
  5. public class QinyiBlockHandler {
  6. /**
  7. * <h2>通用限流处理方法</h2>
  8. * 这个方法必须是 static 的
  9. * */
  10. public static CommonResponse<String> qinyiHandleBlockException(BlockException exception) {
  11. log.error("trigger qinyi block handler: [{}], [{}]",
  12. JSON.toJSONString(exception.getRule()), exception.getRuleLimitApp());
  13. return new CommonResponse<>(
  14. -1,
  15. "flow rule trigger block exception",
  16. null
  17. );
  18. }
  19. }

三、使用sentinel 保护 RestTemplate 服务间调用

1、配置RestTemplate 

1.1、yml配置文件配置

  1. # 开启或关闭 @SentinelRestTemplate 注解
  2. resttemplate:
  3. sentinel:
  4. enabled: true

1.2、代码配置

  1. /**
  2. * <h1>开启服务间的调用保护, 需要给 RestTemplate 做一些包装</h1>
  3. * */
  4. @Slf4j
  5. @Configuration
  6. public class SentinelConfig {
  7. /**
  8. * <h2>包装 RestTemplate</h2>
  9. * */
  10. @Bean
  11. @SentinelRestTemplate(
  12. fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class,
  13. blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class
  14. )
  15. public RestTemplate restTemplate() {
  16. return new RestTemplate(); // 可以对其做一些业务相关的配置
  17. }
  18. }

2、配置服务异常降级之后的处理方法和限流后的处理方法

  1. /**
  2. * <h1>RestTemplate 在限流或异常时的兜底方法</h1>
  3. * */
  4. @Slf4j
  5. public class RestTemplateExceptionUtil {
  6. /**
  7. * <h2>限流后的处理方法</h2>
  8. * */
  9. public static SentinelClientHttpResponse handleBlock(HttpRequest request,
  10. byte[] body,
  11. ClientHttpRequestExecution execution,
  12. BlockException ex) {
  13. log.error("Handle RestTemplate Block Exception: [{}], [{}]",
  14. request.getURI().getPath(), ex.getClass().getCanonicalName());
  15. return new SentinelClientHttpResponse(
  16. JSON.toJSONString(new JwtToken("qinyi-imooc-block"))
  17. );
  18. }
  19. /**
  20. * <h2>异常降级之后的处理方法</h2>
  21. * */
  22. public static SentinelClientHttpResponse handleFallback(HttpRequest request,
  23. byte[] body,
  24. ClientHttpRequestExecution execution,
  25. BlockException ex) {
  26. log.error("Handle RestTemplate Fallback Exception: [{}], [{}]",
  27. request.getURI().getPath(), ex.getClass().getCanonicalName());
  28. return new SentinelClientHttpResponse(
  29. JSON.toJSONString(new JwtToken("qinyi-imooc-block"))
  30. );
  31. }
  32. }

3、使用 Sentinel 保护 RestTemplate 服务间调用

  1. /**
  2. * <h1>使用 Sentinel 保护 RestTemplate 服务间调用</h1>
  3. * */
  4. @Slf4j
  5. @RestController
  6. @RequestMapping("/sentinel-rest-template")
  7. public class SentinelRestTemplateController {
  8. private final RestTemplate restTemplate;
  9. public SentinelRestTemplateController(RestTemplate restTemplate) {
  10. this.restTemplate = restTemplate;
  11. }
  12. /**
  13. * <h2>从授权服务中获取 JwtToken</h2>
  14. * 1. 流控降级:
  15. * 是针对于簇点链路中的 http://127.0.0.1:7000/ecommerce-authority-center/authority/token
  16. * 2. 容错降级: 对于服务不可用时不能生效
  17. * */
  18. @PostMapping("/get-token")
  19. public JwtToken getTokenFromAuthorityService(
  20. @RequestBody UsernameAndPassword usernameAndPassword) {
  21. String requestUrl =
  22. "http://127.0.0.1:7000/ecommerce-authority-center/authority/token";
  23. log.info("RestTemplate request url and body: [{}], [{}]",
  24. requestUrl, JSON.toJSONString(usernameAndPassword));
  25. HttpHeaders headers = new HttpHeaders();
  26. headers.setContentType(MediaType.APPLICATION_JSON);
  27. return restTemplate.postForObject(
  28. requestUrl,
  29. new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
  30. JwtToken.class
  31. );
  32. }
  33. }

四、使用sentinel 对 fegin 熔断降级支持

1、配置fegin

  1. # 打开 Sentinel 对 Feign 的支持
  2. feign:
  3. sentinel:
  4. enabled: true
  5. spring:
  6. cloud:
  7. openfeign:
  8. lazy-attributes-resolution: true

2、编写fegin client 

  1. /**
  2. * <h1>通过 Sentinel 对 OpenFeign 实现熔断降级</h1>
  3. * */
  4. @FeignClient(
  5. value = "e-commerce-imooc",
  6. fallback = SentinelFeignClientFallback.class
  7. )
  8. public interface SentinelFeignClient {
  9. @RequestMapping(value = "qinyi", method = RequestMethod.GET)
  10. CommonResponse<String> getResultByFeign(@RequestParam Integer code);
  11. }

3、编写Sentinel 对 OpenFeign 接口的降级策略

  1. /**
  2. * <h1>Sentinel 对 OpenFeign 接口的降级策略</h1>
  3. * */
  4. @Slf4j
  5. @Component
  6. public class SentinelFeignClientFallback implements SentinelFeignClient {
  7. @Override
  8. public CommonResponse<String> getResultByFeign(Integer code) {
  9. log.error("request supply for test has some error: [{}]", code);
  10. return new CommonResponse<>(
  11. -1,
  12. "sentinel feign fallback",
  13. "input code: "+ code
  14. );
  15. }
  16. }

4、编写controller测试使用fegin的熔断降级

  1. /**
  2. * <h1>OpenFeign 集成 Sentinel 实现熔断降级</h1>
  3. * */
  4. @Slf4j
  5. @RestController
  6. @RequestMapping("/sentinel-feign")
  7. public class SentinelFeignController {
  8. private final SentinelFeignClient sentinelFeignClient;
  9. public SentinelFeignController(SentinelFeignClient sentinelFeignClient) {
  10. this.sentinelFeignClient = sentinelFeignClient;
  11. }
  12. /**
  13. * <h2>通过 Feign 接口去获取结果</h2>
  14. * */
  15. @GetMapping("/result-by-feign")
  16. public CommonResponse<String> getResultByFeign(@RequestParam Integer code) {
  17. log.info("coming in get result by feign: [{}]", code);
  18. return sentinelFeignClient.getResultByFeign(code);
  19. }
  20. }

五、使用sentinel 对 RestTemplate 熔断降级支持 

1、编写服务熔断降级后的策略(controller中fallback中的方法和类中的方法参数必须一致)

  1. /**
  2. * <h1>Sentinel 回退降级的兜底策略</h1>
  3. * 都需要是静态方法 fallback中的方法和类中的方法参数必须一致
  4. * */
  5. @Slf4j
  6. public class QinyiFallbackHandler {
  7. /**
  8. * <h2>getTokenFromAuthorityService 方法的 fallback</h2>
  9. * */
  10. public static JwtToken getTokenFromAuthorityServiceFallback(
  11. UsernameAndPassword usernameAndPassword
  12. ) {
  13. log.error("get token from authority service fallback: [{}]",
  14. JSON.toJSONString(usernameAndPassword));
  15. return new JwtToken("imooc-qinyi-fallback");
  16. }
  17. /**
  18. * <h2>ignoreException 方法的 fallback</h2>
  19. * */
  20. public static JwtToken ignoreExceptionFallback(Integer code) {
  21. log.error("ignore exception input code: [{}] has trigger exception", code);
  22. return new JwtToken("imooc-qinyi-fallback");
  23. }
  24. }

2、编写controller测试使用RestTemplate的熔断降级

  1. package com.imooc.ecommerce.controller;
  2. import com.alibaba.csp.sentinel.annotation.SentinelResource;
  3. import com.alibaba.fastjson.JSON;
  4. import com.imooc.ecommerce.fallback_handler.QinyiFallbackHandler;
  5. import com.imooc.ecommerce.vo.JwtToken;
  6. import com.imooc.ecommerce.vo.UsernameAndPassword;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.http.HttpEntity;
  9. import org.springframework.http.HttpHeaders;
  10. import org.springframework.http.MediaType;
  11. import org.springframework.web.bind.annotation.*;
  12. import org.springframework.web.client.RestTemplate;
  13. /**
  14. * <h1>Sentinel 提供容错降级的功能 服务未启动(容错了)</h1>
  15. * */
  16. @SuppressWarnings("all")
  17. @Slf4j
  18. @RestController
  19. @RequestMapping("/sentinel-fallback")
  20. public class SentinelFallbackController {
  21. /** 注入没有增强的 RestTemplate */
  22. private final RestTemplate restTemplate;
  23. public SentinelFallbackController(RestTemplate restTemplate) {
  24. this.restTemplate = restTemplate;
  25. }
  26. @PostMapping("/get-token")
  27. @SentinelResource(
  28. value = "getTokenFromAuthorityService",
  29. fallback = "getTokenFromAuthorityServiceFallback",
  30. fallbackClass = { QinyiFallbackHandler.class }
  31. )
  32. public JwtToken getTokenFromAuthorityService(
  33. @RequestBody UsernameAndPassword usernameAndPassword) {
  34. String requestUrl =
  35. "http://127.0.0.1:7000/ecommerce-authority-center/authority/token";
  36. log.info("RestTemplate request url and body: [{}], [{}]",
  37. requestUrl, JSON.toJSONString(usernameAndPassword));
  38. HttpHeaders headers = new HttpHeaders();
  39. headers.setContentType(MediaType.APPLICATION_JSON);
  40. return restTemplate.postForObject(
  41. requestUrl,
  42. new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
  43. JwtToken.class
  44. );
  45. }
  46. /**
  47. * <h2>让 Sentinel 忽略一些异常</h2>
  48. * */
  49. @GetMapping("/ignore-exception")
  50. @SentinelResource(
  51. value = "ignoreException",
  52. fallback = "ignoreExceptionFallback",
  53. fallbackClass = { QinyiFallbackHandler.class },
  54. exceptionsToIgnore = { NullPointerException.class }
  55. )
  56. public JwtToken ignoreException(@RequestParam Integer code) {
  57. if (code % 2 == 0) {
  58. throw new NullPointerException("yout input code is: " + code);
  59. }
  60. return new JwtToken("qinyi-imooc");
  61. }
  62. }

五、Sentinel 结合 Nacos 实现限流规则持久化

1、SpringCloud Alibaba Sentinel 配置信息

2、 整合nacos实现限流规则持久化

2.1、添加依赖

  1. <!-- Sentinel 使用 Nacos 存储规则 -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. </dependency>

2.2、编写限流接口

  1. /**
  2. * <h2>在 dashboard 中 "流控规则" 中按照资源名称新增流控规则</h2>
  3. * */
  4. @GetMapping("/by-resource")
  5. @SentinelResource(
  6. value = "byResource",
  7. blockHandler = "qinyiHandleBlockException",
  8. blockHandlerClass = QinyiBlockHandler.class
  9. )
  10. public CommonResponse<String> byResource() {
  11. log.info("coming in rate limit controller by resource");
  12. return new CommonResponse<>(0, "", "byResource");
  13. }

2.3、yml配置(spring:cloud下)

  1. sentinel:
  2. # 配置 sentinel dashboard 地址
  3. transport:
  4. dashboard: 127.0.0.1:7777
  5. port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
  6. # 服务启动直接建立心跳连接
  7. eager: true
  8. datasource:
  9. # 名称任意, 代表数据源
  10. ds:
  11. nacos:
  12. # NacosDataSourceProperties.java 中定义
  13. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  14. dataId: ${spring.application.name}-sentinel
  15. namespace: ${spring.cloud.nacos.discovery.namespace}
  16. groupId: DEFAULT_GROUP
  17. data-type: json
  18. # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
  19. # FlowRule 就是限流规则
  20. rule-type: flow

2.4、在nacos上编写指定限流接口的配置

  1. [
  2. {
  3. "resource": "byresource",
  4. "limitApp": "default",
  5. "grade": 1,
  6. "count": 1,
  7. "strategy": 0,
  8. "controlBehavior": 0,
  9. "clusterMode": false
  10. }
  11. ]
  • resource:资源名称。
  •  limitApp:针对来源,可以编写成服务名称,默认为default。
  • grade:阈值类型,QPS(1)、并发线程数(0)。
  • count:单机阈值。
  • strategy:流控模式,直接(0)、关联(1)、链路(2)。
  • controlBehavior:流控效果,快速失败(0)、Warm Up(1)、排队等待(2)。
  • clusterMode:是否集群,是(true)、否(false)。
  • warmUpPeriodSec:预热时长,单位秒。
  • maxQueueingTimeMs:超时时间,单位毫秒。
  • refResource:关联资源名称

3、 整合nacos实现熔断规则持久化

3.1、添加依赖

  1. <!-- Sentinel 使用 Nacos 存储规则 -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. </dependency>

3.2、yml配置

  1. feign:
  2. sentinel:
  3. enabled: true
  4. spring:
  5. cloud:
  6. openfeign:
  7. lazy-attributes-resolution: true
  8. sentinel:
  9. datasource:
  10. degrade:
  11. nacos:
  12. dataId: sentinel-batch-degrade
  13. groupId: DEFAULT_GROUP
  14. namespace: train
  15. ruleType: degrade
  16. serverAddr: 127.0.0.1:8848
  17. transport:
  18. dashboard: localhost:18080
  19. port: 8719

3.3、在nacos上编写熔断规则。

  1. [{
  2. "resource":"GET:http://business/hello",
  3. "grade":0,
  4. "count": 201,
  5. "timeWindow":11,
  6. "minRequestAmount":6,
  7. "statIntervalMs":1000,
  8. "slowRatioThreshold":0.3
  9. }]
  • resource:资源名称。
  • grade:熔断策略,慢比例调用(0)、异常比例(1)、异常数(2)。
  • count:最大响应时间(最大TR),单位毫秒。
  • timeWindow:熔断时长,单位秒。
  • minRequestAmount:最小请求数。
  • statIntervalMs:统计时长,单位毫秒。
  • slowRatioThreshold:比例阀值。
  1. [{
  2. "resource":"GET:http://business/hello",
  3. "grade":1,
  4. "count": 0.3,
  5. "timeWindow":11,
  6. "minRequestAmount":6,
  7. "statIntervalMs":1000
  8. }]
  • resource:资源名称。
  • grade:熔断策略,慢比例调用(0)、异常比例(1)、异常数(2)。
  • count:比例阀值。
  • timeWindow:熔断时长,单位秒。
  • minRequestAmount:最小请求数。
  • statIntervalMs:统计时长,单位毫秒。
  1. [{
  2. "resource":"GET:http://business/hello",
  3. "grade":2,
  4. "count":3,
  5. "timeWindow":11,
  6. "minRequestAmount":6,
  7. "statIntervalMs":1000
  8. }]
  • resource:资源名称。
  • grade:熔断策略,慢比例调用(0)、异常比例(1)、异常数(2)。
  • count:异常数。
  • timeWindow:熔断时长,单位秒。
  • minRequestAmount:最小请求数。
  • statIntervalMs:统计时长,单位毫秒。

3.4、熔断策略讲解

  1. 慢比例调用:当最大RT=201,比例阀值=0.3,熔断时长=11,最小请求数=6,统计时间=1000,表示当请求资源时,当满足在一秒钟内,请求数超过6个,并且30%的请求时间超过201毫秒这个条件时,接口熔断11秒。
  2. 异常比例:当比例阀值=0.3,熔断时长=3,最小请求数=6,统计时间=1000,表示当请求资源时,当满足在一秒钟内,请求数超过6个,并且异常比例达到30%这个条件时,接口熔断3秒。
  3. 异常数:当异常数=3,熔断时长=3,最小请求数=6,统计时间=1000,表示当请求资源时,当满足在一秒钟内,请求数超过6个,并且异常数超过3个这个条件时,接口熔断3秒。

3.5、编写fegin client 

  1. /**
  2. * <h1>通过 Sentinel 对 OpenFeign 实现熔断降级</h1>
  3. * */
  4. @FeignClient(
  5. value = "e-commerce-imooc",
  6. fallback = SentinelFeignClientFallback.class
  7. )
  8. public interface SentinelFeignClient {
  9. @RequestMapping(value = "qinyi", method = RequestMethod.GET)
  10. CommonResponse<String> getResultByFeign(@RequestParam Integer code);
  11. }

3.6、编写Sentinel 对 OpenFeign 接口的降级策略

  1. /**
  2. * <h1>Sentinel 对 OpenFeign 接口的降级策略</h1>
  3. * */
  4. @Slf4j
  5. @Component
  6. public class SentinelFeignClientFallback implements SentinelFeignClient {
  7. @Override
  8. public CommonResponse<String> getResultByFeign(Integer code) {
  9. log.error("request supply for test has some error: [{}]", code);
  10. return new CommonResponse<>(
  11. -1,
  12. "sentinel feign fallback",
  13. "input code: "+ code
  14. );
  15. }
  16. }

3.7、编写controller测试使用fegin的熔断降级

  1. /**
  2. * <h1>OpenFeign 集成 Sentinel 实现熔断降级</h1>
  3. * */
  4. @Slf4j
  5. @RestController
  6. @RequestMapping("/sentinel-feign")
  7. public class SentinelFeignController {
  8. private final SentinelFeignClient sentinelFeignClient;
  9. public SentinelFeignController(SentinelFeignClient sentinelFeignClient) {
  10. this.sentinelFeignClient = sentinelFeignClient;
  11. }
  12. /**
  13. * <h2>通过 Feign 接口去获取结果</h2>
  14. * */
  15. @GetMapping("/result-by-feign")
  16. public CommonResponse<String> getResultByFeign(@RequestParam Integer code) {
  17. log.info("coming in get result by feign: [{}]", code);
  18. return sentinelFeignClient.getResultByFeign(code);
  19. }
  20. }

六、Gateway集成Sentinel实现网关限流(不论那种方式硬编码中的样板代码必须添加在Gateway)

1、引入依赖

  1. <!-- 集成 Sentinel, 在网关层面实现限流 -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.alibaba.cloud</groupId>
  8. <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
  9. </dependency>
  10. <!-- Sentinel 使用 Nacos 存储规则 -->
  11. <dependency>
  12. <groupId>com.alibaba.csp</groupId>
  13. <artifactId>sentinel-datasource-nacos</artifactId>
  14. </dependency>

2、编写配置文件(spring:cloud下)

  1. sentinel:
  2. # 配置 sentinel dashboard 地址
  3. transport:
  4. dashboard: 127.0.0.1:7777
  5. port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
  6. # 服务启动直接建立心跳连接
  7. eager: true

3、硬编码方式实现

  1. package com.imooc.ecommerce.config;
  2. import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
  3. import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
  4. import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
  5. import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
  6. import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
  7. import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
  8. import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
  9. import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
  10. import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
  11. import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
  12. import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
  13. import com.alibaba.csp.sentinel.slots.block.RuleConstant;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.beans.factory.ObjectProvider;
  16. import org.springframework.cloud.gateway.filter.GlobalFilter;
  17. import org.springframework.context.annotation.Bean;
  18. import org.springframework.context.annotation.Configuration;
  19. import org.springframework.core.Ordered;
  20. import org.springframework.core.annotation.Order;
  21. import org.springframework.http.HttpStatus;
  22. import org.springframework.http.MediaType;
  23. import org.springframework.http.codec.ServerCodecConfigurer;
  24. import org.springframework.web.reactive.function.BodyInserters;
  25. import org.springframework.web.reactive.function.server.ServerResponse;
  26. import org.springframework.web.reactive.result.view.ViewResolver;
  27. import org.springframework.web.server.ServerWebExchange;
  28. import reactor.core.publisher.Mono;
  29. import javax.annotation.PostConstruct;
  30. import java.util.*;
  31. /**
  32. * <h1>Gateway 集成 Sentinel 实现限流</h1>
  33. * */
  34. @Slf4j
  35. @Configuration
  36. public class SentinelGatewayConfiguration {
  37. //=====================================================样板间式代码开始=====================================================
  38. /** 视图解析器 */
  39. private final List<ViewResolver> viewResolvers;
  40. /** HTTP 请求和响应数据的编解码配置 */
  41. private final ServerCodecConfigurer serverCodecConfigurer;
  42. /**
  43. * <h2>构造方法</h2>
  44. * */
  45. public SentinelGatewayConfiguration(
  46. ObjectProvider<List<ViewResolver>> viewResolversProvider,
  47. ServerCodecConfigurer serverCodecConfigurer
  48. ) {
  49. this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
  50. this.serverCodecConfigurer = serverCodecConfigurer;
  51. }
  52. /**
  53. * <h2>限流异常处理器, 限流异常出现时, 执行到这个 handler</h2>
  54. * */
  55. @Bean
  56. @Order(Ordered.HIGHEST_PRECEDENCE)
  57. public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
  58. // 默认会返回错误 message, code 429
  59. return new SentinelGatewayBlockExceptionHandler(
  60. this.viewResolvers,
  61. this.serverCodecConfigurer
  62. );
  63. }
  64. /**
  65. * <h2>限流过滤器, 是 Gateway 全局过滤器, 优先级定义为最高</h2>
  66. * */
  67. @Bean
  68. @Order(Ordered.HIGHEST_PRECEDENCE)
  69. public GlobalFilter sentinelGatewayFilter() {
  70. return new SentinelGatewayFilter();
  71. }
  72. /**
  73. * 自定义限流异常返回
  74. */
  75. @PostConstruct
  76. public void initBlockHandlers() {
  77. BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
  78. public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
  79. Map result = new HashMap();
  80. result.put("code","500016");
  81. result.put("msg","接口被限流了");
  82. return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromObject(result));
  83. }
  84. };
  85. GatewayCallbackManager.setBlockHandler(blockRequestHandler);
  86. }
  87. //=====================================================样板间式代码结束=====================================================
  88. //=====================================================硬编码方式实现限流规则============================================//
  89. /**
  90. * <h2>初始化限流规则</h2>
  91. * */
  92. // @PostConstruct
  93. public void doInit() {
  94. log.info("---------------------------------------------------");
  95. // 加载网关限流规则
  96. log.info("load sentinel gateway rules (code define)");
  97. initGatewayRules();
  98. // 加载自定义限流异常处理器
  99. initBlockHandler();
  100. log.info("---------------------------------------------------");
  101. }
  102. /**
  103. * <h2>硬编码网关限流规则</h2>
  104. * */
  105. private void initGatewayRules() {
  106. Set<GatewayFlowRule> rules = new HashSet<>();
  107. GatewayFlowRule rule = new GatewayFlowRule();
  108. // 指定限流模式, 根据 route_id 做限流, 默认的模式
  109. rule.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);
  110. // 指定 route_id -> service id
  111. rule.setResource("e-commerce-nacos-client");
  112. // 按照 QPS 限流
  113. rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
  114. // 统计窗口和限流阈值
  115. rule.setIntervalSec(60);
  116. rule.setCount(3);
  117. // rules.add(rule);
  118. // 限流分组, Sentinel 先去找规则定义, 再去找规则中定义的分组
  119. rules.add(
  120. new GatewayFlowRule("nacos-client-api-1")
  121. .setCount(3).setIntervalSec(60)
  122. );
  123. rules.add(
  124. new GatewayFlowRule("nacos-client-api-2")
  125. .setCount(1).setIntervalSec(60)
  126. );
  127. // 加载到网关中
  128. GatewayRuleManager.loadRules(rules);
  129. // 加载限流分组
  130. initCustomizedApis();
  131. }
  132. /**
  133. * <h2>自定义限流异常处理器</h2>
  134. * */
  135. private void initBlockHandler() {
  136. // 自定义 BlockRequestHandler
  137. BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
  138. @Override
  139. public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange,
  140. Throwable throwable) {
  141. log.error("------------- trigger gateway sentinel rule -------------");
  142. Map<String, String> result = new HashMap<>();
  143. result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
  144. result.put("message", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
  145. result.put("route", "e-commerce-nacos-client");
  146. return ServerResponse
  147. .status(HttpStatus.TOO_MANY_REQUESTS)
  148. .contentType(MediaType.APPLICATION_JSON)
  149. .body(BodyInserters.fromValue(result));
  150. }
  151. };
  152. // 设置自定义限流异常处理器
  153. GatewayCallbackManager.setBlockHandler(blockRequestHandler);
  154. }
  155. /**
  156. * <h2>硬编码网关限流分组</h2>
  157. * 1. 最大限制 - 演示
  158. * 2. 具体的分组
  159. * */
  160. private void initCustomizedApis() {
  161. Set<ApiDefinition> definitions = new HashSet<>();
  162. // nacos-client-api 组, 最大的限制
  163. ApiDefinition api = new ApiDefinition("nacos-client-api")
  164. .setPredicateItems(new HashSet<ApiPredicateItem>() {{
  165. // 模糊匹配 /imooc/ecommerce-nacos-client/ 及其子路径的所有请求
  166. add(new ApiPathPredicateItem()
  167. .setPattern("/imooc/ecommerce-nacos-client/**")
  168. // 根据前缀匹配
  169. .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
  170. }});
  171. // nacos-client-api-1 分组
  172. ApiDefinition api1 = new ApiDefinition("nacos-client-api-1")
  173. .setPredicateItems(new HashSet<ApiPredicateItem>() {{
  174. add(new ApiPathPredicateItem()
  175. // 精确匹配 /imooc/ecommerce-nacos-client/nacos-client/service-instance
  176. .setPattern("/imooc/ecommerce-nacos-client" +
  177. "/nacos-client/service-instance"));
  178. }});
  179. // nacos-client-api-2 分组
  180. ApiDefinition api2 = new ApiDefinition("nacos-client-api-2")
  181. .setPredicateItems(new HashSet<ApiPredicateItem>() {{
  182. add(new ApiPathPredicateItem()
  183. // 精确匹配 /imooc/ecommerce-nacos-client/nacos-client/project-config
  184. .setPattern("/imooc/ecommerce-nacos-client" +
  185. "/nacos-client/project-config"));
  186. }});
  187. definitions.add(api1);
  188. definitions.add(api2);
  189. // 加载限流分组
  190. GatewayApiDefinitionManager.loadApiDefinitions(definitions);
  191. }
  192. }

4、本地文件方式实现

4.1、编写路由规则

gateway-flow-rule-sentinel.json(路由规则,resource可以为接口名称、微服务名称、分组名称,resourceMode=1,resourceMode=0表示分组)

  1. [
  2. {
  3. "resource": "e-commerce-nacos-client",
  4. "resourceMode": 0,
  5. "count": 3,
  6. "intervalSec": 60
  7. },
  8. {
  9. "resource": "nacos-client-api",
  10. "resourceMode": 1,
  11. "count": 1,
  12. "intervalSec": 60
  13. }
  14. ]

4.2、编写路由规则分组 

gateway-flow-rule-api-sentinel.json(路由规则分组,表示resource中是apiname时,该分组中的接口路径都按照resource中的限流规则)

  1. [
  2. {
  3. "apiName": "nacos-client-api",
  4. "predicateItems": [
  5. {
  6. "pattern": "/imooc/ecommerce-nacos-client/nacos-client/project-config"
  7. },
  8. {
  9. "pattern": "/imooc/ecommerce-nacos-client/**",
  10. "matchStrategy": 1
  11. }
  12. ]
  13. }
  14. ]

4.3、编写配置文件

  1. sentinel:
  2. eager: true
  3. transport:
  4. client-ip: 8720
  5. dashboard: 127.0.0.1:7777
  6. datasource:
  7. dsl.file:
  8. file: classpath:gateway-flow-rule-sentinel.json
  9. ruleType: gw-flow
  10. ds2.file:
  11. file: classpath:gateway-flow-rule-api-sentinel.json
  12. ruleType: gw-api-group

5、nacos方式实现

 5.1、nacos上编写路由规则

gateway-flow-rule-sentinel.json(路由规则,resource可以为接口名称、微服务名称、分组名称,resourceMode=0为roteId,resourceMode=1表示api分组)

  1. [
  2. {
  3. "resource": "e-commerce-nacos-client",
  4. "resourceMode": 0,
  5. "count": 3,
  6. "intervalSec": 60
  7. },
  8. {
  9. "resource": "nacos-client-api",
  10. "resourceMode": 1,
  11. "count": 1,
  12. "intervalSec": 60
  13. }
  14. ]

5.2、nacos上编写路由规则分组 

gateway-flow-rule-api-sentinel.json(路由规则分组,表示resource中是apiname时,改分组中的接口路径都按照resource中的限流规则,matchStrategy=1表示为模糊匹配,默认为精确匹配)

  1. [
  2. {
  3. "apiName": "nacos-client-api",
  4. "predicateItems": [
  5. {
  6. "pattern": "/imooc/ecommerce-nacos-client/nacos-client/project-config"
  7. },
  8. {
  9. "pattern": "/imooc/ecommerce-nacos-client/**",
  10. "matchStrategy": 1
  11. }
  12. ]
  13. }
  14. ]

5.3、编写yml配置文件

  1. sentinel:
  2. eager: true
  3. transport:
  4. client-ip: 8720
  5. dashboard: 127.0.0.1:7777
  6. datasource:
  7. # 名称任意, 代表数据源
  8. ds1:
  9. nacos:
  10. # NacosDataSourceProperties.java 中定义
  11. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  12. dataId: gateway-flow-rule-sentinel
  13. namespace: ${spring.cloud.nacos.discovery.namespace}
  14. groupId: DEFAULT_GROUP
  15. data-type: json
  16. # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
  17. # FlowRule 就是限流规则
  18. rule-type: gw_flow
  19. # 名称任意, 代表数据源
  20. ds2:
  21. nacos:
  22. # NacosDataSourceProperties.java 中定义
  23. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  24. dataId: gateway-flow-rule-api-sentinel
  25. namespace: ${spring.cloud.nacos.discovery.namespace}
  26. groupId: DEFAULT_GROUP
  27. data-type: json
  28. # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
  29. # FlowRule 就是限流规则
  30. rule-type: gw_api_group

 
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/224911
推荐阅读
相关标签
  

闽ICP备14008679号