服务熔断

suaxi
2021-04-29 / 0 评论 / 44 阅读 / 正在检测是否收录...

1、环境搭建

1、启动Nacos、Sentinel

2、新建9003、9004两个模块

pom
<!-- API -->
<dependency>
    <groupId>com.sw</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

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

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

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

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

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>


yml
server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

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


启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class, args);
    }
}


controller(此处的虚拟数据库是为了方便演示)
@RestController
@RequestMapping("/payment")
public class PaymentController {

    @Value("${server.port}")
    private String serverPort;

    public static Map<Long, Payment> map = new HashMap<>();
    static {
        map.put(1L, new Payment(1L, "螺蛳粉01"));
        map.put(2L, new Payment(2L, "螺蛳粉02"));
        map.put(3L, new Payment(3L, "螺蛳粉03"));
    }

    @GetMapping("/{id}")
    public CommonResult<Payment> payment(@PathVariable("id")Long id){
        Payment payment = map.get(id);
        CommonResult<Payment> result = new CommonResult<>(200, "serverPort: " + serverPort, payment);
        return result;
    }
}

注:9004构建步骤与9003一致


2、新建8884模块

pom

同理9004、9004模块


yml
server:
  port: 8884

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        # sentinel dashboard地址
        dashboard: localhost:8080
        # 默认8719端口,如果8719被占用,默认递增
        port: 8719

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

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


启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderMain84 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain84.class, args);
    }
}


config配置类
@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}


controller
@RestController
@RequestMapping("/consumer")
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "fallback/{id}", produces = {"application/json;charset=UTF-8"})
    @SentinelResource("fallback")
    public CommonResult<Payment> fallback(@PathVariable("id")Long id){
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, CommonResult.class, id);
        if (id ==4){
            throw new IllegalArgumentException("参数异常!");
        }else if (result.getData() == null){
            throw new NullPointerException("没有找到对应id的记录!");
        }
        return result;
    }
}
指定降级方法
@RestController
@RequestMapping("/consumer")
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "fallback/{id}", produces = {"application/json;charset=UTF-8"})
    //@SentinelResource("fallback")
    @SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    public CommonResult<Payment> fallback(@PathVariable("id")Long id){
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, CommonResult.class, id);
        if (id ==4){
            throw new IllegalArgumentException("参数异常!");
        }else if (result.getData() == null){
            throw new NullPointerException("没有找到对应id的记录!");
        }
        return result;
    }

    public CommonResult handlerFallback(@PathVariable("id")Long id, Throwable e){
        Payment payment = new Payment(id, "null");
        return new CommonResult(444,"handlerFallback,异常内容:" + e.getMessage(), payment);
    }
}


2、测试

启动测试:

1.指定降级方法测试结果01.png

注:此处没有使用Sentinel来配置降级规则,但却降级成功,是因为fallback用于管理异常,当业务发生异常时,可以降级到指定的方法


为业务添加blockhandler
@RestController
@RequestMapping("/consumer")
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "fallback/{id}", produces = {"application/json;charset=UTF-8"})
    //@SentinelResource("fallback")
    //@SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    @SentinelResource(value = "fallback", blockHandler = "blockHandler") //blockHandler只负责sentinel控制台的配置
    public CommonResult<Payment> fallback(@PathVariable("id")Long id){
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, CommonResult.class, id);
        if (id ==4){
            throw new IllegalArgumentException("参数异常!");
        }else if (result.getData() == null){
            throw new NullPointerException("没有找到对应id的记录!");
        }
        return result;
    }

//    public CommonResult handlerFallback(@PathVariable("id")Long id, Throwable e){
//        Payment payment = new Payment(id, "null");
//        return new CommonResult(444,"handlerFallback,异常内容:" + e.getMessage(), payment);
//    }

    public CommonResult blockHandler(@PathVariable("id")Long id, BlockException exception){
        Payment payment = new Payment(id, "null");
        return new CommonResult(444,"blockHandler,异常内容:" + exception.getMessage(), payment);
    }
}


测试结果:

2.添加blockHandler测试结果.png

注:可以看到返回结果直接报错,并没有降级,所以说blockHandler只适用于Sentinel配置的规则


同时配置fallback和blockHandler
@RestController
@RequestMapping("/consumer")
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "fallback/{id}", produces = {"application/json;charset=UTF-8"})
    //@SentinelResource("fallback")
    //@SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    //@SentinelResource(value = "fallback", blockHandler = "blockHandler") //blockHandler只负责sentinel控制台的配置
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")
    public CommonResult<Payment> fallback(@PathVariable("id")Long id){
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, CommonResult.class, id);
        if (id ==4){
            throw new IllegalArgumentException("参数异常!");
        }else if (result.getData() == null){
            throw new NullPointerException("没有找到对应id的记录!");
        }
        return result;
    }

    public CommonResult handlerFallback(@PathVariable("id")Long id, Throwable e){
        Payment payment = new Payment(id, "null");
        return new CommonResult(444,"handlerFallback,异常内容:" + e.getMessage(), payment);
    }

    public CommonResult blockHandler(@PathVariable("id")Long id, BlockException exception){
        Payment payment = new Payment(id, "null");
        return new CommonResult(444,"blockHandler,异常内容:" + exception.getMessage(), payment);
    }
}


配置Sentinel规则:

3.同时配置fallBack和blockHandler,配置sentinel规则.png

结果:

4.同时配置fallBack和blockHandler,测试结果.png

可以看到,同时配置fallbackblockHandlerblockHandler的优先级更高


exceptionsToIgnore属性
@RestController
@RequestMapping("/consumer")
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "fallback/{id}", produces = {"application/json;charset=UTF-8"})
    //@SentinelResource("fallback")
    //@SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    //@SentinelResource(value = "fallback", blockHandler = "blockHandler") //blockHandler只负责sentinel控制台的配置
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
        exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable("id")Long id){
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, CommonResult.class, id);
        if (id ==4){
            throw new IllegalArgumentException("参数异常!");
        }else if (result.getData() == null){
            throw new NullPointerException("没有找到对应id的记录!");
        }
        return result;
    }

    public CommonResult handlerFallback(@PathVariable("id")Long id, Throwable e){
        Payment payment = new Payment(id, "null");
        return new CommonResult(444,"handlerFallback,异常内容:" + e.getMessage(), payment);
    }

    public CommonResult blockHandler(@PathVariable("id")Long id, BlockException exception){
        Payment payment = new Payment(id, "null");
        return new CommonResult(444,"blockHandler,异常内容:" + exception.getMessage(), payment);
    }
}

测试结果:

5.添加exceptionsToIgnore属性测试结果.png

注:使用exceptionsToIgnore指定异常类,表示当前方法如果抛出了指定的异常,不进行降级处理,直接返回抛出的异常结果

图片来源:尚硅谷 - 周阳 - Spring Cloud Alibaba

0

评论 (0)

取消