restTemplate踩过的坑-spring clound
现在公司项目基本都从臃肿的项目转换成微服务的方向转换,因此也从中使用了spring clound的一些组件,在此过程中就遇到了restTemplate的坑。
起初,是直接注入RestTemplate,后来则不断的遇到错误日志无法请求,出现异常。
异常信息:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No instances available for IP
意思是说url必须是服务的名称,猜测应该是涉及到eureka,直接用ip跟url调用是直接报错的。
因此不适用默认的,直接重新自定义,则引用了原有的注入修改一下。
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 | /** * * 功能描述: * * @作者 jimw 创建时间:2018-04 * */ @Configuration public class RestTemplateConfig { public RestTemplate restTemplate() { return new RestTemplate(getClientHttpRequestFactory()); } /** * 配置HttpClient超时时间 * * @return */ private ClientHttpRequestFactory getClientHttpRequestFactory() { RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(HTTP_SOCKET_TIMEOUT) .setConnectTimeout(HTTP_CONNECT_TIMEOUT).build(); CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build(); return new HttpComponentsClientHttpRequestFactory(client); } /** http请求socket连接超时时间,毫秒为单位 */ public static final int HTTP_SOCKET_TIMEOUT = 15000 ; /** http请求连接超时时间,毫秒为单位 */ public static final int HTTP_CONNECT_TIMEOUT = 15000 ; } |
当配置了这个之后,服务正常了。观察了一段时间,发现在并发的高峰期,开多几个服务器负载,也会存在服务出现请求非常慢,导致接口出现阻塞的情况出现,经过分析
1、出现阻塞的原因是因为高峰并发的时候,出现请求的链接数很大
因此找了源码,发现是因为restTemplate的默认配置值小于请求的链接数,而且路由并发也是默认为5的,因为微服务之间的逻辑处理中也有一定的时间。出现大规模阻塞的坑就这么踩到了。
对代码改造一下,配置最大链接数,路由并发数,这个restTemplate的坑就这么解决了。
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 79 80 81 82 83 84 85 86 | package com.jingbei.guess.config.web; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import org.apache.http.client.HttpClient; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContextBuilder; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate; import lombok.extern.slf4j.Slf4j; /** * * 功能描述: * * @作者 jimw 创建时间: 2018-04 * */ @Slf4j @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setRequestFactory(clientHttpRequestFactory()); restTemplate.setErrorHandler( new DefaultResponseErrorHandler()); return restTemplate; } @Bean public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() { try { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial( null , new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true ; } }).build(); httpClientBuilder.setSSLContext(sslContext); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register( "http" , PlainConnectionSocketFactory.getSocketFactory()) .register( "https" , sslConnectionSocketFactory).build(); // 注册http和https请求 // 开始设置连接池 PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager( socketFactoryRegistry); poolingHttpClientConnectionManager.setMaxTotal( 2700 ); // 最大连接数2700 poolingHttpClientConnectionManager.setDefaultMaxPerRoute( 100 ); // 同路由并发数100 httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); httpClientBuilder.setRetryHandler( new DefaultHttpRequestRetryHandler( 3 , true )); // 重试次数 HttpClient httpClient = httpClientBuilder.build(); HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory( httpClient); // httpClient连接配置 clientHttpRequestFactory.setConnectTimeout( 20000 ); // 连接超时 clientHttpRequestFactory.setReadTimeout( 30000 ); // 数据读取超时时间 clientHttpRequestFactory.setConnectionRequestTimeout( 20000 ); // 连接不够用的等待时间 return clientHttpRequestFactory; } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { log.error( "初始化HTTP连接池出错" , e); } return null ; } } |
在对应的插件中配置即可
依赖包:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.9</version>
</dependency>
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· 为DeepSeek添加本地知识库
· 精选4款基于.NET开源、功能强大的通讯调试工具
· DeepSeek智能编程
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~