• Hystrix断路器


    Hystrix断路器的概述

    分布式系统面临的问题

     

    Hystrix是什么

    Hystrix能干啥

    1.         服务降级

    2.         服务熔断

    3.         接近实时的监控

    Hystrix官网资料

    https://github.com/Netflix/Hystrix/wiki/How-To-Use

    Hystrix官宣,停更进维

    Hystrix的重要概念

    服务降级(fallback),服务熔断(break),服务限流(flowlimit)

    在分布式系统中,服务与服务之间依赖错综复杂,一种不可避免的情况就是某些服务将会出现失败。Hystrix是一个用于处理分布式系统的延时和容错的开源库,它提供了服务与服务之间的容错功能,主要体现在延迟容错和容错,从而做到控制分布式系统中的联动故障。Hystrix通过隔离服务的访问点,阻止联动故障,并提供故障的解决方案,从而提高了这个分布式系统的弹性。

    服务降级

    “断路器”本身就是一种开关装置。当某个服务单元发生故障后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的,可处理的备选响应(fallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要地占用,从而避免了故障在分布式系统中的蔓延,

    乃至雪崩。

    哪些情况会出现降级?

    l  程序运行异常

    l  超时

    l  服务熔断出发服务降级

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

    服务熔断

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

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

    服务限流

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

    Hystrix案例

    Hystrix支付微服务构建

    构建工程

    1.   新建cloud-provider-hystrix-payment8001工程

    2.   添加pom
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fengyangcai.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    3.   写yml
    server:
      port: 8001
    spring:
      application:
        name: cloud-provider-hystrix-payment
    eureka:
      client:
        fetch-registry: true
        register-with-eureka: true
        service-url:
          defaultZone: http://localhost:7003/eureka
          #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版本
    4.   主启动类
    @SpringBootApplication
    @EnableEurekaClient
    //@EnableDiscoveryClient
    //@EnableCircuitBreaker//断路器的注解
    public class HystrixPaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(HystrixPaymentMain8001.class,args);
        }
    }
    5.   业务类
    Service
    @Service
    public class PaymentService {
    //正常的访问方法
        public String paymentInfo_OK(Integer id){
            return "线程池:"+Thread.currentThread().getName()+"paymentInfo_OK,id: "+id+"/t"+"哈哈";
        }
        //一般Hstrix降级放在客户端,这里放在服务端了只是演示而已。
        /* @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {
             @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
     })*/
        public String paymentInfo_TimeOut(Integer id){
                int time=1;
               // int a=10/0;
            try {
                TimeUnit.SECONDS.sleep(time);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return "线程池:"+Thread.currentThread().getName()+"--paymentInfo_TimeOut,id: "+id+"/t"+"哈哈耗时:"+time+"秒";
        }
    
        public String payment_TimeOutHandler(Integer id){
            return  "线程池:"+Thread.currentThread().getName()+"--paymentInfo_TimeOut,id: "+id+"/t"+"####系统繁忙呜呜呜##";
        }
    }
    Controller层
    @RestController
    @Slf4j
    public class PaymentController {
        @Resource
        private PaymentService paymentService;
        @Value("${server.port}")
        private String serverPort;
        @GetMapping("/payment/hystrix/ok/{id}")
        public String paymentInfo_OK(@PathVariable("id")Integer id){
            String result = paymentService.paymentInfo_OK(id);
            log.info("&&&&&&result"+result);
            return result;
        }
        @GetMapping("/payment/hystrix/timeout/{id}")
        public String paymentInfo_timeout(@PathVariable("id")Integer id){
            String result = paymentService.paymentInfo_TimeOut(id);
            log.info("*******result"+result);
            return result;
        }
    }
    
    
    6.   测试

     出现情况:

    Tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。出现两个都在自己转圈圈。

    上述结论

     

    如何解决?解决的要求

    创建cloud-consumer-feign-hystrix-order80消费端

    Pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.fengyangcai.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    Yml

    server:
      port: 80
    spring:
      application:
        name: cloud-consumer-feign-hystrix-order
    eureka:
      client:
        register-with-eureka: false #表示是否将自己注册进EurekaServer默认为true
        fetch-registry: true #是否从EurekaServer捉取已有的注册信息,默认为true.单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        service-url:
          #defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka
          defaultZone: http://localhost:7003/eureka

    主函数

    其中@EnableCircuitBreaker就是引入了hystrix的熔断注解标签

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

    使用openFeign在service层调用服务

    @Component
    @FeignClient(value = "cloud-provider-hystrix-payment")
    public interface PaymentFeignHystrixService {
        @GetMapping("/consumer/payment/hystrix/ok/{id}")
        public String paymentInfo_OK(@PathVariable("id")Integer id);
    
        @GetMapping("/consumer/payment/hystrix/timeout/{id}")
        public String paymentInfo_timeout(@PathVariable("id")Integer id);
    
    }

    Controller层

    其中@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")是全局的一个处理方法标签。

    @HystrixCommand是hystrix的一个处理标签。

    @RestController
    @Slf4j
    @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
    public class OrderFeignHystrixController {
    
        @Resource
        private PaymentFeignHystrixService paymentFeignHystrixService;
    
        @GetMapping("/payment/hystrix/ok/{id}")
        public String paymentInfo_OK(@PathVariable("id")Integer id){
            return paymentFeignHystrixService.paymentInfo_OK(id);
        }
        //一般Hstrix降级放在客户端
        @GetMapping("/payment/hystrix/timeout/{id}")
       /* @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
        })*/
        @HystrixCommand
        public String paymentInfo_timeout(@PathVariable("id")Integer id){
    
            return paymentFeignHystrixService.paymentInfo_timeout(id);
        }
    
        public String payment_TimeOutHandler(Integer id){
            return  "我是消费方80.对方支付系统繁忙请稍后访问";
        }
        //全局fallback方法
        public String payment_Global_FallbackMethod(){
            return "全局的降级处理方法";
        }
    }

     上面是使用了服务降级的配置

    @HystrixCommand
    在官网上是程序,工程落地都是使用配置方式

    @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
    中,fallbackMethod是回路的执行方法,1500代表1.5秒,执行超过这个时间就执行回路方法。

     总结一下使用

    引入依赖,在yml文件中配置

    feign:
      hystrix:
        enabled: true
    在启动类上加上
    @EnableHystrix,如果是熔断加@EnableCircuitBreaker
    业务类方法上加 @HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
    这个导致代码膨胀,每个业务方法对应了一个兜底的方法。我们要统一和自定义的分开。

    在feign的接口上配置
    @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")其中 payment_Global_FallbackMethod就是兜底的方法。

     

    这样还是把处理的兜底方法放在同一个类啊。

     

    下面我们解决这个问题

    为Feign客户端定义的接口添加一个服务降级处理的实现类

    @Component
    public class PaymentFallbackService implements PaymentFeignHystrixService{
        @Override
        public String paymentInfo_OK(Integer id) {
            return "-----PaymentFallbackService fall back";
        }
    
        @Override
        public String paymentInfo_timeout(Integer id) {
            return "-----PaymentFallbackService fall back-paymentInfo_timeout";
        }
    }

     在yml上要加上

     

     Hystrix之服务熔断理论

     大师的论文:https://martinfowler.com/bliki/CircuitBreaker.html

    实操

    修改我们上面的服务提供工程cloud-provider-hystrix-payment8001

    配置PaymentService

      //======服务熔断
        @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"),//失败率达到多少后跳闸
        })
        public String paymentCircuitBreaker(@PathVariable("id")Integer id){
            if (id<0){
                throw new RuntimeException("***********id 不能为负数");
            }
            //使用hutool工具吧创建一个没有-的字符串
            String serialNumber = IdUtil.simpleUUID();
            return  Thread.currentThread().getName()+"	"+"调用成功,流水号为: "+serialNumber;
        }
    
        public String  paymentCircuitBreaker_fallback(@PathVariable("id")Integer id){
            return "id 不能为负数,请稍后再试,--paymentCircuitBreaker_fallback";
        }

    why配置这些参数?

    intellj idea 使用ctrl+N的查看HystrixCommandProperties 类,这个类记载了HystrixCommand的全部属性

    在controller层

     //====服务熔断
        @GetMapping("/payment/hystrix/paymentCircuitBreaker")
        public String paymentCircuitBreaker(@PathVariable("id")Integer id){
    
            String result = paymentService.paymentCircuitBreaker_fallback(id);
            log.info("****result:"+result);
            return result;
        }

    测试

     结论

     官网断路器流程图

     断路器在什么情况下开始起作用?

     

     断路器打开之后

     所有的配置

     

     

    服务限流

    参照alibaba的sentinel说明

    hystrix的工作流程

    https://github.com/Netflix/Hystrix/wiki/How-it-Works

    官网图例

    网上找

    服务监控hystrixDashboard

    概述

    仪表盘9001

    新建cloud-consumer-hystrix-dashboard9001

    pom

     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    yml

    server:
      port: 9001

    hystrixDashboardMain9001 +新的注解@EnableHystrixDashboard

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

    所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置

    启动cloud-consumer-hystrix-dashboard9001该微服务后续将监控微服务8001

    http://localhost:9001/hystrix

     

     要在监控的主启动类上配置

     使用观察监控窗口

    填写监控地址http://localhost:8001/hystrix.stream

     测试地址

     

     

     

     

     




    
    
    









  • 相关阅读:
    关于命题“网络规划中一个VLAN要对应一个网段”的证明
    详谈为何两台主机网络掩码不一致可能导致ping不通
    为什么电脑的ip地址要和网关的ip同一个子网才可以上网?
    快速理解VirtualBox的四种网络连接方式(最详细)
    Ubuntu 16.04下安装OpenStack(juno)之add the compute service报错分析
    Ubuntu 16.04下安装OpenStack(juno) 之add the image service报错分析
    曲线
    Best Cow Fences
    愤怒的牛
    斐波那契数
  • 原文地址:https://www.cnblogs.com/fengyangcai/p/13303490.html
Copyright © 2020-2023  润新知