解决RestTemplate 中高并发情况下Socket InteAddress 用尽

在高并发请求下面,使用RestTemplate 作为请求链接会抛出 java.net.BindException Address alreadly in use coonetc ,主要原因是短时间内Socket 创建链接过多,动态绑定端口被使用尽,高频并且短的请求,在Socket.close()操作之后,协议并不会立即释放绑定的端口,将端口设置为TIME_WAIT状态,过240秒之后才会释放,这个通过netstat -na 查看到往目标机器发送时候查看到大量处于TIME_WAIT状态的端口,最后导致系统的资源耗尽 ,及时WINDOW SERVER 上 启动端口49152(16384)。

解决方法: 使用RestTemplate 换一种请求方式,使用链接池方式进行配置:

      1.Restemplate 提供两种工厂模式实现请求接口

               1). SimpleClientHttpRequestFactory, 底层使用J2SE (java.net包提供方式) 创建HTTP请求,大多数访问量不高时候

                2). HttpComponentsClientHttpRequestFactory 底层使用HttpClient访问远程HTTP服务请求,使用HTTPClient可以配置链接池。 具体配置如下,配置成功后对于高频且短的大量Request请求,控制 Request的请求量,不会跑出IntAddress use out的异常。

package com.huawei.similar.dts.vocab.config;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.TimeUnit;

/**
 *   HttpComponentClientHttpRequestFactory  设置时间
 *
 * */
public class RestTemplateConfig {
    private static RestTemplate restTemplate;

    static {
        // 长链接保持时间长度20秒
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
                new PoolingHttpClientConnectionManager(20, TimeUnit.SECONDS);
        // 设置最大链接数
        poolingHttpClientConnectionManager.setMaxTotal(2*getMaxCpuCore() + 3 );
        // 单路由的并发数
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(2*getMaxCpuCore());

        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);

        // 重试次数3次,并开启
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3,true));
        HttpClient httpClient = httpClientBuilder.build();
        // 保持长链接配置,keep-alive
        httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());

        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

        // 链接超时配置 5秒
        httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
        // 连接读取超时配置
//        httpComponentsClientHttpRequestFactory.setReadTimeout(10000);
        // 连接池不够用时候等待时间长度设置,分词那边 500毫秒 ,我们这边设置成1秒
        httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(3000);

        // 缓冲请求数据,POST大量数据,可以设定为true 我们这边机器比较内存较大
        httpComponentsClientHttpRequestFactory.setBufferRequestBody(true);

        restTemplate = new RestTemplate();
        restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
    }

    public static RestTemplate getRestTemplate(){
        return restTemplate;
    }

    private static int getMaxCpuCore(){
        int cpuCore = Runtime.getRuntime().availableProcessors();
        return  cpuCore;
    }
}

 

你可能感兴趣的:(问题系列总结)