hystrix配置中Apollo与Archaius对比分析

目录
  • 前言
  • ARCHAIUS警告日志
  • 我们遇到的问题
  • HYSTRIX在FEIGN中的加载过程
  • SPRINGBOOT自动加载HYSTRIX
  • HYSTRIX的动态兜底配置
  • APOLLO配置驱动HYSTRIX
  • 结语

前言

feign是一个出色的Http请求客户端封装框架,feign-hystrix是整个框架体系里的其中一个模块,用来集成hystrix熔断器的,feign和hystrix这两个项目都是Netflix开源的(openfeign已独立迭代)。在spring boot项目中,可以使用spring-cloud-starter-openfeign模块,无缝集成feign和hystrix。但是,hystrix默认采用的Archaius来驱动hystrix的配置系统,无缝集成的同时,也会把archaius-core给引入进来。archaius是一个配置中心项目,类似spring cloud config和apollo,如果archaius只是作为hystrix配置的驱动,项目启动时会打印烦人的警告日志,提示你没有配置任何动态配置源。当项目里已经采用了apollo时,可以直接剔除掉Archaius,他们的功能定位高度重合了。直接剔除依赖,会导致原本配置在spring中的配置不生效,博主也是在不小心剔除后,遇到了配置不生效的问题,才有了本篇博文,记录下过程。只要稍加改动,结合apollo配置动态下发能力,可以做到hystrix的配置实时动态生效。

ARCHAIUS警告日志

2020-12-10 11:19:41.766 WARN 12835 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2020-12-10 11:19:41.766 INFO 12835 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2020-12-10 11:19:41.772 WARN 12835 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2020-12-10 11:19:41.772 INFO 12835 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.

我们遇到的问题

在一次系统优化重构中,博主给整个项目来了一个360的大瘦身,把所有的未使用的依赖统统给挪走了。其中就包括了spring-cloud-starter-openfeign模块的archaius-core依赖。因为我们已经使用了apollo配置中心,archaius在这个项目里显得很多余,而且还会打印烦人的警告日志。所以就直接排除了,如:

implementation ('org.springframework.cloud:spring-cloud-starter-openfeign'){
    exclude(module:"archaius-core")
}

为此,专门了解了下archaius的来历,并且针对feign的熔断器的Fallback能力进行了测试,一切运行正常。上线一周后,问题暴露出来了,同事反馈,hystrix的配置好像不生效了。现象是,原本设置的hystrix线程执行不超时,却发生了很多执行一秒就超时了,我们的关键配置如下(这不是一个很好的配置示范,后面会调整更细粒度控制):

#禁止执行超时
hystrix.command.default.execution.timeout.enabled = false

直观感觉就是这个配置不生效了,联想到archaius-core被移除,所以先立马恢复了依赖,重新打包上线,问题解决。就这?为了彻底搞清楚Hystrix的配置加载过程,我们对feign整合hystrix进行了全面的了解。

HYSTRIX在FEIGN中的加载过程

在spring-cloud-starter-openfeign的封装下,使用起来非常简单,但是内部的加载流程非常复杂。所以博主也不打算全面铺开来说这块内容,有机会会独立一篇来说。这里根据我们上文遇到的禁用执行超时不生效的问题,博主总结了加载流程中的几个关键的地方:

Feign和Hystrix的桥接器Feign-Hystrix

这个项目是feign和hystrix的桥接器,通过这样的一个桥接器,将两个框架的api能力整合在了一起,下面简要阐述下,加载过程关键类的作用:

SetterFactory:承载了构造HystrixCommand实例的所有的配置的接口,有一个默认实现Default,在下面会用到,是自定义配置实现的突破口

HystrixInvocationHandler:这是一个实现了JDK代理接口类,用来代理Feign最终的执行,HystrixCommand类就是在这个实例里被构造执行的,使用的构造方法正是带入参Setter的构造方法,集成方会实现SetterFactory来构造Setter。调试程序时我们将端点打进这个类里,就可以看到配置加载的情况

SPRING BOOT自动加载HYSTRIX

@Configuration
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
   @Bean
   @Scope("prototype")
   @ConditionalOnMissingBean
   @ConditionalOnProperty(name = "feign.hystrix.enabled")
   public Feign.Builder feignHystrixBuilder() {
      return HystrixFeign.builder();
   }
}

这里是Hystrix在feign框架下加载的总入口。这个默认的构建器Builder中,有一个默认实现的SetterFactory,这个SetterFactory专门负责传递参数给Hystrix初始化HystrixCommand用。可以看到这里Bean的实例化加上了@ConditionalOnMissingBean条件约束,既我们可以自定义实现Hystrix的构造器,覆盖这里的实现,在自定义的构造器中,可以通过自定义实现SetterFactory,来注入任意的配置。这个是实现Hystrix配置自定义加载的方式之一,不过不推荐,没必要破坏spirng现有的这种结构,而且代码也会比较冗长(下面{...}省略了一百多行配置处理代码,用来兼容Hystrix现有配置定义),看起来如下:

HYSTRIX的动态兜底配置

配置是hystrix的核心,各种策略的选择执行都需要配置来驱动,所以,虽然在应用层面不需要太多的配置设置,但是必要的配置hystrix都会填充一个默认值,比如,hystrix默认执行超时设置的1s。Hystrix中的配置有三个层次的加载优先级,如:

  • 最先加载Setter:Setter是用户传递给Hystrix构造器的,所以优先级别最高
  • 其次加载动态配置源:如果必要的配置在Setter里没有找到,则在动态配置源中获取
  • 最后加载默认配置:如果动态配置源中也没有找到配置,则采用默认的配置

其中动态配置源,有一个基于SystemProperties的配置实现HystrixDynamicPropertiesSystemProperties。HystrixCommand在实例化时,如果用户没有给到具体的配置,Hystrix每次都会去SystemProperties中寻找配置。也就是说,我们可以通过-D参数注入任意Hystrix的配置参数,都会生效。有了这个特性,可以非常简单的结合apollo,达到hystrix配置动态生效的效果,而且所有配置兼容Hystrix原本的配置。

APOLLO配置驱动HYSTRIX

实现这个功能的关键是。系统初始化时,将hystrix.command前缀相关的配置从apollo中获取到然后统统注入SystemProperties。配置更新时,同时更新SystemProperties中的配置即可,非常简单,用代码说话:

/**
 * @author kl (http://kailing.pub)
 * @since 2020/12/10
 */
@Slf4j
@Configuration
@AutoConfigureBefore(value = {FeignClientsConfiguration.class, FeignAutoConfiguration.class})
public class HystrixConfiguration{
    public static final String DYNAMIC_TAG = "dynamic.";
    public static final String DYNAMIC_PREFIX = DYNAMIC_TAG + "hystrix.command.";
    public static final String PREFIX = "hystrix.command.";
    @ApolloConfig
    private Config config;
    @PostConstruct
    public void initHystrix(){
        this.config.addChangeListener(
                event -> this.loadHystrixConfig(event.changedKeys()),
                null,
                Sets.newHashSet(DYNAMIC_PREFIX)
        );
        this.loadHystrixConfig(config.getPropertyNames());
    }
    private void loadHystrixConfig(Setconfigkyes) {
        configkyes.forEach(key -> {
            if (StringUtils.containsIgnoreCase(key, PREFIX)) {
                String value = config.getProperty(key, null);
                String realKey = key.replaceAll(DYNAMIC_TAG,"").trim();
                System.setProperty(realKey, value);
                log.info("Hystrix config: {}={}", key, value);
            }
        });
    }
}

这里注意一个问题:为啥这里多设计了一个dynamic.前缀的配置,这是因为博主在测试过程中触发了apollo配置监听器隐藏的问题,导致Apollo的动态监听器不生效了。Apollo配置加载是以SystemProperties为最高优先级的,当配置发生变化时,apollo会将SystemProperties覆盖到配置之后,才比较本次配置发布是否有更新。因为我们一开始就将相关的配置加载到SystemProperties里了,所以每次变更都会被覆盖成之前的值,导致更新判断失效,一直进不了监听器。如果想要动态更新,就需要维护一份apollo的配置和SystemProperties里的映射关系,而不能保持一致,这样每次修改apollo时,就可以将维护映射关系的前缀去掉,然后将值动态更新到SystemProperties。目前的设计里,既支持原生的所有配置一次性加载,也支持dynamic.前缀拼装原有配置动态加载
配置示例

#初始化时一次性加载
hystrix.command.default.execution.timeout.enabled = true
#每次修改动态生效
dynamic.hystrix.command.default.execution.timeout.enabled = true

结语

Feign-hystrix的配置,有了Apollo,还用Archaius吗?当然不用,采用apollo实现方案,既兼容了所有原生配置,还可以做到动态生效,岂不美哉。

以上就是hystrix配置中Apollo与Archaius对比分析的详细内容,更多关于hystrix配置Apollo与Archaius对比的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring Cloud Hystrix 线程池队列配置(踩坑)

    背景: 有一次在生产环境,突然出现了很多笔还款单被挂起,后来排查原因,发现是内部系统调用时出现了Hystrix调用异常.在开发过程中,因为核心线程数设置的比较大,没有出现这种异常.放到了测试环境,偶尔有出现这种情况,后来在网上查找解决方案,网上的方案是调整maxQueueSize属性就好了,当时调整了一下,确实有所改善.可没想到在生产环境跑了一段时间后却又出现这种了情况,此时我第一想法就是去查看maxQueueSize属性,可是maxQueueSize属性是设置值了.当时就比较纳闷了,为什么ma

  • feign的ribbon超时配置和hystrix的超时配置说明

    先看下我的配置: ribbon: MaxAutoRetries: 1 #最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试 MaxAutoRetriesNextServer: 1 #切换实例的重试次数 OkToRetryOnAllOperations: false # 对所有的操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false ConnectTimeout: 1000 #请求连接的超时时间 ReadTimeo

  • apollo与springboot集成实现动态刷新配置的教程详解

    分布式apollo简介 Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性. 本文主要介绍如何使用apollo与springboot实现动态刷新配置,如果之前不了解apollo可以查看如下文档 https://github.com/ctripcorp/apollo 学习了解一下apollo,再来查看本文 正文 apollo与spring实现动态刷新配置本文主要演示2种刷新,一种

  • SpringCloud之Hystrix的详细使用

    目录 ***一.服务降级*** 2.不使用Hystrix的项目 3. 使用Hystrix 4. 全局的Hystrix配置 ***二.服务熔断*** 1.熔断机制概述 2.项目中使用 1.概念 服务降级:服务器繁忙,请稍后再试,不让客户端等待,并立即返回一个友好的提示(一般发生在 程序异常,超时,服务熔断触发服务降级,线程池.信号量 打满也会导致服务降级)服务熔断 : 达到最大服务访问后,直接拒绝访问,然后调用服务降级的方法并返回友好提示(如保险丝一样)服务限流 : 秒杀等高并发操作,严禁一窝蜂的

  • springcloud 熔断器Hystrix的具体使用

    说起springcloud熔断让我想起了去年股市中的熔断,多次痛的领悟,随意实施的熔断对整个系统的影响是灾难性的,好了接下来我们还是说正事. 熔断器 雪崩效应 在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应.服务雪崩效应是一种因"服务提供者"的不可用导致"服务消费者"的不可用,并将不可用逐渐放大的过程. 如果下图所示:A作为服务提供者,B为A的服务消费者,C和D是B的服务消费者.A不可

  • hystrix配置中Apollo与Archaius对比分析

    目录 前言 ARCHAIUS警告日志 我们遇到的问题 HYSTRIX在FEIGN中的加载过程 SPRINGBOOT自动加载HYSTRIX HYSTRIX的动态兜底配置 APOLLO配置驱动HYSTRIX 结语 前言 feign是一个出色的Http请求客户端封装框架,feign-hystrix是整个框架体系里的其中一个模块,用来集成hystrix熔断器的,feign和hystrix这两个项目都是Netflix开源的(openfeign已独立迭代).在spring boot项目中,可以使用sprin

  • java协程框架quasar和kotlin中的协程对比分析

    目录 前言 快速体验 添加依赖 添加javaagent 线程VS协程 协程代码 多线程代码 协程完胜 后记 前言 早就听说Go语言开发的服务不用任何架构优化,就可以轻松实现百万级别的qps.这得益于Go语言级别的协程的处理效率.协程不同于线程,线程是操作系统级别的资源,创建线程,调度线程,销毁线程都是重量级别的操作.而且线程的资源有限,在java中大量的不加限制的创建线程非常容易将系统搞垮.接下来要分享的这个开源项目,正是解决了在java中只能使用多线程模型开发高并发应用的窘境,使得java也能

  • python中in在list和dict中查找效率的对比分析

    首先给一个简单的例子,测测list和dict查找的时间: import time query_lst = [-60000,-6000,-600,-60,-6,0,6,60,600,6000,60000] lst = [] dic = {} for i in range(100000000): lst.append(i) dic[i] = 1 start = time.time() for v in query_lst: if v in lst: continue end1 = time.time

  • nodejs中Express与Koa2对比分析

    知会上看到有个问题 <Express会被Koa2取代吗?> .刚好对Express.koa有点小研究,于是简单回答了一下. 1.先说结论 目前没有看到Express会被koa2取代的迹象. 目前来说,Express的生态更成熟,入门门槛相对较低.从npm上的下载热度来说,两者的差距还较大,Express的月下载量约为koa2的40倍. 不过koa2的亮点足够吸引人,生态也开始变得完善. 2.从使用门槛来说 从使用上来说,Express对初学者更有好些,对着官网修修改改改就能做点东西出来. ko

  • php中随机函数mt_rand()与rand()性能对比分析

    本文实例对比分析了php中随机函数mt_rand()与rand()性能问题.分享给大家供大家参考.具体分析如下: 在php中mt_rand()和rand()函数都是可以随机生成一个纯数字的,他们都是需要我们设置好种子数据然后生成,那么mt_rand()和rand()那个性能会好一些呢,下面我们带着疑问来测试一下. 例子1. mt_rand() 范例,代码如下: 复制代码 代码如下: <?php echo mt_rand() . "n"; echo mt_rand() . &quo

  • Python判断值是否在list或set中的性能对比分析

    本文实例对比分析了Python判断值是否在list或set中的执行性能.分享给大家供大家参考,具体如下: 判断值是否在set集合中的速度明显要比list快的多, 因为查找set用到了hash,时间在O(1)级别. 假设listA有100w个元素,setA=set(listA)即setA为listA转换之后的集合. 以下做个简单的对比: for i in xrange(0, 5000000): if i in listA: pass for i in xrange(0, 5000000): if

  • Javascript中的几种继承方式对比分析

    开篇 从'严格'意义上说,javascript并不是一门真正的面向对象语言.这种说法原因一般都是觉得javascript作为一门弱类型语言与类似java或c#之类的强型语言的继承方式有很大的区别,因而默认它就是非主流的面向对象方式,甚至竟有很多书将其描述为'非完全面向对象'语言.其实个人觉得,什么方式并不重要,重要的是是否具有面向对象的思想,说javascript不是面向对象语言的,往往都可能没有深入研究过javascript的继承方式,故特撰此文以供交流. 为何需要利用javascript实现

  • 对Python3中的print函数以及与python2的对比分析

    本文首先介绍在python3中print函数的应用,然后对比在pyhton2中的应用.(本文作者所用版本为3.6.0) 首先我们通过help(print)命令来查看print函数的相关信息,(注意在python2中print不是函数,不能通过help获得相关信息). 第一行告诉我们print在python3中是一个内建函数. 然后是这个函数的调用格式,以及各参数的意义. 这个函数可以将values(可以是多个用逗号隔开的值)输出到一个数据流文件,默认的输出格式是标准输出(sys.stdout).

  • java中同类对象之间的compareTo()和compare()方法对比分析

    首先我们都知道java中的比较都是同一类对象与对象之间的比较,就好像现实生活中比较人和人的年龄一样,你不会去把人的年龄和人的身高来比较,这显然是没有意义的. java中同类对象之间的比较又分为两种,基本类型之间的比较和引用类型之间的比较. java中"=="比较对象是否引用了同一个对象,或者比较基本类型变量值是否相等.Object类的equals()方法用来比较是否一个对象(内存地址比较),可以重写. JDK中有些类重写了equals()方法,只要类型.内容都相同,就认为相等.很变态的

  • 详解Django中的FBV和CBV对比分析

    在学习Django过程中在views.py进行逻辑处理时接触到了两种视图的书写风格,FBV和CBV FBV 指 function based views,即基于函数的视图 CBV 指 class based views,即基于类的视图 基于类的视图相较于基于函数的视图可以更加便利的实现类的继承封装等.在日常使用的时候,二者的区别主要在于对于request的请求方法的处理方式 FBV 我们通过函数传入的request的method来判断客户端发起的是什么请求,并进行相应的操作,返回相应的数据. d

随机推荐