1. 服务降级(fallback)
    是在服务器压力陡增的情况下,利用有限资源,根据当前业务情况,关闭某些服务接口或者页面,以此释放服务器资源以保证核心任务的正常运行。
  2. 服务熔断(break)
    一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施。
  3. 服务限流(flowlimit)
    秒杀等高并发操作,严禁同时大规模请求,排队,一秒钟N个有序进行。

什么是熔断和降级

服务的稳定是公司可持续发展的重要基石,随着业务量的快速发展,一些平时正常运行的服务,会出现各种突发状况,而且在分布式系统中,每个服务本身又存在很多不可控的因素,比如线程池处理缓慢,导致请求超时,资源不足,导致请求被拒绝,又甚至直接服务不可用、宕机、数据库挂了、缓存挂了、消息系统挂了…对于一些非核心服务,如果出现大量的异常,可以通过技术手段,对服务进行降级并提供有损服务,保证服务的柔性可用,避免引起雪崩效应。

为什么要使用熔断和降级

在一个分布式系统里,一个服务依赖多个服务,可能存在某个服务调用失败,比如超时、异常等,需要保证在一个依赖出问题的情况下,不会导致整体服务失败。

1.引入pom

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
 </dependency>

2.启动类添加注解@EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class,args);
    }
}

3.服务端controller

@RestController
@RequestMapping("/payment")
@Slf4j
public class PaymentController {

    @Autowired
    private IPaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;
    /**
     * 获取订单详细信息
     */
    @GetMapping(value = "/hystrix/ok/{id}")
    public String payment_ok(@PathVariable("id") Long id)
    {
        String result = paymentService.payment_ok(id);
        log.info("*****result:"+result);
        return result;
    }

    @GetMapping(value = "/hystrix/timeout/{id}")
    public String payment_timeout(@PathVariable("id") Long id)
    {
        String result = paymentService.payment_timeout(id);
        log.info("*****result:"+result);
        return result;
    }
}

4.服务端实现接口

fallbackMethod指向当程序异常时去访问的接口

@Service
public class PaymentServiceImpl implements IPaymentService {
    /**
     * 正常访问
     *
     * @param id 订单ID
     * @return 订单
     */
    @Override
    public String payment_ok(Long id)
    {
        return "payment_ok,id="+id+"\t"+"正常访问";
    }
    /**
     * 超时访问
     */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")
    })
    @Override
    public String payment_timeout(Long id)
    {
//        try {
//            TimeUnit.MILLISECONDS.sleep(3000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        int age = 10/0;
        return "payment_timeout,id="+id+"\t"+"未发生异常";
    }
    /**
     * 降级接口
     */
    @Override
    public String paymentInfo_TimeoutHandler(Long id){
        return "paymentInfo_TimeoutHandler,id="+id+"\t"+"系统繁忙,请稍后再试";
    }
}

5.消费端controller

@RestController
@RequestMapping("/consumer/payment")
@Slf4j
public class OrderFeignHystrixController {
    @Autowired
    private PaymentFeignHystrixService hystrixService;

    @GetMapping( "/payment_ok/{id}")
    public String getPayment(@PathVariable("id") Long id){
        return hystrixService.payment_ok(id);
    }
    /**
     * 超时访问
     */
    @GetMapping( "/payment_timeout/{id}")
//    @HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
//            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")
//    })
    public String payment_timeout(@PathVariable("id")Long id)
    {
//        int age = 10/0;
        return hystrixService.payment_timeout(id);
    }
    /**
     * 兜底接口
     */
    public String paymentInfo_TimeoutHandler(Long id){
        return "消费端80 paymentInfo_TimeoutHandler:对方异常,请稍后再试"+id+"\t"+",兜底访问";
    }
}

6.消费端接口

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-SERVICE",fallback = PaymentFeignHystrixServiceImpl.class)
public interface PaymentFeignHystrixService {
    @GetMapping(value = "/payment/hystrix/ok/{id}")
    public String payment_ok(@PathVariable("id") Long id);
    @GetMapping(value = "/payment/hystrix/timeout/{id}")
    public String payment_timeout(@PathVariable("id") Long id);
}

7.消费端实现类

当消费端通过FeignClient访问服务端接口异常时,去走消费端本地代码

@Component
public class PaymentFeignHystrixServiceImpl implements PaymentFeignHystrixService {
    @Override
    public String payment_ok(Long id) {
        return "payment_ok:服务端繁忙,请稍后再试";
    }

    @Override
    public String payment_timeout(Long id) {
        return "payment_timeout:服务端繁忙,请稍后再试";
    }
}

服务熔断

//服务熔断
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),//时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),//失败率多少次关闭
    })
    @Override
    public String paymentCircuitBreaker(Integer id) {
        if(id<0){
            throw new RuntimeException("*******id 不能小于0");
        }
        String serialNumber = IdUtil.simpleUUID();
        return "paymentCircuitBreaker调用成功,流水号:"+serialNumber;
    }
    @Override
    public String paymentCircuitBreaker_fallback(Integer id) {
        return "id 不能为负数,请稍后再试,"+id;
    }