• Hystrix断路器


    Hystrix介绍

    在微服务场景中,通常会有很多层的服务调用。如果一个底层服务出现问题,故障会被向上传播给用户。我们需要一种机制,当底层服务不可用时,可以阻断故障的传播。这就是断路器的作用。他是系统服务稳定性的最后一重保障。

    在springcloud中断路器组件就是Hystrix。Hystrix也是Netflix套件的一部分。他的功能是,当对某个服务的调用在一定的时间内(默认10s),有超过一定次数(默认20次)并且失败率超过一定值(默认50%),该服务的断路器会打开。返回一个由开发者设定的fallback。

    fallback可以是另一个由Hystrix保护的服务调用,也可以是固定的值。fallback也可以设计成链式调用,先执行某些逻辑,再返回fallback。

    Hystrix作用:

    能够实现 服务的降级,服务的熔断,接近实时的监控

    官网资料 https://github.com/Netflix/Hystrix/wiki/How-To-Use

    Hystrix官宣,停更进维 https://github.com/Netflix/Hystrix

    Hystrix重要概念

    服务降级

            服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback

    哪些情况会触发降级

            程序运行异常

            超时

            服务熔断触发服务降级

            线程池/信号量打满也会导致服务降级

    服务熔断

            类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

    就是保险丝 服务的降级->进而熔断->恢复调用链路

    服务限流  

            秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

    hystrix案例

      在上一节整合openfeign的基础上整合hystrix 主要用到了这个三个服务

      模拟故障

      服务提供者有一个耗时的服务,消费者调用一次访问特别慢,转圈但是最终可以访问

     但是不影响这个接口

     当开启多线程测试,访问量为2000去访问

    再次访问

    也开始转圈了

    导致原因

          8001同一层次的其他接口服务被困死,因为tomcat线程里面的工作线程已经被挤占完毕

          80此时调用8001,客户端访问响应缓慢,转圈圈

    上诉结论

           正因为有上述故障或不佳表现,才有我们的降级/容错/限流等技术诞生

           如何解决?解决的要求

    超时导致服务器变慢(转圈) 超时不再等待

           出错(宕机或程序运行出错) 出错要有兜底

    解决 

             对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级

             对方服务(8001)down机了,调用者(80)不能一直卡死等待,必须有服务降级

             对方服务(8001)OK,调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者),自己处理降级

    服务降级

         pom文件加入依赖

    <!--整合熔断器-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

           降低配置  @HystrixCommand

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

    业务类启用

       

    package com.shiwen.controller;
    
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import com.shiwen.entity.CommonResult;
    import com.shiwen.entity.Payment;
    import com.shiwen.service.PaymentService;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.concurrent.TimeUnit;
    
    
    /**
     * 支付表(Payment)表控制层
     *
     * @author wangjie
     * @since 2020-09-27 17:19:14
     */
    
    @RestController
    @RequestMapping("payment")
    public class PaymentController {
        /**
         * 服务对象
         */
        @Autowired
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverPort;
    
        /**
         * 通过主键查询单条数据
         *
         * @param id 主键
         * @return 单条数据
         */
        @ApiOperation(value = "根据id查询数据")
        @GetMapping("select-one/{id}")
        public CommonResult selectOne(@PathVariable  Long id) {
            Payment payment = this.paymentService.queryById(id);
            return new CommonResult(200,"成功"+serverPort,payment);
        }
    
        /**
         * 增加
         */
        @ApiOperation(value = "添加数据")
        @PostMapping("add")
        public CommonResult addPayment(@RequestBody Payment payment){
            boolean insert = paymentService.insert(payment);
            if(insert==true){
                return new CommonResult(200,"插入成功人不输"+serverPort,true);
            }else{
                return new CommonResult(500,"插入失败"+serverPort,false);
            }
        }
    
        /**
         * 编写超时程序
         */
        @GetMapping("timeout")
        @HystrixCommand(fallbackMethod = "timeOutMethod",commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000") //三秒以内正常
        })
        public CommonResult timeOutMethods(){
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new CommonResult(200,"超时服务",serverPort);
        }
    
        //兜底的方法
        public  CommonResult  timeOutMethod(){
            return new CommonResult(200,"系统占时繁忙请稍后重试",serverPort);
        }
    
    
    }
    

     启动类添加@EnableHystrix

     一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法timeOutMethod图示

     这样写一个方法一个兜底的方法代码太过臃肿,通过注解@DefaultProperties(defaultFallback = "globalTimeOutMethod")配置全局的兜底方法

    @RestController
    @RequestMapping("/order")
    @DefaultProperties(defaultFallback = "globalTimeOutMethod")
    public class FeignController {
    
        @Autowired
        private FeignService feignService;
    
        @GetMapping("/selete/{id}")
        public CommonResult getUserById(@PathVariable Long id){
            return feignService.selectOne(id);
        }
    
        @GetMapping("/timeout")
        //@HystrixCommand(defaultFallback = "orderTimeOutMethod",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
        @HystrixCommand
        public CommonResult getTimeOut(){
            return feignService.timeOutMethods();
        }
    
    
        public CommonResult orderTimeOutMethod(){
            return new CommonResult(200,"消费端兜底的方法","===================");
        }
    
        public CommonResult globalTimeOutMethod(){
            return new CommonResult(200,"消费端全局的兜底方法","=====================");
        }
    }
    

      还有一个问题是兜底的方法和业务代码混合在一起 以下的降级实在80消费端完成的

    第一步创建

    FeignServiceImpl类实现FeignService接口 编写每一个方法对应的兜底内容
    @Component
    public class FeignServiceImpl  implements FeignService {
        @Override
        public CommonResult selectOne(Long id) {
            return null;
        }
    
        @Override
        public CommonResult timeOutMethods() {
            return new CommonResult(200,"我是一接口的形式实现兜底方法的","====================");
        }
    }

    第二步 FeignService 接口指名兜底的类fallback = FeignServiceImpl.class

    @FeignClient(value = "CLOUD-PAYMENT-SERVICE",fallback = FeignServiceImpl.class)
    public interface FeignService {
    
        @GetMapping("payment/select-one/{id}")
        CommonResult selectOne(@PathVariable("id") Long id);
    
    
        @GetMapping("payment/timeout")
        CommonResult timeOutMethods();  

    第三步controller调用
    package com.shiwen.controller;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.shiwen.entity.CommonResult;
    import com.shiwen.service.FeignService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author wangjie
     * @Title: FeignController
     * @Description: openfeign服务的调用
     * @company: 西安石文软件有限公司
     * @date 2020/10/1411:13
     */
    @RestController
    @RequestMapping("/order")
    //@DefaultProperties(defaultFallback = "globalTimeOutMethod")
    public class FeignController {
    
        @Autowired
        private FeignService feignService;
    
        @GetMapping("/selete/{id}")
        public CommonResult getUserById(@PathVariable Long id){
            return feignService.selectOne(id);
        }
    
        @GetMapping("/timeout")
        //@HystrixCommand(defaultFallback = "orderTimeOutMethod",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
        //@HystrixCommand
        public CommonResult getTimeOut(){
            return feignService.timeOutMethods();
        }
    
    
        public CommonResult orderTimeOutMethod(){
            return new CommonResult(200,"消费端兜底的方法","===================");
        }
    
        public CommonResult globalTimeOutMethod(){
            return new CommonResult(200,"消费端全局的兜底方法","=====================");
        }
    }
    

      yml编写 开启hystrix

    feign:
    hystrix:
    enabled: true
    测试依次启动注册中心,服务提供者,消费者
    访问http://localhost/order/timeout 当程序访问超时就会走实现类了兜底

     服务熔断

    说白了就是程序不正常了,再这一段时间访问并不会立马崩掉,而是访问失败的次数大于设定的比率,就会跳闸,对服务实现降级,之后走的是兜底方法,当程序再次恢复正常时,并不会里面返回正确的数据。还是走的是兜底的方法,同样需要在一段时间访问成功的次数大于设定的比率,会再次跳闸。程序恢复正常(就是检测到改节点微服务调用响应正常后,恢复调用链路)

    服务熔断需要配置的参数

    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
    @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器
    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数
    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间范围
    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸
    })

    package com.shiwen.controller;
    
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import com.shiwen.entity.CommonResult;
    import com.shiwen.entity.Payment;
    import com.shiwen.service.PaymentService;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.concurrent.TimeUnit;
    
    
    /**
     * 支付表(Payment)表控制层
     *
     * @author wangjie
     * @since 2020-09-27 17:19:14
     */
    
    @RestController
    @RequestMapping("payment")
    public class PaymentController {
        /**
         * 服务对象
         */
        @Autowired
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverPort;
    
        /**
         * 通过主键查询单条数据
         *
         * @param id 主键
         * @return 单条数据
         */
        @ApiOperation(value = "根据id查询数据")
        @GetMapping("select-one/{id}")
        @HystrixCommand(fallbackMethod = "timeOutMethodAll",commandProperties = {
                @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数
                @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间范围
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸
        })
        public CommonResult selectOne(@PathVariable  Long id) {
            if(id<0.0){
               int i=10/0;
               return new CommonResult(200,"成功"+serverPort,"程序出错了");
            }else {
                Payment payment = this.paymentService.queryById(id);
                return new CommonResult(200,"成功"+serverPort,payment);
            }
        }
    
        /**
         * 增加
         */
        @ApiOperation(value = "添加数据")
        @PostMapping("add")
        public CommonResult addPayment(@RequestBody Payment payment){
            boolean insert = paymentService.insert(payment);
            if(insert==true){
                return new CommonResult(200,"插入成功人不输"+serverPort,true);
            }else{
                return new CommonResult(500,"插入失败"+serverPort,false);
            }
        }
    
        /**
         * 编写超时程序
         */
        @GetMapping("timeout")
        public CommonResult timeOutMethods(){
            try {
                TimeUnit.SECONDS.sleep(6);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new CommonResult(200,"超时服务",serverPort);
        }
    
        //兜底的方法
        public  CommonResult timeOutMethodAll(Long id){
            return new CommonResult(200,"系统占时繁忙请稍后重试",serverPort);
        }
    
    
    }
    

      

    小蘑菇
  • 相关阅读:
    maven创建的quickstart项目生成可执行jar
    spring boot 修改banner
    spring boot项目打包成war
    node集成mysql——pool连接池
    adb命令模拟按键输入keycode
    Spring 全局异常处理
    程序开发中版本管理之命名规则及格式
    群晖Nas中搭建Intellij Idea的LicenseServer服务
    uml-类图书写指南
    Spring Boot + Docker + K8S 简单示例
  • 原文地址:https://www.cnblogs.com/wang66a/p/13840761.html
Copyright © 2020-2023  润新知