• Hystrix服务降级fallback


    Hystrix服务降级fallback

    降级配置的核心注解@HystrixCommand

    1、寻找8001自身服务问题

    设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处理,作服务降级fallback

    @HystrixCommand报异常后如何处理,一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法

    package com.zcl.springcloud.service.Impl;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import com.zcl.springcloud.service.PaymentService;
    import org.springframework.stereotype.Service;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * 描述:
     *
     * @author zhong
     * @date 2022-09-19 16:25
     */
    @Service
    public class PaymentServiceImpl implements PaymentService {
        /**
         * 正常访问
         * @param id
         * @return
         */
        @Override
        public String paymentInfo_OK(Integer id) {
            return "线程池:"+Thread.currentThread().getName()+"paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O";
        }
    
        /**
         * 超时演示,服务降级,超过3秒调用下面指定的方法进行返回
         * @param id
         * @return
         */
        @Override
        @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandel",commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
        })
        public String paymentInfo_TimeOut(Integer id) {
            // int ss = 1 / 0; // 模拟内部代码异常,执行兜底方法
            int age = 5;
            try { TimeUnit.SECONDS.sleep(age); } catch (InterruptedException e) { e.printStackTrace(); }
            return "线程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOut,id: "+id+"\t"+"O(∩_∩)O,耗费秒"+age;
        }
    
        /**
         * 服务容错,兜底方法,当上面的程序报错时执行该方法
         * @param id
         * @return
         */
        public String paymentInfo_TimeOutHandel(Integer id){
            return "线程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOutHandel,id: "+id;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    2、添加@EnableCircuitBreaker注解到启动类激活

    3、启动8001支付服务自测fallback

    http://localhost:8001/payment/hystrix/timeout/100
    
    • 1

    当浏览器请求转圈圈3秒后就会输出如下兜底方法,并且后端也会出现sleep interrupted(指定了睡眠5秒)线程睡眠中断报错

    线程池:HystrixTimer-1系统繁忙或运行报错,id: 100(ㄒoㄒ)~~
    
    • 1

    当测试8001内部出现报错的时候也会直接执行兜底方法

    2、80订单微服务自测fallback

    80订单微服务,也可以更好的保护自己,自己也依样画葫芦进行客户端降级保护

    我们自己配置过的热部署方式对java代码的改动明显,但对@HystrixCommand内属性的修改建议重启微服务

    2.1、开启配置

    feign:
      hystrix:
        enabled: true
    
    • 1
    • 2
    • 3

    2.3、修改主启动类

    添加@EnableHystrix注解完成开启,注解包路径import org.springframework.cloud.netflix.hystrix.EnableHystrix;

    2.4、业务类的编写

    在远程调用支付服务时,8001服务的超时时间设置5秒后执行服务降级,而当前的80服务的超时时间最多是1.5秒,而8001服务默认线程睡眠3秒,所以80等待不到支付信息就会给自己进行服务降级

    项目重启后通过:http://localhost/consumer/payment/hystrix/timeout/100进行访问测试

    /**
     * 远程调用微服务睡眠三秒的接口,超时1.5秒后调用服务降级方法
     * @param id
     * @return
     */
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
    })
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        // int age = 1 / 0; // 自测服务降级
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    
    /**
     * 服务熔断方法
     * @param id
     * @return
     */
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    3、以上fallback存在的问题和解决问题

    3.1、每个业务方法对应一个兜底的方法,代码膨胀

    可以通过定义全局的服务降级方法,如果没有指定具体的一对一降级方法就使用默认的

    1. 在类上通过@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")指定全局的服务降级方法
    2. 在需要服务降级的方法上天添加@HystrixCommand注解,需要将原来的去掉,避免重复
    3. 需要定义一个全局的服务降级方法
    package com.zcl.springcloud.controller;
    
    import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import com.zcl.springcloud.service.PaymentHystrixService;
    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 zhong
     * @date 2022-09-19 19:27
     */
    @Slf4j
    @RestController
    @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
    public class OrderHystirxController {
        /**
         * 注入Feign业务接口
         */
        @Resource
        private PaymentHystrixService paymentHystrixService;
    
        /**
         * 定义全局服务降级方法
         * @return
         */
        private String payment_Global_FallbackMethod(){
            return "Global xxx对方系统繁忙或者已宕机,请10秒后在次尝试...";
        }
    
        /**
         * 远程调用微服务睡眠三秒的接口,超时1.5秒后调用服务降级方法
         * @param id
         * @return
         */
        @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)
        {
            String result = paymentHystrixService.paymentInfo_TimeOut(id);
            return result;
        }
    
        /**
         * 服务熔断方法
         * @param id
         * @return
         */
        public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
        {
            return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    通过访问:http://localhost/consumer/payment/hystrix/timeout/100测试

    3.2、服务降级方法与业务逻辑混淆

    既让需要使用到Feign进行远程调用,就必须有接口,我们可以在接口上进行服务降级操作,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦

    服务降级,客户端去调用服务端,碰上服务端宕机或关闭

    3.2.1、未来会遇到的三个常见异常

    1. 运行时异常
    2. 超时异常
    3. 宕机异常

    3.2.2、统一为接口里面的方法进行异常处理

    在原来的控制器里面的服务降级方法都写在了一起,导致代码的耦合度高,也不利于美观,下面就是为了对上提出的问题做一个优化处理

    根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口,重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处(实现类必须要添加@Component注解添加到Spring容器中)

    package com.zcl.springcloud.service;
    
    import org.springframework.stereotype.Component;
    
    /**
     * 描述:接口实现类
     *
     * @author zhong
     * @date 2022-09-19 21:47
     */
    @Component
    public class PaymentFallbackService implements PaymentHystrixService{
        @Override
        public String paymentInfo_OK(Integer id) {
            return "-----PaymentFallbackService fallback paymentInfo_OK,(ㄒoㄒ)~~";
        }
    
        @Override
        public String paymentInfo_TimeOut(Integer id) {
            return "-----PaymentFallbackService fallback paymentInfo_TimeOut,(ㄒoㄒ)~~";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.2.4、YAML配置开启支持

    feign:
      hystrix:
        enabled: true # 开启支持服务降级
    
    • 1
    • 2
    • 3

    3.2.5、开启接口的fallback

    必须要开启调用fallback = PaymentFallbackService.class才能为每一个接口提供

    package com.zcl.springcloud.service;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    /**
     * 描述:调用微服务接口
     *
     * @author zhong
     * @date 2022-09-19 19:24
     */
    @Component
    @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
    public interface PaymentHystrixService {
        xxxx
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.2.6、重启测试

    1. 启动7001Eureka服务注册中心

    2. 启动8001服务提供者

    3. 正常的访问测试:http://localhost/consumer/payment/hystrix/ok/

    4. 故障关闭微服务8001

      客户端自己调用提示

      此时服务端provider已经宕机了,但是我们做了服务降级处理,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器

  • 相关阅读:
    Lucid EDI需求分析及项目注意事项
    Vue中的异步组件
    微客云升级会员制度
    vnpy_ctp源码下载后转变为python可用的处理过程
    优先队列题目:滑动窗口最大值
    来自领导的指点--1 : 小程序和H5 代理问题
    Python中将字典转为成员变量
    CV+Deep Learning——网络架构Pytorch复现系列——basenets(BackBones)(一)
    nprogress进度条的安装与使用
    Scalable Zero-shot Entity Linking with Dense Entity Retrieval
  • 原文地址:https://blog.csdn.net/baidu_39378193/article/details/127255857