项目准备
项目架构如下:
项目搭建
参考:【SpringCloud】Spring Cloud Alibaba 之 Sentinel哨兵介绍入门(二十九)
1、搭建一个Nacos服务
参考项目搭建,用于做项目的注册中心及配置中心,并启动
2、搭建一个Sentinel控制台
参考项目搭建,并启动
3、搭建2个nacos-payment-provider服务
参考项目搭建,springcloud-provider-sentinel-payment9003 和 springcloud-provider-sentinel-payment9004 项目
项目中PaymentController,如下:
1 @RestController 2 public class PaymentController { 3 @Value("${server.port}") 4 private String serverPort; 5 6 public static HashMap<Long, Payment> hashMap = new HashMap<Long, Payment>(); 7 8 static { 9 hashMap.put(1L, new Payment(1L, "aaaaaa")); 10 hashMap.put(2L, new Payment(2L, "bbbbbb")); 11 hashMap.put(3L, new Payment(3L, "cccccc")); 12 } 13 14 @GetMapping(value = "/paymentSQL/{id}") 15 public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) { 16 Payment payment = hashMap.get(id); 17 CommonResult<Payment> result = new CommonResult<Payment>(200, "from server port : " + serverPort, payment); 18 return result; 19 } 20 }
项目中有2个实体类,CommonResult实体类如下:
1 @Data 2 @AllArgsConstructor 3 @NoArgsConstructor 4 public class CommonResult<T> { 5 6 private int code; 7 private String msg; 8 private T data; 9 10 public CommonResult(int code, String msg) { 11 this.code = code; 12 this.msg = msg; 13 } 14 }
Payment实体类
1 @Data 2 @AllArgsConstructor 3 @NoArgsConstructor 4 public class Payment { 5 private Long id; 6 private String serial; 7 }
然后分别启动2个服务
3、搭建1个springcloud-consumer-sentinel-order7994服务(调用者)
a、pom文件如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>test-springcloud</artifactId> 7 <groupId>com.test</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>springcloud-consumer-sentinel-order7994</artifactId> 13 14 <dependencies> 15 16 <!-- alibaba nacos sentinel --> 17 <dependency> 18 <groupId>com.alibaba.cloud</groupId> 19 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> 20 <version>2.2.1.RELEASE</version> 21 <exclusions> 22 <exclusion> 23 <groupId>com.fasterxml.jackson.dataformat</groupId> 24 <artifactId>jackson-dataformat-xml</artifactId> 25 </exclusion> 26 </exclusions> 27 </dependency> 28 29 <!-- alibaba nacos --> 30 <dependency> 31 <groupId>com.alibaba.cloud</groupId> 32 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 33 </dependency> 34 35 <!-- openfeign --> 36 <dependency> 37 <groupId>org.springframework.cloud</groupId> 38 <artifactId>spring-cloud-starter-openfeign</artifactId> 39 </dependency> 40 41 <!-- spring boot --> 42 <dependency> 43 <groupId>org.springframework.boot</groupId> 44 <artifactId>spring-boot-starter-web</artifactId> 45 </dependency> 46 <dependency> 47 <groupId>org.springframework.boot</groupId> 48 <artifactId>spring-boot-starter-actuator</artifactId> 49 </dependency> 50 <dependency> 51 <groupId>org.springframework.boot</groupId> 52 <artifactId>spring-boot-devtools</artifactId> 53 <scope>runtime</scope> 54 <optional>true</optional> 55 </dependency> 56 <dependency> 57 <groupId>org.projectlombok</groupId> 58 <artifactId>lombok</artifactId> 59 <optional>true</optional> 60 </dependency> 61 <dependency> 62 <groupId>org.springframework.boot</groupId> 63 <artifactId>spring-boot-starter-test</artifactId> 64 <scope>test</scope> 65 </dependency> 66 67 </dependencies> 68 </project>
b、application配置文件如下:
1 # 端口 2 server: 3 port: 7994 4 5 spring: 6 application: 7 name: nacos-order-consumer 8 cloud: 9 nacos: 10 discovery: 11 server-addr: localhost:8848 12 sentinel: 13 transport: 14 # 配置Sentinel DashBoard地址 15 dashboard: localhost:8080 16 # 应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer 17 # 默认8719端口,假如端口被占用,依次+1,直到找到未被占用端口 18 port: 8719 19 20 21 management: 22 endpoints: 23 web: 24 exposure: 25 include: '*'
c、主启动类OrderMain7994
1 @SpringBootApplication 2 @EnableDiscoveryClient 3 //@EnableFeignClients 4 public class OrderMain7994 { 5 public static void main(String[] args) { 6 SpringApplication.run(OrderMain7994.class, args); 7 } 8 }
d、配置类AppConfig,整合Ribbon服务调用
1 @Configuration 2 public class AppConfig { 3 @Bean 4 @LoadBalanced 5 public RestTemplate restTemplate() { 6 return new RestTemplate(); 7 } 8 }
e、controller内容如下:
1 @RestController 2 @Slf4j 3 public class CircleBreakerController { 4 public static final String SERVICE_URL = "http://nacos-payment-provider"; 5 6 @Autowired 7 private RestTemplate restTemplate; 8 9 @RequestMapping("/consumer/fallback/{id}") 10 public CommonResult<Payment> fallback(@PathVariable("id") Long id) { 11 CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class); 12 if (id == 4) { 13 throw new IllegalArgumentException("IllegalArgumentException, 非法参数"); 14 } else if (result.getData() == null) { 15 throw new NullPointerException("NullPointerException,该ID没有对应的记录,空指针异常"); 16 } 17 18 return result; 19 } 20 21 }
4、测试验证项目
1)访问地址:http://localhost:7994/consumer/fallback/3,正常获取到provider服务提供者的内容
2)访问地址:http://localhost:7994/consumer/fallback/4,抛异常,非法参数
3)访问地址:http://localhost:7994/consumer/fallback/5,抛异常,空指针异常
@SentinelResource使用
1、@SentinelResource定义资源名
1.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}") 2 @SentinelResource(value = "fallback") // 没有配置 3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) { 4 ... 5 }
1.2、重新启动项目
1.3、访问地址http://localhost:7994/consumer/fallback/3,并在sentinel控制台设置限流规则
注意这里设置规则的时候,可以直接使用@SentinelResource的value作为资源名
1.4、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功
2、@SentinelResource 中的fallback
fallback负责业务异常和限流时处理
2.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}") 2 @SentinelResource(value = "fallback", fallback = "handlerFallback") // fallback负责业务异常和限流返回 3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) { 4 ... 5 } 6 7 public CommonResult<Payment> handlerFallback(Long id, Throwable e) { 8 Payment payment = new Payment(id, "null"); 9 return new CommonResult(500, "兜底异常处理handlerFallback,Exception内容:" + e.getMessage(), payment); 10 }
2.2、重新启动项目
2.3、访问地址http://localhost:7994/consumer/fallback/4,出现异常由fallback指定的方法处理
2.4、在sentinel控制台设置限流规则,设置QPS为阀值为1
2.5、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功,限流返回内容为fallback指定的方法
3、@SentinelResource 中的blockHandler
blockHandler只负责sentinel控制台配置违规
3.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}") 2 @SentinelResource(value = "fallback", blockHandler = "blockHandler") // blockHander只负责sentinel控制台配置违规 3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) { 4 ... 5 } 6 7 public CommonResult<Payment> handlerFallback(Long id, Throwable e) { 8 Payment payment = new Payment(id, "null"); 9 return new CommonResult(500, "兜底异常处理handlerFallback,Exception内容:" + e.getMessage(), payment); 10 } 11 12 public CommonResult<Payment> blockHandler(Long id, BlockException blockException) { 13 Payment payment = new Payment(id, "null"); 14 return new CommonResult(500, "blockHandler-Sentinel限流,Exception内容:" + blockException.getMessage(), payment); 15 }
3.2、重新启动项目
3.3、访问地址http://localhost:7994/consumer/fallback/4,返回参数非法异常
3.4、在sentinel控制台设置限流规则,设置QPS为阀值为1
3.4、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功,限流返回内容为blockHandler指定的方法
4、@SentinelResource 中的fallback和blockHandler同时存在
fallback负责处理异常,blockHandler负责sentinel控制台配置违规
4.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}") 2 @SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "handlerFallback") 3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) { 4 ... 5 }
4.2、重新启动项目
4.3、访问地址http://localhost:7994/consumer/fallback/4,出现异常由fallback指定的方法处理
4.4、在sentinel控制台设置限流规则,设置QPS为阀值为1
4.4、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功,限流返回内容为blockHandler指定的方法
5、@SentinelResource 中的exceptionsToIgnore
排除fallback指定的方法不处理的异常
5.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}") 2 @SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "handlerFallback", 3 exceptionsToIgnore = {IllegalArgumentException.class}) 4 public CommonResult<Payment> fallback(@PathVariable("id") Long id) { 5 ... 6 }
5.2、重新启动项目
5.3、访问地址http://localhost:7994/consumer/fallback/4,出现参数异常直接显示,fallback指定的方法不处理异常