Hystrix断路器

Hystrix断路器

在这里插入图片描述
服务雪崩
  • 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他微服务,这就是所谓的 “扇出”,如果扇出的链路上某个微服务的调用时间过长或者不可用,对微服务A的调用就会占有越来越多的系统资源,进而引起系统奔溃,所谓的 “雪崩效应”。
  • 对于高流量的应用来说,单一的后端依赖坑会导致所有服务器上的所有资源都在几秒内饱和。更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发送更多的级联故障。这些表示需要对故障和延迟进行隔离和管理,以便单个依赖关系失败,不能导致整个应用程序奔溃
  • 所以 通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收-流量,然后这个有问题的模块还调用了其他模块,这样就会发生级联故障,或者叫雪崩。

简介
  • Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能保证一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性。

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

  • 功能:服务降级,服务熔断,接近实时的监控,限流,隔离等

Hystrix重要概念
服务降级(fallback)

提供者和消费者都可以进行服务降级。(一般都是放在客户端(消费者))

在这里插入图片描述


服务熔断(break)

[图片上传失败...(image-7789bd-1598540361137)]

服务限流(flowlimit)

[图片上传失败...(image-9541ae-1598540361137)]
新建客户端 cloud-provider-hystrix-payment8001 模块

  1. 引入POM (在客户端(消费者使用))
<!-- hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
  1. yml配置
server:
  port: 8001


spring:
  application:
    name: cloud-provider-hystrix-payment
    

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #单机版
      defaultZone: http://localhost:7001/eureka

  1. 主启动类
@EnableEurekaClient
@SpringBootApplication
public class PaymentHystrixMain8001 {

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

}

  1. service
@Service
public class PaymentService {

    //正常访问方法
    public String paymentInfo_OK(Integer id){
        return "线程池:" + Thread.currentThread().getName() + "\tpaymentInfo_OK,id:" + id;
    }


    //超时访问方法
    public String paymentInfo_TimeOut(Integer id){
        int timeNumber = 3;
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() +
                "\tpaymentInfo_TimeOut,id:" + id + ",耗时:" + timeNumber + "秒";
    }

}
  1. controller
@Slf4j
@RestController
public class PaymentController {

    @Resource
    PaymentService paymentService;

    @Value("${server.port}")    //spring的@Value注解
    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(Integer id){
        String result = paymentService.paymentInfo_OK(id);
        log.info("******result:" + result);
        return result;
    }

}
  1. 启动7001和8001

==http://localhost:8001/payment/hystrix/ok/1==

[图片上传失败...(image-484b55-1598540361137)]

== http://localhost:8001/payment/hystrix/timeout/1==
[图片上传失败...(image-e91c48-1598540361137)]

进行高并发测试:


在这里插入图片描述

在这里插入图片描述

然后去访问http://localhost:8001/payment/hystrix/ok/1,访问速度变慢了。


新建消费者

新建消费者模块 cloud-consumer-feign-hystrix-order80

  1. 引入POM
<dependencies>
    <!-- openfeign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--   hystrix     -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>com.angenin.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

  1. yml文件
server:
  port: 80


eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:7001/eureka

#需要加上,否则会报错
ribbon:
  ReadTimeout: 4000
  ConnectTimeout: 4000

  1. 主启动类
@EnableEurekaClient
@EnableFeignClients
@SpringBootApplication
public class OrderHystrixMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderHystrixMain80.class, args);
    }

}

  1. service
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {

    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);
    
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
  1. controller
@Slf4j
@RestController
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;


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

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }

}

  1. 启动jmeter,然后再进行测试
在这里插入图片描述

安装JMeter
JMeter下载地址:http://jmeter.apache.org/download_jmeter.cgi

下载tgz和zip都可以:

在这里插入图片描述

启动jmeter 测试

在这里插入图片描述

故障现象、导致原因以及解决

现象:
[图片上传失败...(image-153dfb-1598540361137)]
解决:

在这里插入图片描述
服务降级
在这里插入图片描述
提供者 (8001模块)
  1. 修改8001中PaymentService的paymentInfo_TimeOut方法,并添加paymentInfo_TimeOutHandler方法:
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
            //设置自身超时调用时间的峰值为3秒,峰值内可以正常运行,超过了需要有兜底的方法处理,服务降级fallback
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public String paymentInfo_TimeOut(Integer id){
        int timeNumber = 5;
        //int i = 1 / 0;
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() +
                "\tpaymentInfo_TimeOut,id:" + id + ",耗时:" + timeNumber + "秒";
    }
    public String paymentInfo_TimeOutHandler(Integer id){
        return "8001提供者,线程池:" + Thread.currentThread().getName() + 
                "\tpaymentInfo_TimeOutHandler系统繁忙,请稍后再试,id:" + id;
    }
  1. 然后在8001的主启动类上添加@EnableCircuitBreaker注解,启用断路器。

[图片上传失败...(image-84dc04-1598540361137)]

消费者 (80模块)
在这里插入图片描述
  1. yml添加 :
feign:
  hystrix:
    enabled: true

  1. 在主启动类添加@EnableHystrix注解。

  2. 修改OrderHystrixController的paymentInfo_TimeOut方法,并添加paymentTimeOutFallbackMethod方法:

    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){
        return "消费者80,支付系统繁忙";
    }

启动7001,8001,80,http://localhost/consumer/payment/hystrix/timeout/1(如果是提供者那边出问题,并且消费者设置了fallback,会优先进入消费者的fallback)

在这里插入图片描述

在这里插入图片描述
代码膨胀的解决办法:
在这里插入图片描述
在这里插入图片描述

服务熔断

在这里插入图片描述
  1. 在8001的PaymentService中添加
在这里插入代码片    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),                      //开启断路器
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),         //请求总数阈值(默认20)
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),   //休眠时间窗口期(休眠多久进入半开模式(单位毫秒,默认5秒))
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),       //请求次数的错误率达到多少跳闸(百分率%,默认50%)
})
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        if(id < 0){
            throw  new RuntimeException("****id 不能为负数");
        }
        String serialNumber = IdUtil.simpleUUID();

        return  Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
    }
    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
        return "id 不能为负数,请稍后再试, id: " + id;
    }

  1. 在8001的PaymentController中添加
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("******result:" + result);
    return result;
}
  1. 启动7001和8001
    http://localhost:8001/payment/circuit/-1(输入超过6次进入熔断)
    [图片上传失败...(image-2317ba-1598540361137)]
  • 熔断10秒内就算是正确的请求也返回错误信息。
  • 10秒后进入半开模式,对请求进行处理,此时如果是正确的请求,那么就关闭熔断,否则再次进入熔断,10秒后再次开启半开模式,对请求进行处理,直到半开模式处理到正确请求。

总结

https://martinfowler.com/bliki/CircuitBreaker.html

在这里插入图片描述
  • 我的总结:如果请求次数的错误率超过指定值,开启熔断,经过一段时间后,变为半开模式,然后放进一个请求进行处理,如果请求处理成功,关闭熔断;如果还是报错,继续进入熔断,再经过一段时间后,变为半开模式,再进行对下一个请求进行处理,一直在熔断,半开模式来回切换,直到请求成功,关闭熔断。
在这里插入图片描述
  • 官网步骤:
在这里插入图片描述
  • 断路器在什么情况下开始起作用:


    在这里插入图片描述

    在这里插入图片描述
  • 断路器开启或关闭的条件:


    在这里插入图片描述

    断路器打开之后:

在这里插入图片描述
服务限流

会在后面高级篇alibaba的Sentinel讲解。

Hystrix工作流程:

在这里插入图片描述

在这里插入图片描述

服务监控HystrixDashboard

简介
除了隔离依赖服务调用以外,

仪表盘9001

  1. 新建模块 cloud-consumer-hystrix-dashboard9001

  2. pom

<dependencies>
    <!--   hystrix仪表盘图形化     -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    <dependency>
        <groupId>com.angenin.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  1. http://localhost:9001/hystrix
在这里插入图片描述

断路器演示(服务监控hystrixDashboard)
注意:所有微服务提供者都需要在pom中引入监控依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在8001的主启动类中添加:

   /**
    * 此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
    * ServletRegistrationBean因为SpringBoot的默认路径不是 “/hystrix.stream"
    * 只要在自己的项目里配置上下的servlet就可以了
    */
   @Bean
   public ServletRegistrationBean getServlet() {
       HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet() ;
       ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
       registrationBean.setLoadOnStartup(1);
       registrationBean.addUrlMappings("/hystrix.stream");
       registrationBean.setName("HystrixMetricsStreamServlet");
       return  registrationBean;
   }
在这里插入图片描述

在浏览器输入http://localhost:8001/payment/circuit/1http://localhost:8001/payment/circuit/-1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343