工作总结——RestTemplate请求时间过长问题

出现场景

项目使用微服务,将每个数据源拆分成了一个服务,并通过Eureka注册,web服务通过配置的不同数据源的url调用各个数据源的服务从而获取相应数据。

但近日部署后在跑全量更新缓存的过程中,发现了一个严重问题。缓存更新不完整,通过日志信息定位到,每次在调用MongoDB数据源微服务时,会发生无响应,导致更新任务无法继续进行下去,耗费大量时间。

而调用各个服务的接口正是使用RestTemplate实现的,但经过查看,RestTemplate的Bean并未进行超时配置。这就很方了,RestTemplate本身在不配置超时的时候,是不存在超时机制的,只能通过tcp协议的响应超时来结束连接,那要等多久?等不了的,系统等不了,我更等不了。

解决方案

嗯,反正问题是很好解决的,如下:

        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(10*1000);
        httpRequestFactory.setConnectTimeout(10*1000);
        httpRequestFactory.setReadTimeout(10*1000);
        return new RestTemplate(httpRequestFactory);

完事儿,在加载RestTemplate的bean的过程中,注入超时,具体的超时时间,是根据normal情况下系统跑出来的耗时时长进行的设置。

分析

借此机会,准备好好分析下里面的配置项,从而达到,定义出一个合理的RestTemplate的Bean。

  • setConnectTimeout(int timeout)方法

设置基础的HttpClient连接超时。

	public void setConnectTimeout(int timeout) {
		Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
		this.requestConfig = requestConfigBuilder().setConnectTimeout(timeout).build();
		setLegacyConnectionTimeout(getHttpClient(), timeout);
	}
  • setBufferRequestBody(boolean bufferRequestBody)

该设置的默认值是ture,含义是使用内部缓存将请求的Body体进行缓冲处理。这里呢,如果通过POST或PUT发送大量数据时,建议将此属性更改为false,以免内存不足。

	public void setBufferRequestBody(boolean bufferRequestBody) {
		this.bufferRequestBody = bufferRequestBody;
	}
  • setConnectionRequestTimeout(int connectionRequestTimeout)

设置使用基础HttpClient从连接管理器请求连接时使用的超时(以毫秒为单位)。可以看到,这里的超时时间是允许为0的,那么问题来了,如果为零会发生什么事情:嗯没错,就是无限超时。

	public void setConnectionRequestTimeout(int connectionRequestTimeout) {
		this.requestConfig = requestConfigBuilder().setConnectionRequestTimeout(connectionRequestTimeout).build();
	}
  • setHttpClient(HttpClient httpClient)

哎哟,看到这个方法,我有一个大胆的想法。。。可以自实现一个自定义的HttpClient了。嗯嗯不错

	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}
  • setReadTimeout(int timeout)

该超时设置的是Socket读取超时时间。

	public void setReadTimeout(int timeout) {
		Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
		this.requestConfig = requestConfigBuilder().setSocketTimeout(timeout).build();
		setLegacySocketTimeout(getHttpClient(), timeout);
	}
  • setLegacyConnectionTimeout

将指定的连接超时应用于已弃用的HttpClient实现。

	private void setLegacyConnectionTimeout(HttpClient client, int timeout) {
		if (abstractHttpClientClass != null && abstractHttpClientClass.isInstance(client)) {
			client.getParams().setIntParameter(org.apache.http.params.CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
		}
	}
  • setLegacySocketTimeout

将指定的Socket超时应用于已弃用的HttpClient实现。

	private void setLegacySocketTimeout(HttpClient client, int timeout) {
		if (abstractHttpClientClass != null && abstractHttpClientClass.isInstance(client)) {
			client.getParams().setIntParameter(org.apache.http.params.CoreConnectionPNames.SO_TIMEOUT, timeout);
		}
	}

注意:这里的已弃用的HttpClient的实现主要是指HttpClient 4.3版本之前的实现。

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值