SpringCloud(H版&Alibaba)技术(七) —— Hystrix断路器

目录​​​

简介

Hystrix重要概念

        服务降级(fallback)

        服务熔断(break)

        服务限流(flowlimit)

Hystrix案例

        高并发测试​

                安装JMeter

                Jmeter压测测试

                Jmeter压测结论

                        新建80加入

        故障现象、导致原因

        降级容错解决的维度要求

        服务降级

8001fallback  提供者

80fallback 客户端 消费者

目前的问题和解决办法

Hystrix 全局服务降级Default Properties

Hystrix 通配服务降级Feignfallback

服务熔断

熔断概念​​实操

总结

熔断类型

官网熔断流程图

服务限流

Hystrix工作流程

服务监控HystrixDashboard

简介

仪表盘9001

断路器演示 (服务监控hystrixDashboard)

        监控测试




简介

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

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

Hystrix停更进维

Hystrix重要概念

服务降级(fallback)

-简单来说就是 假如对方系统不可用了,你需要给我一个兜底的解决方法,不要让我在那耗死

服务熔断(break)

服务限流(flowlimit)

Hystrix案例

Hystrix支付微服务构建
把7001改为单机版,方便后面进行案例测试。

1.新建cloud-provider-hystrix-payment8001

2.写pom

 <dependencies>
        <!--新增hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>com.aurora.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>

3.改yml

server:
  port: 8001

eureka:
  client:
    register-with-eureka: true    #表识不向注册中心注册自己
    fetch-registry: true   #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    service-url:
      #defaultZone: http://eureka7002.com:7002/eureka/    #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/
#  server:
#    enable-self-preservation: false
spring:
  application:
    name: cloud-provider-hystrix-payment
#    eviction-interval-timer-in-ms: 2000

4.主启动

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

5.service

@Service
public class PaymentService {

    //成功
    public String paymentInfo_OK(Integer id){
        return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_OK,id:  "+id+"\t"+"哈哈哈"  ;
    }

    //失败
    public String paymentInfo_TimeOut(Integer id){
        int timeNumber = 3;
        try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();}
        return "线程池:"+Thread.currentThread().getName()+"   paymentInfo_TimeOut,id:  "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber;
    }

}

6.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;
    }
}

7.测试
   启动eureka7001  再启动cloud-provider-hystrix-payment8001
   访问 success的方法 http://localhost:8001/payment/hystrix/ok/31

 每次调用耗费3秒钟  http://localhost:8001/payment/hystrix/timeout/31

上述module均OK   以上述为根基平台,从正确->错误->降级熔断->恢复

高并发测试

安装JMeter

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

下载tgz和zip都可以:

进入解压后的目录的bin目录,找到jmeter.properties文件,修改语言zh_CN。

双击jmeter.bat运行jmeter,修改语言成中文版。

Jmeter压测测试

进行高并发测试 添加测试计划 线程组


保存当前线程组
添加http请求

设置如下:

保存后启动

然后去访问http://localhost:8001/payment/hystrix/ok/31,访问速度变慢了。两个都在转圈圈

而后台一直在发送超时结果
导致原因:

由于这两个方法在同一个微服务里面 大规模的资源打到timeout  微服务不得不集中资源去处理这些高并发请求 (武汉疫情严重 全国各地都去支援 同理)
tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。

Jmeter压测结论

上面还是服务提供者8001自己测试,假如此时外部的消费者80也来访问,那消费者只能干等,最终导致消费端80不满意,服务端8001直接被拖死

新建80加入

1.新建cloud-consumer-feign-hystrix-order80

2.改pom
 

  <dependencies>
        <!--新增hystrix-->
        <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>com.aurora.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>

3.写yml 

server:
  port: 80

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

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

4.主启动

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

5.service

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")      //微服务名称 80要调8001
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);
}

6.controller 

@RestController
@Slf4j
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_OK(id);
        log.info("*******result:"+result);
        return result;
    }
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        log.info("*******result:"+result);
        return result;
    }

}

7.测试
   启动hystrix-order80  浏览器:http://localhost/consumer/payment/hystrix/ok/31

8.启动jmeter,然后再进行测试

故障现象、导致原因

现象:
        8001同一层次的其他接口服务被困死,因为tomcat线程里面的工作线程已经被挤占完毕
        80此时调用8001,客户端访问响应缓慢,转圈圈

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

降级容错解决的维度要求

服务降级

8001fallback  提供者

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

 2.然后在8001的主启动类上添加@EnableCircuitBreaker注解,启用断路器。

3.启动7001和8001,测试8001的fallback,http://localhost:8001/payment/hystrix/timeout/1成功进入fallback方法。(并且fallback方法是用Hystrix的线程池)

 4.去掉sleep,改为 1 / 0,测试方法运行异常 localhost:8001/payment/hystrix/timeout/1,也可以进入fallback方法。


 80fallback 客户端 消费者


1.改yml

feign:
  hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。

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

3.业务类
修改OrderHystrixController的paymentInfo_TimeOut方法,并添加paymentTimeOutFallbackMethod方法

    @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;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){
        return "消费者80,对方支付系统繁忙请10秒钟后再试或自己运行出错检查自己,/(ㄒoㄒ)/~";
    }


在80 controller 中添加int i = 1 / 0;,运行异常也会进入80的fallback方法

目前的问题和解决办法

解决办法:设置全局fallback方法。

Hystrix 全局服务降级Default Properties

@DefaultProperties(defaultFallback = "")

1.在80的OrderHystrixController中添加全局fallback方法:

    //全局fallback方法,不能有传参
    public String payment_Global_FallbackMethod(){
        return "Global异常处理信息,请稍后再试!";
    }

 2.在OrderHystrixController类上加上@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod") ,设置全局fallback方法。

 3.把paymentInfo_TimeOut方法的@HystrixCommand改成:

 4.测试
    重启80  localhost/consumer/payment/hystrix/timeout/1   显示Global异常

Hystrix 通配服务降级Feignfallback


模拟宕机场景 

1.在80的service包下新建PaymentFallbackService类,实现PaymentHystrixService接口

@Component
public class PaymentFallbackService implements PaymentHystrixService {
    @Override
    public String paymentInfo_OK(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_OK , (┬_┬)";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_TimeOut , (┬_┬)";
    }
}

2.要在yml中加上:(我们在之前就加上了)

feign:
  hystrix:
    enabled: true 

 3.给PaymentHystrixService接口的@FeignClient注解加上fallback = PaymentFallbackService.class属性,用于出错进行fallback处理。

4.测试 先启动8001 再启动80
   正常访问测试:http://localhost/consumer/payment/hystrix/ok/31

 故意关闭微服务8001  调用PaymentFallbackService中的paymentInfo_ok方法

服务熔断

断路器:就是保险丝  https://martinfowler.com/bliki/CircuitBreaker.html

熔断概念


实操

1.修改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 不能负数");
    }
    String serialNumber = IdUtil.simpleUUID(); //等价于UUID.randomUUID().toString()

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

IdUtil.simpleUUID() 来自hutool中的 唯一ID工具-IdUtil (hutool.cn)

为什么配置这些参数

 2.在8001的PaymentController中添加

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

3.测试 启动7001和8001
   正确:http://localhost:8001/payment/circuit/31

  错误:http://localhost:8001/payment/circuit/-31  (输入超过10次以上 错误率六成进入熔断)



再尝试多次等正确率上升才恢复

 总结


如果请求次数的错误率超过指定值,开启熔断,经过一段时间后,变为半开模式,然后放进一个请求进行处理,如果请求处理成功,关闭熔断;如果还是报错,继续进入熔断,再经过一段时间后,变为半开模式,再进行对下一个请求进行处理,一直在熔断,半开模式来回切换,直到请求成功,关闭熔断。

熔断类型

 官网熔断流程图


断路器在什么情况下开始起作用:https://github.com/Netflix/Hystrix/wiki/How-it-Works

断路器开启或关闭的条件:
断路器打开之后:
All配置

服务限流

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

Hystrix工作流程

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

官方图例:

服务监控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.aurora.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>

3.写yml

server:
  port: 9001

4.主启动 ( HystrixDashboardMain9001+新注解@EnableHystrixDashboard )

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

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

 <!-- actuator监控信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> 

 5.启动9001  浏览器输入:http://localhost:9001/hystrix

断路器演示 (服务监控hystrixDashboard)

注意:监控时所有微服务提供者都需要在pom中引入监控依赖

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

1.修改cloud-provider-hystrix-payment8001

 在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;
   }


监控测试

启动9001,7001,8001 
    1.9001监控8001  监控地址:http://localhost:8001/hystrix.stream

2.浏览器输入 http://localhost:8001/payment/circuit/31 和 http://localhost:8001/payment/circuit/-31
   上述测试通过 ok  刷新正确的正数多次后 点击监控

多次输入 http://localhost:8001/payment/circuit/-31 错误访问

稍微等一会,然后输入正确的访问 熔断就会关闭
使用流程:先访问正确地址,再访问错误地址,再正确地址,会发现图示断路器都是慢慢放开的

7色:每一种故障对应一种颜色

1圈 


1线




下一篇:SpringCloud(H版&Alibaba)技术(八) —— Gateway新一代网关 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值