Loading

sentinel服务熔断

1.环境准备

服务熔断:应对微服务雪崩效应的一种链路保护机制,类似保险丝。

需要完成Sentinel整合Ribbon+openFeign,所以我们先要搭建环境,那么先从整合Ribbon开始

image

新建nacos-provider-9001/9002

父pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.6.4</version>
     <relativePath/> <!-- lookup parent from repository -->
 </parent>

 <groupId>com.zt.studydemo</groupId>
 <artifactId>study_demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>study_demo</name>
 <packaging>pom</packaging>
 <description>study_demo</description>

 <properties>
     <java.version>1.8</java.version>
 </properties>

 <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>

     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
     </dependency>
 </dependencies>

 <dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
             <version>2021.0.1</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>

         <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-alibaba-dependencies</artifactId>
             <version>2.2.7.RELEASE</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
 </dependencyManagement>

</project>

子pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <parent>
     <groupId>com.zt.studydemo</groupId>
     <artifactId>study_demo</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <relativePath/> <!-- lookup parent from repository -->
 </parent>

 <artifactId>nacos-9001</artifactId>
 <name>nacos-9001</name>
 <description>nacos-9001</description>

 <properties>
     <java.version>1.8</java.version>
 </properties>

 <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>

     <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
     </dependency>
 </dependencies>

 <build>
     <plugins>
         <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
     </plugins>
 </build>

</project>

yml

server:
port: 9001

spring:
application:
 name: nacos-provider
cloud:
 nacos:
   discovery:
     server-addr: 192.168.56.10:3333
management:
endpoints:
 web:
   exposure:
     include: '*'

启动类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Nacos9001Application {

 public static void main(String[] args) {
     SpringApplication.run(Nacos9001Application.class, args);
 }

}

控制器:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
 @Value("${server.port}")
 private String serverPort;

 @GetMapping("info/{id}")
 public String msbSql(@PathVariable("id") Long id){
     return "Hello Nacos Discovery" + serverPort;
 }

}

新建sentinel-service-8401

pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <parent>
     <groupId>com.zt.studydemo</groupId>
     <artifactId>study_demo</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <relativePath/> <!-- lookup parent from repository -->
 </parent>

 <artifactId>sentinel-service-8401</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>sentinel-service-8401</name>
 <description>sentinel-service-8401</description>

 <properties>
     <java.version>1.8</java.version>
 </properties>

 <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>

     <!-- Nacos客户端依赖 -->
     <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
     </dependency>

     <!-- sentinel依赖 -->
     <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
     </dependency>
 </dependencies>

 <build>
     <plugins>
         <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
     </plugins>
 </build>

</project>

yml:

server:
port: 8401

spring:
main:
 allow-circular-references: true
application:
 name: sentinel-service-8401
cloud:
 nacos:
   discovery:
     server-addr: 192.168.56.10:3333
 sentinel:
   transport:
     # 配置Sentinel dashboard地址
     dashboard: localhost:8080
     # 默认8719端口,键入被占用会自动从8719+1,直到找到未被占用的端口
     port: 8719
   # 配置为false
   web-context-unify: false

management:
endpoints:
 web:
   exposure:
     include: '*'

service-url:
nacos-user-service: http://nacos-provider

主启动类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class SentinelService8401Application {

 public static void main(String[] args) {
     SpringApplication.run(SentinelService8401Application.class, args);
 }

 /**
     * 远程调用
     * @return
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

控制器类:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;@RestControllerpublic class DemoController {    //服务提供者URL    @Value("${service-url.nacos-user-service}")    private String SERVICE_URL;    @Autowired    private RestTemplate restTemplate;    @GetMapping("/consumer/fallback/{id}")    public String fallback(@PathVariable Long id) {        return restTemplate.getForObject(SERVICE_URL + "/info/" + id, String.class);    }}

测试:访问http://localhost:8401/consumer/fallback/1

查看最后结果是否为9001/9002切换调用

2.SentinelResource的fallback属性

fallback属性:

fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:

  1. 返回值类型必须与原函数返回值类型一致;2. 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。3. fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

其实通过官网上提供的概念,我们不难看出这个属性类似于blockHandler,但是他们有本质的不同。

fallback属性和blockHandler属性的本质不同在于他们作用的异常不同:

  1. blockHandler:针对违反Sentinel控制台配置规则时触发BlockException异常时对应处理的属性2. fallback:针对Java本身出现的异常进行处理的对应属性。

修改DemoController类:

 @GetMapping("/consumer/fallback/{id}") public String fallback(@PathVariable Long id) {     if(id<=3){         //通过Ribbon发起远程访问,访问9001/9002         return restTemplate.getForObject(SERVICE_URL + "/info/" + id, String.class);     }else{         throw new NullPointerException("没有对应的数据记录");     } }

此时如果我们访问http://localhost:8084/consumer/fallback/4(id非法)地址时,就会出现对应的显示效果:

image

明显此时显示效果非常不好,我们就可以通过@SentinelResource注解的fallback属性来解决这种java异常,给出友好提示

 @GetMapping("/consumer/fallback/{id}") //添加SentinelResource注解的fallback属性,同时设置方法来解决Java异常 @SentinelResource(value = "falllback",fallback = "fallbackHandler") public String fallback(@PathVariable Long id) {     if(id<=3){         //通过Ribbon发起远程访问,访问9001/9002         return restTemplate.getForObject(SERVICE_URL + "/info/" + id, String.class);     }else{         throw new NullPointerException("没有对应的数据记录");     } } //保证方法签名基本保持一致,但是要添加异常类型参数 public String fallbackHandler(Long id,Throwable e){     return "出现未知商品id"; }

image

到这里为止我们就很清楚的知道了fallback属性的作用,同时它和blockHandler属性类似,也可以设置fallbackClass属性,来指定对应类型,来处理对应的Java异常,当然要注意和blockHandlerClass属性一样,也需要让所有的方法都必需为 static 函数,否则无法解析。

3.同时配置blockHandler和fallback属性

@GetMapping("/consumer/fallback/{id}") //同时添加SentinelResource注解的fallback和blockHandler属性 @SentinelResource(value = "falllback",fallback = "fallbackHandler",blockHandler = "blockHandler") public String fallback(@PathVariable Long id) {     if(id<=3){         //通过Ribbon发起远程访问,访问9001/9002         return restTemplate.getForObject(SERVICE_URL + "/info/" + id, String.class);     }else{         throw new NullPointerException("没有对应的数据记录");     } } //保证方法签名基本保持一致,但是要添加异常类型参数 public String fallbackHandler(Long id,Throwable e){     return "出现未知商品id"; } //处理Sentinel限流 public String blockHandler(Long id, BlockException e){     return "BlockException限流"; }

配置熔断规则:

在10秒内超过最小访问次数5次,并且异常数超过2的时候,就会触发熔断规则。

image

此时我们来访问http://localhost:8401/consumer/fallback/4看效果:

  • 在没有触发熔断之前的异常交给fallback来处理

image

  • 一旦触发熔断规则就变成了blockHandler来处理

    image

4.exceptionsToIgnore属性

exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

@SentinelResource(value = "falllback",fallback = "fallbackHandler",blockHandler = "blockHandler",         exceptionsToIgnore = {NullPointerException.class})//被标注的异常将会被原样抛出
posted @ 2022-05-21 10:01  ZT丶  阅读(301)  评论(0编辑  收藏  举报