微服务使用 Hystrix 实现服务降级

一、为什么要服务降级

设想一个场景,很多人都在请求一个接口,此时这个接口就会变得非常繁忙,调用者就要等待很长时间,而微服务是互相调用的,所以微服务的调用者即客户端回等待很长时间,给用户造成不好的使用体验。

而服务降级,就是指在服务端发生超时或者出错的时候,客户端要及时的屏蔽这些不好的信息,给用户一个良好的体验,比如在请求超时的时候,固定如果超过 3 秒就提示用户系统繁忙请稍后再试。

二、服务降级具体实现

2.1、服务端

如果实在服务端,即服务的提供方,我们可以在系统业务类上加一个 HystrixCommand 注解。

同时在主启动类上加一个 @EnableCircuitBreaker 注解。

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

业务类:

/**
* HystrixCommand 服务降级:
 *  在微服务调用中的服务端
 *  发生超时或者出现异常之后调用兜底的方法处理;
 *
 * @param id ID
 * @return 返回提示信息
 */
@HystrixCommand(
        fallbackMethod = "paymentInfoTimeOutHandler",
        commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
        })
public String paymentInfoTimeOut(Integer id) {
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "线程池: " + Thread.currentThread().getName() + " paymentInfo_OK, id: " + id + "\t" + "耗时3秒钟!";
}
/**
 * 具体的处理方法
 *
 * @param id ID
 * @return 返回提示信息
 */
public String paymentInfoTimeOutHandler(Integer id) {
    return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOutHandler, id: " + id + "\t" + "系统繁忙请稍后再试!";
}

该注解的作用是,先设置一个兜底的方法来应对突发情况,如果超过了设置的时间或者出现了异常就触发这个方法。

此时我们如果再去访问超时的接口就会收到提示信息。

2.2、客户端

对于使用 Feign 进行调用的客户端,我们也可以在控制器上加上类似的方法。

/**
 * 客户端服务降级:
 *  请求不到信息,这几出提示信息
 *
 * @param id
 * @return
 */
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")  //3秒钟以内就是正常的业务逻辑
})
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
    String result = paymentHystrixService.paymentInfoTimeOut(id);
    log.info("*******result:" + result);
    return result;
}
/**
 * 兜底方法
 *
 * @return 返回提示信息
 */
public String paymentTimeOutFallbackMethod() {
    return "我是消费者80,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)";
}

同时也要在主启动类上加上一个注解 @EnableHystrix

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

这样配置之后客户端可以更好的保护自己。

三、简化代码

对于上述代码有两个问题:

  1. 每个业务方法对应一个兜底的方法,代码膨胀;
  2. 应该让统一和自定义的方法分开。

对此我们可以使用 @DefaultProperties(defaultFallback = "") 注解表示不配置兜底方法 默认触发的方法

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "paymentGlobalFallbackMethod")
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;

    /**
     * 客户端服务降级:
     *  请求不到信息,这几出提示信息
     *
     * @param id
     * @return
     */
    @HystrixCommand
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
        String result = paymentHystrixService.paymentInfoTimeOut(id);
        log.info("*******result:" + result);
        return result;
    }

    /**
     * 兜底方法
     *
     * @return 返回提示信息
     */
    public String paymentGlobalFallbackMethod() {
        return "我是消费者80,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)";
    }
}

其中 PaymentHystrixService 是 Feign 调用服务的接口类入口。

如上,我们在 @HystrixCommand 注解中没有配置兜底方法,但是最后程序回去执行 paymentGlobalFallbackMethod 方法,这就是默认配置。

如果我们想自定义方法可以重写在注解中配置自己的兜底方法。

此时还有一个问题就是兜底方法和调用方法出现在一起了,从而导致了代码膨胀。

我们可以使用一个类 PaymentFallbackService 去继承我们的 Feign 的客户端接口,这样服务降级系统就会自动去调用已经实现的方法作为兜底方法。

@Component
public class PaymentFallbackService implements PaymentHystrixService {
    @Override
    public String paymentInfo_OK(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_OK , (┬_┬)";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_TimeOut , (┬_┬)";
    }
}

别忘了在 yml 中配置:

feign:
  hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。

此时可以直接在 @FeignClient 注解中加一个属性 fallback 设置为我们的实现类。

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {......}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硕子鸽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值