热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

浅谈SpringCloudfeign的http请求组件优化方案

这篇文章主要介绍了浅谈SpringCloudfeign的http请求组件优化方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

1 描述

如果我们直接使用SpringCloud Feign进行服务间调用的时候,http组件使用的是JDK的HttpURLConnection,每次请求都会新建一个连接,没有使用线程池复用。具体的可以从源码进行分析

2 源码分析

我们在分析源码很难找到入口,不知道从何开始入手,我们在分析SpringCloud feign的时候可用在配置文件下面我讲一下个人的思路。

1 首先我点击@EnableFeignClients 看一下这个注解在哪个资源路径下

如下图所示:

2 找到服务启动加载的配置文件

3 因为feign底层的负载均衡是基于Ribbon的所以很快就找到了FeignRibbonClientAutoConfiguration.java 这个类

@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@Configuration
@AutoConfigureBefore(FeignAutoConfiguration.class)
@EnableConfigurationProperties({ FeignHttpClientProperties.class })
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
 OkHttpFeignLoadBalancedConfiguration.class,
 DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {

首先我们从这三个类进行分析,从名字上来看我为了验证没有特殊配置,feign底层走的是不是默认的DefaultFeignLoadBalancedConfiguration.class

OkHttpFeignLoadBalancedConfiguration.class

HttpClientFeignLoadBalancedConfiguration.class

DefaultFeignLoadBalancedConfiguration.class

DefaultFeignLoadBalancedConfiguration.class

@Configuration
class DefaultFeignLoadBalancedConfiguration {
	@Bean
	@ConditionalOnMissingBean
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
							 SpringClientFactory clientFactory) {
		return new LoadBalancerFeignClient(new Client.Default(null, null),
				cachingFactory, clientFactory);
	}
}

从上面代码可知每次请求过来都会创建一个新的client,具体的源码演示有兴趣的可以深入研究,在这里不是我们所研究的重点。

OkHttpFeignLoadBalancedConfiguration.class

@Configuration
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty(value = "feign.okhttp.enabled")
class OkHttpFeignLoadBalancedConfiguration {
	@Configuration
	@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
	protected static class OkHttpFeignConfiguration {
		private okhttp3.OkHttpClient okHttpClient;
		@Bean
		@ConditionalOnMissingBean(ConnectionPool.class)
		public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties,
													 OkHttpClientConnectionPoolFactory connectionPoolFactory) {
			Integer maxTotalCOnnections= httpClientProperties.getMaxConnections();
			Long timeToLive = httpClientProperties.getTimeToLive();
			TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
			return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
		}
		@Bean
		public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
										 ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
			Boolean followRedirects = httpClientProperties.isFollowRedirects();
			Integer cOnnectTimeout= httpClientProperties.getConnectionTimeout();
			this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).
					connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).
					followRedirects(followRedirects).
					connectionPool(connectionPool).build();
			return this.okHttpClient;
		}
		@PreDestroy
		public void destroy() {
			if(okHttpClient != null) {
				okHttpClient.dispatcher().executorService().shutdown();
				okHttpClient.connectionPool().evictAll();
			}
		}
	}
	@Bean
	@ConditionalOnMissingBean(Client.class)
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
							 SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
		OkHttpClient delegate = new OkHttpClient(okHttpClient);
		return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
	}
}

从源码可以看出

1 该类是个配置类,当引入OkHttpClient.Class会加载

client方法中可以看出会返回一个http连接池的client
HttpClientFeignLoadBalancedConfiguration
@Configuration
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
class HttpClientFeignLoadBalancedConfiguration {

这个类和OkHttpFeignLoadBalancedConfiguration原理类型

使用OKHttp替代默认的JDK的HttpURLConnection

使用appach httpclient使用教程类似

使用方法

1 pom

 
  io.github.openfeign
  feign-okhttp
 

2 Yml文件

feign:
 okhttp:
 enabled: true

3 自定义连接池

可以通过代码进行配置,也可以通过yml配置

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
 @Bean
 public okhttp3.OkHttpClient okHttpClient(){
 return new okhttp3.OkHttpClient.Builder()
  .readTimeout(60,TimeUnit.SECONDS)
  .connectTimeout(60,TimeUnit.SECONDS)
  .connectionPool(new ConnectionPool())
  .build();
 }
}

验证

默认的Feign处理会走到如下位置;

位置处于如下图所示

 @Override
 public Response execute(Request request, Options options) throws IOException {
 HttpURLConnection cOnnection= convertAndSend(request, options);
 return convertResponse(connection).toBuilder().request(request).build();
 }

走okhttp客户端会走如下代码

具体位置如下图所示:

@Override public Response execute() throws IOException {
 synchronized (this) {
 if (executed) throw new IllegalStateException("Already Executed");
 executed = true;
 }
 captureCallStackTrace();
 try {
 client.dispatcher().executed(this);
 Response result = getResponseWithInterceptorChain();
 if (result == null) throw new IOException("Canceled");
 return result;
 } finally {
 client.dispatcher().finished(this);
 }
 }

验证结果

如下所示:

彩蛋

okhttp客户端会走的代码可以看出来okhttp有synchronized锁线程安全的那默认的是否是线程安全的呢 有待去验证。

追加

如果发现配置的超时时间无效,可以添加以下配置,因为读取超时配置的时候没有读取上面的okhttp的配置参数,而是从Request中读取。

具体配置如下所示:

 @Bean
 public Request.Options options(){
 return new Request.Options(60000,60000);
 }

补充:springCloud feign使用/优化总结

基于springCloud Dalston.SR3版本

1.当接口参数是多个的时候 需要指定@RequestParam 中的value来明确一下。

/**
 * 用户互扫
 * @param uid 被扫人ID
 * @param userId 当前用户ID
 * @return
 */
@PostMapping(REQ_URL_PRE + "/qrCodeReturnUser")
UserQrCode qrCodeReturnUser(@RequestParam("uid") String uid,@RequestParam("userId") Integer userId);

2.接口参数为对象的时候 需要使用@RequestBody注解 并采用POST方式。

3.如果接口是简单的数组/列表参数 这里需要使用Get请求才行

@GetMapping(REQ_URL_PRE + "/getUserLevels")
Map getUserLevels(@RequestParam("userIds") List userIds);

4.直接可以在@FeignClient中配置降级处理方式 对于一些不重要的业务 自定义处理很有帮助

@FeignClient(value = "cloud-user", fallback = IUsers.UsersFallback.class)

5.feign默认只有HystrixBadRequestException异常不会走熔断,其它任何异常都会进入熔断,需要重新实现一下ErrorDecoder包装业务异常

示例:https://github.com/peachyy/feign-support

6. feign HTTP请求方式选择

feign默认使用的是基于JDK提供的URLConnection调用HTTP接口,不具备连接池。所以资源开销上有点影响,经测试JDK的URLConnection比Apache HttpClient快很多倍。但是Apache HttpClient和okhttp都支持配置连接池功能。具体选择需要权衡

7.默认不启用hystrix 需要手动指定feign.hystrix.enabled=true 开启熔断

8.启用压缩也是一种有效的优化方式

feign.compression.request.enabled=true
feign.compression.response.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json

9.参数相关调优

hystrix线程数设置

设置参数hystrix.threadpool.default.coreSize 来指定熔断隔离的线程数 这个数需要调优,经测试 线程数我们设置为和提供方的容器线程差不多,吞吐量高许多。

第一次访问服务出错的问题

启用Hystrix后,很多服务当第一次访问的时候都会失败 是因为初始化负载均衡一系列操作已经超出了超时时间了 默认的超时时间为1S,设置参数超时时间hystrix.command.default.execution.isolation.thread.timeoutInMillisecOnds=30000 可解决这个问题。

负载均衡参数设置

设置了Hystrix的超时参数会 还需设置一下ribbon的相关参数 这些参数和Hystrix的超时参数有一定的逻辑关系

请求处理的超时时间 ribbon.ReadTimeout=120000

请求连接的超时时间 ribbon.COnnectTimeout=30000

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。如有错误或未考虑完全的地方,望不吝赐教。


推荐阅读
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 探讨了小型企业在构建安全网络和软件时所面临的挑战和机遇。本文介绍了如何通过合理的方法和工具,确保小型企业能够有效提升其软件的安全性,从而保护客户数据并增强市场竞争力。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 在现代网络环境中,两台计算机之间的文件传输需求日益增长。传统的FTP和SSH方式虽然有效,但其配置复杂、步骤繁琐,难以满足快速且安全的传输需求。本文将介绍一种基于Go语言开发的新一代文件传输工具——Croc,它不仅简化了操作流程,还提供了强大的加密和跨平台支持。 ... [详细]
  • 网络运维工程师负责确保企业IT基础设施的稳定运行,保障业务连续性和数据安全。他们需要具备多种技能,包括搭建和维护网络环境、监控系统性能、处理突发事件等。本文将探讨网络运维工程师的职业前景及其平均薪酬水平。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文详细介绍了如何在ECharts中使用线性渐变色,通过echarts.graphic.LinearGradient方法实现。文章不仅提供了完整的代码示例,还解释了各个参数的具体含义及其应用场景。 ... [详细]
  • Composer Registry Manager:PHP的源切换管理工具
    本文介绍了一个用于Composer的源切换管理工具——Composer Registry Manager。该项目旨在简化Composer包源的管理和切换,避免与常见的CRM系统混淆,并提供了详细的安装和使用指南。 ... [详细]
  • 本文详细介绍了Git分布式版本控制系统中远程仓库的概念和操作方法。通过具体案例,帮助读者更好地理解和掌握如何高效管理代码库。 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 解决微信电脑版无法刷朋友圈问题:使用安卓远程投屏方案
    在工作期间想要浏览微信和朋友圈却不太方便?虽然微信电脑版目前不支持直接刷朋友圈,但通过远程投屏技术,可以轻松实现在电脑上操作安卓设备的功能。 ... [详细]
author-avatar
可惜偏偏孤独一个小姐_448
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有