Hystrix断路器

一、Hystrix概述

在这里插入图片描述Hystrix:中文:豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。

服务雪崩:

1、服务雪崩介绍:

分布式系统面临的问题:服务雪崩

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图:
在这里插入图片描述
如果各个服务正常运行,那大家齐乐融融,高高兴兴的,但是如果其中一个服务崩坏掉会出现什么样的情况呢?

在这里插入图片描述
上图中:当Service A的流量波动很大,流量经常会突然性增加!那么在这种情况下,就算Service A能扛得住请求,Service B和Service C未必能扛得住这突发的请求。比如这时候Service C由于请求访问过多变得不可用了。

此时,假如Service C因为抗不住请求,变得不可用。那么Service B的请求也会阻塞,慢慢耗尽Service B的线程资源,Service B就会变得不可用。紧接着,Service A也会不可用。

总结:即服务C的不可用,导致原先可用的服务B慢慢也变得不可用了,再然后,就是服务B的不可用也慢慢导致 原本正常的服务A变得不可用,就好像一条串联电路中,一个断路导致全部不能正常工作一样。



在这里插入图片描述
在这里插入图片描述

简单地讲。一个服务失败,导致整条链路的服务都失败的情形,我们称之为服务雪崩



2、引起雪崩的原因和服务雪崩的三个阶段
原因大致有四:
1、硬件故障;
2、程序Bug;
3、缓存击穿(用户大量访问缓存中没有的键值,导致大量请求查询数据库,使数据库压力过大);
4、用户大量请求;

服务雪崩的三个阶段:
第一阶段: 服务不可用;
第二阶段:调用端重试加大流量(用户重试/代码逻辑重试);
第三阶段:服务调用者不可用(同步等待造成的资源耗尽);

3、解决服务雪崩的方案
1) 应用扩容(扩大服务器承受力)

加机器
升级硬件
2)流量控制(超出限定流量,返回类似重试页面让用户稍后再试)

限流
关闭重试
3) 缓存

将用户可能访问的数据大量的放入缓存中,减少访问数据库的请求。

4)服务降级

服务接口拒绝服务
页面拒绝服务
延迟持久化
随机拒绝服务
5) 服务熔断

Hystrix简介:

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

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

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

fallback:服务降级/应急方案
在这里插入图片描述
官网资料:https://github.com/Netflix/Hystrix/wiki/How-To-Use

在这里插入图片描述

停更维护:https://github.com/Netflix/Hystrix

在这里插入图片描述

在这里插入图片描述

二、Hystrix重要概念:

fallback:服务降级/应急方案

服务熔断:

当下游的服务因为某种原因突然变得不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用

在这里插入图片描述

服务降级

服务降级主要有两种场景:

一、当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度!

二、当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户!

已经看出来,第一个场景怎么和服务熔断的概念有异曲同工之妙,没错,服务熔断可视为降级方式的一种!

在这里插入图片描述

结合上述场景,在实际的项目中,采用以下的方式来完成降级工作

  1. 梳理出核心业务流程和非核心业务流程。然后在非核心业务流程上加上开关,一旦发现系统扛不住,关掉开关,结束这些次要流程。
  2. 一个微服务下肯定有很多功能,那自己区分出主要功能和次要功能。然后次要功能加上开关,需要降级的时候,把次要功能关了吧!
  3. 降低一致性了,即将核心业务流程的同步改异步,将强一致性改最终一致性。

在这里插入图片描述
Hystrix是Netflix公司开源的一款容错框架。 它可以完成以下几件事情:

  • 资源隔离,包括线程池隔离和信号量隔离,避免某个依赖出现问题会影响到其他依赖。

  • 断路器,当请求失败率达到一定的阈值时,会打开断路器开关,直接拒绝后续的请求,并且具有弹性机制,在后端服务恢复后,会自动关闭断路器开关。

  • 降级回退,当断路器开关被打开,服务调用超时/异常,或者资源不足(线程、信号量)会进入指定的fallback降级方法。

  • 请求结果缓存,hystrix实现了一个内部缓存机制,可以将请求结果进行缓存,那么对于相同的请求则会直接走缓存而不用请求后端服务。

  • 请求合并, 可以实现将一段时间内的请求合并,然后只对后端服务发送一次请求。

Hystrix如何实现:

  1. 使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;
  2. 每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)
  3. 记录请求成功,失败,超时和线程拒绝。
  4. 服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
  5. 请求失败,被拒绝,超时或熔断时执行降级逻辑。
  6. 近实时地监控指标和配置的修改。

三、Hystrix案例

准备工作:

在这里插入图片描述

构建:
在这里插入图片描述

(1)创建提供者payment模块:cloud-provider-hystrix-payment8001

(2)pom:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--eureka 服务-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--hystrix 服务-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>2.2.2.RELEASE</version>
        </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>
    </dependencies>

在这里插入图片描述

(3)提供者的application.yml:

在这里插入图片描述
(4)主启动类:com.fan.springcloud.PaymentHystrixMain8001

package com.fan.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

在这里插入图片描述
(5)业务类:
service类: service.PaymentService

package com.fan.springcloud.service;

import jdk.internal.org.objectweb.asm.commons.TryCatchBlockSorter;
import sun.nio.ch.DefaultSelectorProvider;

import java.util.concurrent.TimeUnit;
@Service
public class PaymentService {

    public String paymentInfo_ok(Integer id) //正常的一个方法
    {
        return "线程池:"+Thread.currentThread().getName()+"paymentinfo_ok,id: "+id+
                "\t"+"哈哈ok";
    }

    public String paymentinfo_timeout(Integer id ){//耗时的一个方法
        try {
            TimeUnit.SECONDS.sleep(3);
        }catch(InterruptedException e){e.printStackTrace();}
        return "线程池:" +Thread.currentThread().getName()+
                "paymentinfo_timeout,id"+id+"\t"+"哈哈,耗时3秒";
    }
}

在这里插入图片描述
提供者的contrller:controller.PaymentController

package com.fan.springcloud.controller;

import com.fan.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
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;

@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;//服务类的方法 被注入

    @Value("${server.port}")//获取application.yml中的端口号
    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)测试:

启动Eureka注册中心的微服务和提供者的微服务:
在这里插入图片描述

浏览器测试:eureka7001.com:7001
在这里插入图片描述

测试不耗时的方法:localhost:8001/payment/hystrix/ok/31

在这里插入图片描述
测试耗时方法:localhost:8001/payment/hystrix/timeout/31

在这里插入图片描述

高并发测试:

以上是在非高并发情况下的测试:为了了解使用hystrix,我们在搞并发的情况下测试:
这里我们使用jmeter工具,jmeter工具的安装和使用请百度。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

请求地址:http://localhost:8001/payment/hystrix/timeout/31
在这里插入图片描述

然后浏览器先测试:http://localhost:8001/payment/hystrix/timeout/31
在这里插入图片描述
然后立马启动另一个不耗时的方法测试:http://localhost:8001/payment/hystrix/ok/31

此时发现,在非高并发情况下,后测试的非耗时的方法并不会卡一下,及等待一下,但是在高并发情况下,我们后测试的不耗时的方法这时候会明显的等待一下(转圈)。

这是因为耗时的操作先运行,占满了tomcat的线程总数,导致后调用的原先瞬时非耗时方法也开始卡顿。

在这里插入图片描述

高并发测试消费者和提供者的微服务:

在这里插入图片描述
(1)新建消费者模块:cloud-consumer-feign-hystrix-order80

(2)消费者pom:

<dependencies>
        <!--注册中心放到第一个,eureka 服务-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--客户端使用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>
        <!--web下的两个配套-->
        <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>
            <version>2.2.2.RELEASE</version>
        </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>
    </dependencies>

(3)消费者的application.yml:

server:
  port: 80

spring:
  application:
    name: cloud-consumer-hystrix

eureka:
  client:
    register-with-eureka: true #false表示不向注册中心注册自己。
    fetch-registry: true #是否抓取注册信息。
    service-url:
      defaultZone: http://eureka7003.com:7003/eureka  #单机版只写自己本身

(4)主启动类:com.fan.springcloud.OrderHystrixMain80

package com.fan.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

在这里插入图片描述

(5)业务类:
5.1 service配合feign的接口:远程调用主要体现在这里:消费者的service接口对接提供者的controller映射方法。

消费者的service.PaymentHystrixService 接口:

package com.fan.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;

import java.util.concurrent.TimeUnit;

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT") //ureka上的那个name service,即application
public interface PaymentHystrixService {
	//payment远程能提供的有哪些服务,我们直接去提供者controller那里复制粘贴即可
    @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 );
}

在这里插入图片描述
5.2 消费者的controller: controller.OrderHystrixController

此controller是我们的order端调用payment端,使用的是feign 接口:

package com.fan.springcloud.controller;
import com.fan.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;

@RestController
@Slf4j
public class OrderHystrixController {
    //注入调用的接口
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")//远程的有参调用,consumer前缀代表来自消费侧
    public String paymentInfo_ok(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_ok(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")//远程的有参调用,consumer前缀代表来自消费侧
    public String paymentInfo_timeout(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_timeout(id);
        return result;
    }
}

梳理调用线路:消费者controller --调用–> 消费者service --调用–> 提供者controller

启动测试:启动三个服务,依次启动ureka,服务的提供者,服务的消费者

在这里插入图片描述

自测8001:http://localhost:8001/payment/hystrix/ok/31
在这里插入图片描述

自测8001:http://localhost:8001/payment/hystrix/timeout/31
在这里插入图片描述

测试消费者feign接口端:
http://localhost/consumer/payment/hystrix/ok/31

在这里插入图片描述
高并发测试:消费端出现等待
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

服务降级使用:

提供者和消费者的微服务卡死的情况和解决方案:
在这里插入图片描述

提供者8001服务降级处理:

在这里插入图片描述

此注解@HystrixCommand相当于一个异常处理的注解:
在这里插入图片描述

(1)从提供者8001先进行服务降级的处理:PaymentService进行修改

自定义一个应急方案的方法:paymentInfo_TimeOutHandler,相当于一个异常处理方法。

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

package com.fan.springcloud.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class PaymentService {

    public String paymentInfo_ok(Integer id)
    {
        return "线程池:"+Thread.currentThread().getName()+"paymentinfo_ok,id: "+id+
                "\t"+"哈哈ok";
    }

	//降级处理的注解
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public String paymentinfo_timeout(Integer id ){
        try {
            TimeUnit.SECONDS.sleep(4);
        }catch(InterruptedException e){e.printStackTrace();}
        return "线程池:" +Thread.currentThread().getName()+
                "paymentinfo_timeout,id"+id+"\t"+"哈哈,耗时4秒";
    }

    //出错的应急方法,增加异常处理方法:paymentInfo_TimeOutHandler
    public String paymentInfo_TimeOutHandler( Integer id){
        log.info("8001降级处理,超时");
        return "调用支付接口超时或异常:\t "+Thread.currentThread().getName()+"paymentInfo_TimeOutHandler,id: "+id+
                "\t"+"对不起,出错了!!!";
    }
}

(2)主启动类添加新注解@EnableCircuitBreaker:
在这里插入图片描述
在这里插入图片描述

启动注册中心和提供者8001,并测试:

http://localhost:8001/payment/hystrix/ok/31
http://localhost:8001/payment/hystrix/timeout/31

当我们把时间改成4秒的时候,测试:http://localhost:8001/payment/hystrix/timeout/31
就可以测试应急方法是否被调用了: TimeUnit.SECONDS.sleep(4);
在这里插入图片描述
当我们把时间改成2秒的时候,测试:http://localhost:8001/payment/hystrix/timeout/31
就没有达到预定的峰值3秒,就走正常的方法。在这里插入图片描述
同样,我们也可以进行程序出错的降级演示:

在这里插入图片描述

消费者80进行服务降级处理:

在这里插入图片描述

pom不需要改动
这里修改消费者80的yml:

server:
  port: 80

spring:
  application:
    name: cloud-consumer-hystrix

eureka:
  client:
    register-with-eureka: true #false表示不向注册中心注册自己。
    fetch-registry: true #是否抓取注册信息。
    service-url:
      defaultZone: http://eureka7003.com:7003/eureka  #单机版只写自己本身
feign:
  hystrix:
    enabled: true

在这里插入图片描述
主启动类增加注解:@EnableHystrix
在这里插入图片描述
修改消费者80的controller中的超时方法:

package com.fan.springcloud.controller;
import com.fan.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

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;

@RestController
@Slf4j
public class OrderHystrixController {
    //注入调用的接口
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")//远程的有参调用,consumer前缀代表来自消费侧
    public String paymentInfo_ok(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_ok(id);
        return result;
    }

    //可能会出错的方法,并指定出错后的应急处理方法
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")//远程的有参调用,consumer前缀代表来自消费侧
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
    })
    public String paymentInfo_timeout(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_timeout(id);
        return result;
    }
    //增加应急处理方法:paymentTimeOutFallbackMethod
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){
        log.info("我是消费者80的服务降级处理方法");
        return "我是消费者80的服务降级处理方法,对方支付系统繁忙,请10秒后再试";
    }
}

在这里插入图片描述

测试消费者:http://localhost/consumer/payment/hystrix/timeout/31
在这里插入图片描述
到此我们就完美解决了服务降级



服务降级处理的优化:

一种做法是:通常使用是在controller方法上启用注解 @HystrixCommand 但是每个方法都写 fallbackMethod 总有些麻烦 所以可以定义一个抽象类 BaseController 使用的时候 controller 继承 BaseController 即可实现统一 fallbackMethod,类似于异常处理类

在这里插入图片描述

初步 的解决方案
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

最终 的解决方案

上述方式还不够极简,比如fallback函数与函数耦合在一起,可以进一步解耦。通过实现@FeignClient的接口,指明fallback类。其中每个函数对应的就是fallback函数。

(1)此实现类PaymentFallbackService 相当于异常处理类,实现了PaymentHystrixService: 还要把此类放入到springboot容器中

@Service
public class PaymentFallbackService implements PaymentHystrixService{
    @Override
    public String paymentInfoOk(Integer id) {
        return "fall back, ok...";
    }

    @Override
    public String paymentInfoTimeout(Integer id) {
        return "fall back, timeout...";
    }
}

在这里插入图片描述

(2)在@FeignClient的接口上,指明fallback类。这样便可实现,fallback函数与函数的进一步解耦。

package com.fan.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;

import java.util.concurrent.TimeUnit;
//FeignClient接口,提供访问调用的接口
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class) //ureka上的那个name service,即application
public interface PaymentHystrixService {
    //payment远程能提供的有哪些服务,我们直接去提供者controller那里复制粘贴即可

    @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);
}

测试:
正常访问测试: http://localhost/consumer/payment/hystrix/ok/31

故意关闭微服务8001后测试:
http://localhost/consumer/payment/hystrix/ok/31
http://localhost/consumer/payment/hystrix/timeout/31

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结:
在这里插入图片描述

服务熔断:

服务熔断概述:

类比保险丝,分为三个步骤:服务降级->进而熔断->恢复调用链路。

熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。

SpringCloud中,熔断机制是通过Hystrix实现。Hystrix会监控微服务间的调用情况,当失败的调用到一定阈值,默认是5s内20次调用失败,就会启动熔断机制。熔断机制的注解是通过@HystrixCommand实现的。

熔断类型:

  • 熔断打开:请求不在进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态。
  • 熔断关闭:正常情况。
  • 熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断。

涉及断路器的三个重要参数:快照时间窗,请求总数阈值,错误百分比阈值。

快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,统计的时间范围就是快照时间窗,默认是10s。
请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断。默认是20,意味着10s内,如果Hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因,断路器都不会打开。
错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果再30次调用中,有16次发送了超时异常,则超过了50%的错误百分比,在默认设定50%阈值的情况下,这时候会将断路器打开。

原来的主逻辑要如何恢复?

当开启的时候,所有请求都不会进行转发;一段时间之后(默认是5s),这个时候断路器是半开状态,会让其中一个请求进行转发,如果成功,断路器会关闭,若失败,继续开启。重复上述步骤。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

参考资料:
在这里插入图片描述
在这里插入图片描述
half open是半开状态

在这里插入图片描述

服务熔断案例:

断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值。

  1. 快照时间窗:断路器确定是否打开需要统计一 些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
  2. 请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20, 意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
  3. 错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。

增加提供者8001的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 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();

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


扩展知识:hutool工具包

了解工具hutool.all工具包:官网地址:hutool.cn

文档地址:https://hutool.cn/docs/#/

UUID全称通用唯一识别码(universally unique identifier),JDK通过java.util.UUID提供了 Leach-Salz 变体的封装。在Hutool中,生成一个UUID字符串方法如下:

//生成的UUID是带-的字符串,类似于:a5c8a5e8-df2b-4706-bea4-08d0939410e3
String uuid = IdUtil.randomUUID();

//生成的是不带-的字符串,类似于:b17f24ff026d40949c85a24f4f375d42
String simpleUUID = IdUtil.simpleUUID();


在这里插入图片描述

增加8001的PaymentController的方法:

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

测试: localhost:8001/payment/circuit/2
测试: localhost:8001/payment/circuit/-2

在这里插入图片描述

小总结:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Hystrix工作流程

在这里插入图片描述
官网图例:
在这里插入图片描述

服务监控HystrixDashbord

在这里插入图片描述
在这里插入图片描述

创建模块:
在这里插入图片描述

pom:
在这里插入图片描述
yml:

在这里插入图片描述
在这里插入图片描述

启动测试:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
填写监控地址:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值