• SpringCloud基础知识【Hystrix熔断器】


    1. Hystrix概述

    Hystix,是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。

    • 雪崩:一个服务失败。导致整条链路的服务都失败的情形。

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

    那么如何预防雪崩的出现呢?

    • Hystix为我们提供了隔离降级熔断限流等方法防止雪崩的发生。

    2. Hystix-隔离

    资源隔离要解决的核心的问题:就是将多个依赖服务的调用分别隔离到各自的资源池内。

    • 避免对某一个依赖服务的调用,因为依赖服务的接口调用的延迟或者失败,导致服务所有的线程资源全部耗费在这个服务的接口调用上
    • 一旦某个服务的线程资源全部耗尽的话,可能就导致服务就会崩溃,甚至说这种故障会不断蔓延。如下图所示:
      在这里插入图片描述

    2.1 线程池隔离

    线程池隔离:适合绝大多数的场景,Hystix默认采用线程池隔离

    • 如下图所示,A 服务将Threadpool中拆分成Threadpool-BThreadpool-CThreadpool-D3个单独对B\C\D进行服务。
    • 各线程池相互独立。一个服务[C]挂掉并不会引起整条链路都失败的情况发生。

    在这里插入图片描述

    线程池隔离优缺点

      优点∶

    1. 使用线程池隔离可以完全隔离依赖的服务(例如图中的 B、C、D服务),请求线程可以快速放回
    2. 当线程池出现问题时,线程池隔离是独立的,不会影响其他服务和接口。
    3. 当失败的服务再次变得可用时,线程池将清理并可立即恢复,而不需要一个长时间的恢复。
    4. 独立的线程池提高了并发性。

     缺点∶

    1. 线程池隔离的主要缺点是它们增加计算开销(CPU)。每个命令的执行涉及到排队、调度和上下文切换都是在一个单独的线程上运行的。

    2.2 信号量隔离

    信号量隔离:适合与对内部的一些比较复杂的业务逻辑的访问,而不是对外部依赖的访问。

    • 一个线程池、但对不同的服务上加上一个阀门(访问的次数)。超过该数量,就拒绝后续的服务。

    在这里插入图片描述

    2.3 Hystix隔离小结

    是否有线程切换是否支持异步是否支持超时是否支持熔断是否支持限流开销
    线程池
    信号量×××

    什么情况下,用线程池隔离?

    1. 请求并发量大,并且耗时长(计算量大,或读数据库)
    2. 原因:可以保证大量的容器(tomcat)线程可用,不会由于服务原因,一直处于阻塞或等待状态,快速失败返回。

    什么情况下,用信号量隔离?

    1. 请求并发量大,并且耗时短(计算量小,或读缓存)
    2. 原因:这类服务的返回通常会非常的快,不会占用容器线程太长时间,而且也减少了线程切换的一些开销,提高了缓存服务的效率。

    3. Hystix-降级

    Hystix降级:当服务发生异常或调用超时,返回默认处理方案(默认数据)

    在这里插入图片描述

    3.1 服务提供方降级

    Hystrix初始代码Fiegn初始代码一样,这里就不再赘述。

    在这里插入图片描述在这里插入图片描述
    1. 在服务提供方(hystrix-provider),引入 hystrix依赖
    2. 定义降级方法
    3. 使用@HystrixCommand 注解配置降级方法
    4. 在启动类上开启Hystrix功能:@EnableCircuitBreaker

    在这里插入图片描述
    实例操作

    • 引入 hystrix依赖
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 在服务提供方启动类开启开启Hystrix功能
    package com.itheima.provider;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @EnableEurekaClient //该注解 在新版本中可以省略
    @SpringBootApplication
    
    @EnableCircuitBreaker //开启Hystrix功能
    public class ProviderApp {
    
        public static void main(String[] args) {
    
            SpringApplication.run(ProviderApp.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 因为后续会有消费方调用提供方中controller中提供的方法接口,那么如果该接口出异常,我们就需要为其提供一个降级方法。
    package com.itheima.provider.controller;
    
    import com.itheima.provider.domain.Goods;
    import com.itheima.provider.service.GoodsService;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import org.springframework.beans.factory.annotation.Autowired;
    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.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Date;
    
    /**
     * Goods Controller 服务提供方
     */
    
    @RestController
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Autowired
        private GoodsService goodsService;
    
        @Value("${server.port}")
        private int port;
    
        /**
         * 降级:
         *  1. 出现异常
         *  2. 服务调用超时
         *      * 默认1s超时
         *
         *  @HystrixCommand(fallbackMethod = "findOne_fallback")
         *      fallbackMethod:指定降级后调用的方法名称
         */
    
        @GetMapping("/findOne/{id}")
        @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
                //设置Hystrix的超时时间,默认1s
                @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    
        })
        public Goods findOne(@PathVariable("id") int id){
    
            //降级情况1.异常
            int i = 3/0;
            
            //降级情况2.服务调用超时
            try {
                //2. 休眠2秒
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Goods goods = goodsService.findOne(id);
    
            goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
            return goods;
        }
    
    
        /**
         * 定义降级方法:
         *  1. 方法的返回值需要和原方法一样
         *  2. 方法的参数需要和原方法一样
         */
        public Goods findOne_fallback(int id){//findOne的降级方法。
            Goods goods = new Goods();
            goods.setTitle("降级了~~~");
    
            return goods;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    在这里插入图片描述

    3.2 消费方降级

    1. feign 组件已经集成了hystrix组件。
    2. 定义feign调用接口实现类,复写方法,即降级方法
      在这里插入图片描述
    3. @FeignClient注解中使用fallback 属性设置降级处理类。
    4. 配置开启 feign.hystrix.enabled = true

    在这里插入图片描述
    实例操作

    • 服务消费方的application.yml中添加下面代码:开启feign对hystrix的支持
    # 开启feign对hystrix的支持
    feign:
      hystrix:
        enabled: true
    
    • 1
    • 2
    • 3
    • 4
    • 在GoodsFeignClient 接口上的@FeignClient注解中使用fallback 属性设置降级处理类。
    package com.itheima.consumer.feign;
    
    
    import com.itheima.consumer.domain.Goods;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    
    
    @FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
    public interface GoodsFeignClient {
    
    
        @GetMapping("/goods/findOne/{id}")
        public Goods findGoodsById(@PathVariable("id") int id);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 实现降级处理类
    package com.itheima.consumer.feign;
    
    import com.itheima.consumer.domain.Goods;
    import org.springframework.stereotype.Component;
    
    /**
     * Feign 客户端的降级处理类
     * 1. 定义类 实现 Feign 客户端接口
     * 2. 使用@Component注解将该类的Bean加入SpringIOC容器
     */
    @Component
    public class GoodsFeignClientFallback implements GoodsFeignClient {
        @Override
        public Goods findGoodsById(int id) {
            Goods goods = new Goods();
            goods.setTitle("又被降级了~~~");
            return goods;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    3.3 Hystix降级小结

    注意:

    • 当服务提供方和服务的消费方都配置了降级时,当失败后(出现异常、服务调用超时)只有服务提供方的降级会生效

    • 原因:当出现异常,服务提供方已经降过级,降过级后,返回的数据是正常的数据。那么这时服务消费方就不用再次被降级。

    4. Hystix-熔断

    Hystrix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,不管请求降级与否,直到服务恢复正常为止。

    • circuitBreaker.sleepWindowlnMilliseconds:监控时间
    • circuitBreaker.requestVolumeThreshold:失败次数
    • circuitBreaker.errorThresholdPercentage:失败率

    在这里插入图片描述

    4.1 代码演示

    在服务提供方(hystrix-provider)controlloer包下的GoodsControlloer中写(默认该机制已开启)

    package com.itheima.provider.controller;
    
    import com.itheima.provider.domain.Goods;
    import com.itheima.provider.service.GoodsService;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import org.springframework.beans.factory.annotation.Autowired;
    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.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Date;
    
    /**
     * Goods Controller 服务提供方
     */
    
    @RestController
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Autowired
        private GoodsService goodsService;
    
        @Value("${server.port}")
        private int port;
    
        @GetMapping("/findOne/{id}")
        @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
                //设置Hystrix的超时时间,默认1s
                @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
                //监控时间 默认5000 毫秒
                @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
                //失败次数。默认20次
                @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
                //失败率 默认50%
                @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
    
        })
        public Goods findOne(@PathVariable("id") int id){
    
            //如果id == 1 ,则出现异常,id != 1 则正常访问
            if(id == 1){
                //1.造个异常
                int i = 3/0;
            }
    
            Goods goods = goodsService.findOne(id);
    
            goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
            return goods;
        }
    
    
        /**
         * 定义降级方法:
         *  1. 方法的返回值需要和原方法一样
         *  2. 方法的参数需要和原方法一样
         */
        public Goods findOne_fallback(int id){
            Goods goods = new Goods();
            goods.setTitle("降级了~~~");
    
            return goods;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    4.1 熔断监控

    • Hystrix提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。
    • 但是 Hystrix-dashboard 只能监控一个微服务
    • Netflix还提供了 Turbine ,进行聚合监控

    在这里插入图片描述
    聚合监控

    5. Hystix-限流

    在高并发访问下,由于系统资源有限,必须对访问量进行控制。

    • Hystrix提供了限流功能,在springcloud架构的系统中,可以在网关启用Hystrix,进行限流处理,每个微服务也可以各自启用Hystrix进行限流。
    • Hystrix默认使用线程隔离模式,可以通过线程数+队列大小进行限流
    hystrix:
      threadpool:
        default:
          coreSize: 200 #并发执行的最大线程数,默认10
          maxQueueSize: 1000 #BlockingQueue的最大队列数,默认值-1
          queueSizeRejectionThreshold: 800 #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    【字符编码系列一】ASCII编码是什么?
    Linux基础命令 逻辑卷扩容
    MySQL 排序
    烽火服务器下修改远程管理IP的步骤(完整版)
    从源码深入理解读写锁(golang-RWMutex)
    EasyAVFilter代码示例之将视频点播文件转码成HLS(m3u8+ts)视频点播格式
    mongoose 搭建 http 服务 -- 编译
    什么是数据安全性?
    [Vue 配置] Vite + Vue3 项目配置和使用 NProgress
    dreamweaver作业静态HTML网页设计——家乡海南旅游网站
  • 原文地址:https://blog.csdn.net/qq_40926887/article/details/127822466