全局捕获异常能用 为啥要用降级

坑:

fallback method wasn’t found

  1. 目标方法和回退方法参数和返回类型要一致
  2. @HystrixCommand(fallbackMethod = fallbackHi”)
  3. public String getHi(String x) {
  4. String msg = restTemplate.getForObject(“http://jack/hi“, String.class);
  5. return msg;
  6. }
  7. public String fallbackHi(String x){
  8. return cant say hi, and get: + x;
  9. }
  10. “`
//如果需要服务降级,那么会调用哪个方法

    /**
     * 设置自身调用超时时间的峰值,峰值内可以正常运行,  超过了需要有兜底的方法处理,做服务降级fallback
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "sleep_TimeOutHandler",
            commandProperties={
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
    })
    public String sleep(String id){
        try {
            Thread.sleep(3000);
        }catch (Exception e){
            log.info("睡眠异常");
        }
        return "调用sleep成功----端口号:"+SERVER_PORT+"id为: "+id;
    }

    public String sleep_TimeOutHandler(String id){
        return "线程池:"+Thread.currentThread().getName()+"o(╥﹏╥)o";
    }
}

在主启动类开启降级
@EnableCircuitBreaker 或者@EnableHystrix

实现服务降级有两种方式:

第一种就是实现HystrixCommand接口,并且重写里面的run 和 服务降级时需要调用的 getFallback()

public class QueryOrderIdCommand extends HystrixCommand<Integer> {
    private final static Logger logger = LoggerFactory.getLogger(QueryOrderIdCommand.class);
    private OrderServiceProvider orderServiceProvider;

    public QueryOrderIdCommand(OrderServiceProvider orderServiceProvider) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("orderService"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("queryByOrderId"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withCircuitBreakerRequestVolumeThreshold(10)//至少有10个请求,熔断器才进行错误率的计算
                        .withCircuitBreakerSleepWindowInMilliseconds(5000)//熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试
                        .withCircuitBreakerErrorThresholdPercentage(50)//错误率达到50开启熔断保护
                        .withExecutionTimeoutEnabled(true))
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties
                        .Setter().withCoreSize(10)));
        this.orderServiceProvider = orderServiceProvider;
    }

    @Override
    protected Integer run() {
        return orderServiceProvider.queryByOrderId();
    }

    @Override
    protected Integer getFallback() {
        return -1;
    }
}

image.png

  • execute()实际是调用了queue().get()
  • queue()实际调用了toObservable().toBlocking().toFuture()

第二种就是通过注解

触发服务降级的条件:

延时,默认的访问延时为1s 解决方案: 服务延时
程序bug运行时异常 解决方案: 服务降级
服务宕机(把服务提供者关掉,服务消费者自己兜底) 解决方案: 服务降级
服务熔断触发服务降级

  public String sleep(String id){
//        try {
////            Thread.sleep(3000);
////        }catch (Exception e){
////            log.info("睡眠异常");
////        }

        int b=4/0;
        return "调用sleep成功----端口号:"+SERVER_PORT+"id为: "+id;
    }


一般服务降级都放在消费者,提供者也需要有自己的保护机制

如果所有的服务降级都这样写,那么出现的问题就是: 代码量太大了

解决办法一:

在一个类上加@DefaultProperties全局服务降级
注意:服务降级的类上面要加 @HystrixCommand 来表明他需要服务降级方法。

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author zzyy
 * @create 2020/3/6 23:20
 **/
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;


       @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_OK(id);
    }

       @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    /*@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })*/
    @HystrixCommand
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        //int age = 10/0;
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }

    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

    /**
     * 全局fallback
     *
     * @return
     */
    public String payment_Global_FallbackMethod() {
        return "Global异常处理信息,请稍后重试.o(╥﹏╥)o";
    }
}

解决办法二:

实现Feign的服务调用接口,重写里面的方法
image.png
然后在接口处声明兜底类

@Component
@FeignClient(value = "cloud-provider-hystrix-payment",fallback = GetPaymentFallback.class)
public interface GetPaymentService {

    @GetMapping("/getSleet")
    public String sleet(@RequestParam("id") String id);

    @GetMapping("/getSuccess")
    public String succ(@RequestParam("id") String id);