zoukankan      html  css  js  c++  java
  • Hystrix配置实战及feign超时配置失效

    一、feign超时配置失效

    最近项目上遇见feign超时配置总是失效。导致feign调用超过2s之后就会超时,会进行自动重试,重复调用两次服务,并且还是指定接口。这就更加奇怪。最后通过观察以及源码调试,发现问题所在。在这里先说下原因。

     

    原因:同一个服务feign组件做了拆分,使用contextId对feign拆分后的feign做了声明。配置超时配置的时候,不能再使用feign组件注解 @FeignClient里的name去做配置了,而应该是contextId里的名称

    示例代码:

    //A服务的基础业务接口
    @FeignClient(contextId = "AServer", name = "AServer", configuration = FeignConfiguration.class)
    public interface ABaseServer {
    
    }
    
    //A服务的个性化业务接口
    @FeignClient(contextId = "ASpecialServiceServer", name = "AServer", configuration = FeignConfiguration.class)
    public interface ASpecialServer {
    
    }
    
    //上面是对feign拆分后的声明
    //错误的yml配置
    feign:
      client:
        config:
    #这里仍然使用了name作为超时配置,那么只有ABaseServer 里面声明的接口才会使用以下的配置,因为恰巧ABaseServer的contextId名称是AServer。
          AServer: 
            connectTimeout: 60000
            readTimeout: 60000
    
    //正确的yml配置,手段一:配置上以contextId为声明来配置
    feign:
      client:
        config:
    #基础业务接口的超时配置
          AServer: 
            connectTimeout: 60000
            readTimeout: 60000
    #个性化业务接口的超时配置
          ASpecialServiceServer: 
            connectTimeout: 50000
            readTimeout: 50000
    
    //正确的yml配置,手段二:A服务全部使用default全局配置,Bserver单独声明,并不会使用全局配置
    feign:
      client:
        config:
          default: 
            connectTimeout: 60000
            readTimeout: 60000
          BServer:
            connectTimeout: 30000
            readTimeout: 30000

    feign内部集成了ribbon做为了负载均衡的组件,ribbon也有相关超时配置,feign的超时配置不当也会造成超时失效,关于如何配置可以参考之前的一篇博客:https://www.cnblogs.com/wa1l-E/p/13994240.html

    这次feign的超时不生效,主要原因是,项目上做了一次feign的拆分,即A服务调用B服务的接口由于过多,接口从功能模块和业务上做了feign组件的拆分,也就是spring容器中会有两个feign针对同一个服务。

    问题1:拆分后,springboot在启动时,会报错,原因是针对同一个服务有多个feign 实例,而spring容器又默认是单例加载。

    解决这个问题有两个方案:

    1、

     

    2、在feign注解定义上加上contextId来避免启动报错。示例代码如下:

    @FeignClient(name = "A", contextId = "ABaseServiceServer", configuration = FeignConfiguration.class)
    public interface AServer {
    
    }
    
    
    @FeignClient(name = "A", contextId = "ACustomServiceServer", configuration = FeignConfiguration.class)
    public interface AServer {
    
    }

    都是同一个服务的feign组件,但是contextId不同,解决了问题。

    项目上采用了第二种解决手段,但也正是因为对解决问题没有做到追根刨底的精神,导致引入了feign超时失效的原因。

    问题2:使用ContextId对feign做声明后,导致部分接口超时失效。

    结论:在开篇时,结论已经说过,这里就不再赘述。主要说下原因以及定位问题的过程和解决方法。

    定位过程:发现该问题时,首先发现是部分接口失效,当然是测试并观察,发现只有未使用contextId配置的feign组件的接口会超时。但是当时并不知道是contextId的声明影响。所以果断开撕源码。定位问题

    首先Feign有一个内部类Builder,听名字就知道使用了建造者是设计模式,建造者适合创造属性多变的对象, 而Feign恰好具备这种特性,使用建造者设计模式在适合不过了。

    Builder类有一个属性Options option这个Options类就是feign的超时配置声明。如下图:

        再来看一下UML图

     

         可以看到真正的配置就是再容器初始话feign的时候,初始化 builder的时候使用的配置就是真正使用的配置。那么接下来就好办了,使用我之前讲过的源码调试大法,开始调试,启动服务,断点开启,最后一路追踪,发现实例化的代码如下:

         不知道启动后怎么调试找到相关代码的同学可以参考另一篇博客:https://www.cnblogs.com/wa1l-E/p/14115042.html    还是一句话,动手多实践。

        

        97行见名其义:初始化Feign.builder,109行是关键代码,看名字就知道,配置feign,那么builder的option一定是在这里初始化的,我们一路追进去看看

    到了上面的方法中,我们发现了尤其重要的两行代码,看名字就知道使用configure配置属性,那么在这里一定是使用配置去初始话Feign的超时相关配置,没有的话会使用默认的配置。
    这里的方法就不赘述了,有兴趣的同学可以去断点看看,最关键的另一个发现是 在获取配置的时候,使用的是
    contextId,这不由得和上面Feign注解 @FeignClient中声明的contextId关联起来,最后通过调试也发现,确实是这样。contextId源码注释是bean的显实声明名称,如果不配置默认使用beanName.到这里就发现问题了。
    那么解决手段就简单了

    解决手段:

    手段一:如果拆分后的接口不需要做特殊的超时配置区分,那么使用default全局配置既可,至于其他的feign客户端,在做配置,便不会使用全局的配置。

    手段二:如果拆分后的接口,超时配置是不一样的,那么使用contextId做超时配置才是正确的。

    最后建议实际使用手段二,粒度更细。

     

    二、Hystrix配置实战:

    首先介绍一下上面Feign超时后,Hystrix配置后,会自动重试的原因,然后再介绍一下Hystrix的主要配置,搭建一个Hstrix-dashboard,然后通过一个接口的测试,通过dashBoard观察Hystrix的配置的。

     1、Hystrix的配置

    熔断配置:

    #hystrix熔断器配置:(接口发生异常,服务调用方直接做熔断处理,返回提示,避免流量过大接口调用引起雪崩。)

    #如果接口发生异常,那么会熔断,熔断开启。后面的请求不会再去进行服务远程调用,直接走熔断 #下面配置策略是: 10s滚动窗口期内,大于等于1个线程 失败率超过百分之50,则打开熔断开关.负责关闭熔断开关 #熔断开关打开后,后续请求直接走熔断,不会进行远程调用 hystrix.command.
    default.circuitBreaker.requestVolumeThreshold=1 hystrix.command.default.metrics.rollingStats.timeInMilliseconds=10000 hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 #在5s后,熔断会进入 半开状态,会放入一部分请求进行远程调用,如果成功,则关闭熔断.如果失败,则继续打开熔断 hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000

    降级配置:

    #hystrix降级配置:(接口发生异常,服务调用方直接对接口进行降级处理,返回托底数据。和熔断的区别是一个有托底数据,一个没有。)
    #超时打开,设置为70s,这里的超时时间必须大于Ribbon和feign的超时,因为小于Feign正常调用超时时间,直接会熔断. hystrix.command.
    default.execution.timeout.enabled=true hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=70000

     2、配置Hystrix-dashboard调试Hystrix熔断和降级配置

    • 搭建Hystrix-dashboard: 没空的同学可以直接下载我之前搭建的: https://github.com/coffeebabeCGG/spring-cloud 这里就不赘述如何搭建了
    • 启动项目后,需要填如要监控的服务地址:http://ip:port/context-path/actuator/hystrix.stream

    • 从下图可以看到queryByPage接口的熔断目前是关闭状态。关于dashboard的详细参数说明,下面给大家补一张图。

       

    最后:接口postMan的runtest批量调用接口测试,通过dashBoard观察接口的熔断情况,配置是否生效。就可以了解Hystrix的基本使用了。

     

     

     

     

  • 相关阅读:
    路由控制
    NodeJS -Express 4.0 用include取代partial
    工程的结构文件
    Express 框架的安装
    iconfont阿里爸爸做的开源图库
    12.文件系统fs
    11.事件驱动events
    10.Node.js核心模块
    Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service
    Apache CXF实现Web Service(1)——不借助重量级Web容器和Spring实现一个纯的JAX-WS web service
  • 原文地址:https://www.cnblogs.com/wa1l-E/p/14814871.html
Copyright © 2011-2022 走看看