• 【SpringCloud】三、 分布式系统的延迟和容错



    前言:现在看spring的官网已经没有了Hystrix,而只剩下一个子项目Spring Cloud Netflix,而Spring Cloud Netflix已经移除了Hystrix,这么多组件大家还没来得及熟悉,就已经说拜拜了
    目前很多公司项目中还有使用改组件,虽说以后新的技术可能不在考虑,但该会的还是要学。后面会介绍新的限流 Sentinel
    同时给大家推荐一个新的分布式容错组件: Resilience4j 是受Netflix Hystrix启发的轻量级容错库,但专为 Java 8 和函数式编程而设计。有兴趣的可以看看
    https://github.com/resilience4j/resilience4j

    在这里插入图片描述

    一、Hystrix

    Hystrix被称为熔断器,它是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多服务之间通过远程调用实现信息交互,调用时不可避免会出现调用失败,比如超时、异常等原因导致调用失败,Hystrix能够保证在一个服务出问题的情况下,不会导致整体服务失败,避免级联故障(服务雪崩),以提高分布式系统的弹性;
    熔断器也有叫断路器,他们表示同一个意思,最早来源于微服务之父 Martin
    Fowler 的论文 CircuitBreaker 一文。“熔断器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,能够及时切断故障电路,防止发生过载、发热甚至起火等严重后果。
    所以当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

    服务降级

    服务降级是指当某个微服务响应时间过长,发生异常,或者服务不可用了,我们不能把错误信息返回回来,或者让它一直卡在那里,所以要准备一个对应的策略(一个方法),当发生这种问题时,我们直接调用这个备用的方法来快速返回一个默认的结果,让请求得到快速响应,而不是一直卡在那里;

    降级的作用?
    1、可以监听你的请求有没有超时;(默认是1秒,时间可以改)
    2、异常或报错了可以快速让请求返回,不会一直等待;(避免线程累积)
    3、当的系统马上迎来大量的并发(双十一秒杀这种或者促销活动) 此时如果系统承载不了这么大的并发时,可以考虑先关闭一些不重要的微服务(在降级方法中返回一个比较友好的信息),把资源让给核心微服务,待高峰流量过去,再开启回来。

    请求限流

    请求限流就是,针对接口和服务进限制你某个微服务的使用量

    限流有很多方案:

    • 1、Nginx
    • 2、Redis + Lua
    • 3、Sentinel
    • 4、基于限流算法自己实现(令牌桶、漏桶算法)

    hystrix限流

    hystrix限流就是限制你某个微服务的使用量(可用线程数、信号量)
    hystrix通过线程池的方式来管理微服务的调用,它默认是一个线程池(大小10个) 管理你的所有微服务,你可以给某个微服务开辟新的线程池:

    @RequestMapping("/cloud/goodsHystrix2")
    @HystrixCommand(fallbackMethod = "fallback",
                    threadPoolKey = "goods",
                    threadPoolProperties = {@HystrixProperty(name = "coreSize", value = "2"),
                    @HystrixProperty(name = "maxQueueSize", value = "1")})
    public ResultObject goodsHystrix2() throws InterruptedException {}
    

    threadPoolKey 是线程池唯一标识, hystrix 会使用该标识来计数,看线程占用是否超过了, 超过了就会直接降级该次调用;
    这里coreSize给他值为2 那么假设你这个方法调用时间是1s执行完, 那么在1s内如果有超过2个请求进来的话,剩下的请求则全部降级;
    其中maxQueueSize是一个线程队列,里面只能放一个请求线程,本来线程数有2个,队列里面允许放一个,那么总共只能有3个请求线程执行,如果超过了就会限流;

    二、使用熔断器 Hystrix

    在 Spring Cloud 中使用熔断器 Hystrix 是非常简单和方便的,只需要简单两步即可:

    • 1、加依赖
    <!-- spring-cloud-starter-netflix-hystrix -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
    • 2、在入口类中使用@EnableCircuitBreaker 注解或 @EnableHystrix
      开启断路器功能,也可以使用一个名为@SpringCloudApplication 的注解代替主类上的三个注解;

    • 3、在调用远程服务的方法上添加注解:

    @HystrixCommand(fallbackMethod = "fallback")

    hystrix 默认超时时间是 1000 毫秒,如果你后端的响应超过此时间,就会触发
    断路器;
    修改 hystrix 的默认超时时间:

    @RequestMapping("/cloud/goodsHystrix")
    @HystrixCommand(fallbackMethod = "fallback",
                    commandProperties={
                            @HystrixProperty(name="execution.timeout.enabled", value="true"),
                        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="5000")
                    })
    public ResultObject goodsHystrix()
    

    或者在配置文件进行配置:

    ribbon.ReadTimeout=6000
    ribbon.ConnectTimeout=3000
    hystrix.command.default.execution.timeout.enabled=true
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
    
    这里有个坑需要注意一下:
    如果hystrix.command.default.execution.timeout.enabled为true,则会有两个执行方法超时的配置,一个就是ribbon的ReadTimeout,一个就是熔断器hystrix的timeoutInMilliseconds, 此时谁的值小谁生效;
    
    如果hystrix.command.default.execution.timeout.enabled为false,则熔断器不进行超时熔断,而是根据ribbon的ReadTimeout抛出的异常而熔断,也就是取决于ribbon的ConnectTimeout,配置的是请求服务的超时时间,除非服务找不到,或者网络原因,这个时间才会生效;
    ribbon.ReadTimeout=6000
    ribbon.ConnectTimeout=3000
    
    

    三、feign的服务降级

    feign 默认是支持hystrix的, 但是在Spring cloud Dalston 版本之后就默认关闭了, 因为业务需求不一定要使用;
    所以现在要使用首先得打开他,在yml文件加上如下配置:

    feign.hystrix.enabled=true
    
    • 加上配置之后降级方法怎么写呢?
    
    @FeignClient(value="SPRINGCLOUD-SERVICE-GOODS", fallback = GoodsRemoteClientFallBack.class)
    public interface GoodsRemoteClient {
    
        /**
         * 声明一个feign的接口,它的实现是服务提供者的controller实现
         *
         * @return
         */
        @RequestMapping("/service/goods")
        public ResultObject goods();
    }
    
    • 在feign客户端的注解上 有个属性叫fallback 然后指向一个类
    
    @Component
    public class GoodsRemoteClientFallBack implements GoodsRemoteClient {
    
        @Override
        public ResultObject goods() {
            return new ResultObject(Constant.ONE,"feign服务调用降级");
        }
    }
    

    如此方法降级便可以了;

    • 当然如果需要拿到具体的服务错误信息,那么可以这样:
      客户端指定一个fallbackFactory即可;
    @FeignClient(value="34-SPRINGCLOUD-SERVICE-GOODS", fallbackFactory = GoodsRemoteClientFallBackFactory.class)
    public interface GoodsRemoteClient {
    
        /**
         * 声明一个feign的接口,它的实现是服务提供者的controller实现
         *
         * @return
         */
        @RequestMapping("/service/goods")
        public ResultObject goods();
    }
    @Component
    public class GoodsRemoteClientFallBackFactory implements FallbackFactory<GoodsRemoteClient> {
    
        @Override
        public GoodsRemoteClient create(Throwable throwable) {
            return new GoodsRemoteClient() {
                @Override
                public ResultObject goods() {
                    String message = throwable.getMessage();
                    //这个message 就是错误信息,至此,就完成了feign与hystrix的整合;
                    System.out.println("feign远程调用异常:" + message);
                    return new ResultObject();
                }
            };
        }
    }
    

    hystrix相关配置:
    可以参考这个博客 https://blog.csdn.net/Leon_Jinhai_Sun/article/details/114147362

  • 相关阅读:
    Challenges and Opportunities for Students
    数字统计【NOIP2010普及组】
    【软件测试】正交法设计测试用例的使用
    Electron如何在UOS操作系统(统信)下打包成桌面应用?
    CSR/SSR以及同构渲染的区别
    触觉智能分享-SSD20X实现升级显示进度条
    [附源码]Python计算机毕业设计Django人事管理系统
    0-1背包问题
    分布式事务 —— SpringCloud Alibaba Seata
    58-DOS与DDOS分析(正常TCP会话与SYN Flood攻击、ICMP Flood 攻击、SNMP放大攻击等)
  • 原文地址:https://blog.csdn.net/weixin_43333483/article/details/127037387