我的代码中的并行性可能会导致“超时等待池中的连接”

时间:2016-02-21 19:12:20

标签: java multithreading apache http stream

我有这个java http客户端代码:

 private void init(String[] args) {
        setServerVersion(args);
        commonParallelGenerator.setInputFlavor();
        commonParallelGenerator.setNumberOfThreads("25"); //machine has 31 cores.
    }


...



            Report report = requestsList
                    .parallelStream()
                    .map(request -> freshResultsGenerator.getResponse(request, e2EResultLongBL))

...

//最终使用此http客户端:

import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import com.google.common.base.Stopwatch;
import com.google.common.base.Strings;
import com.google.inject.Inject;


public class RoutingUrlHttpClient implements IRoutingUrlHttpClient {

    final static Logger logger = Logger.getLogger(RoutingUrlHttpClient.class);


    private IRoutingResponseFromStringFetcher routingResponseParser;
    private IRoutingResponseConverter routingResponseConverter;
    private IUrlUtils urlUtils;
    private CloseableHttpClient client;
    private ILogUtils logUtils;


    @Inject
    @Singleton
    public RoutingUrlHttpClient(IRoutingResponseFromStringFetcher routingResponseParser,
                                IRoutingResponseConverter routingResponseConverter, IUrlUtils urlUtils,
                                ILogUtils logUtils) {
        this.routingResponseParser = routingResponseParser;
        this.routingResponseConverter = routingResponseConverter;
        this.urlUtils = urlUtils;
        this.logUtils = logUtils;

        RequestConfig requestConfig = RequestConfig.custom()
                //time till handshake
                .setConnectTimeout(40 * 1000)
                //happens when you have a pool of connections and they are all busy, not allowing the connection
                // manager to give you one connection to make the request.
                .setConnectionRequestTimeout(40 * 1000)
                //time till response
                .setSocketTimeout(40 * 1000)
                .build();
        client = HttpClientBuilder
                .create()
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    private CompleteRoutingResponseDtoWrapper sendRoutingRequestString(int numberOfTriesLeft,
                                                                       String routingRequestUrl) {
        routingRequestUrl = urlUtils.getHttpUrl(routingRequestUrl);

        CompleteRoutingResponseDtoWrapper answer = new CompleteRoutingResponseDtoWrapper();
        CloseableHttpResponse response = null;
        try {

            logger.debug("before sending http");

            Stopwatch stopWatch = Stopwatch.createStarted();
            response = client.execute(new HttpGet(routingRequestUrl));
            stopWatch.stop();
//            String latencyMsg = "after sending http. client-latency: "+stopWatch.elapsed(TimeUnit.MILLISECONDS) +" server-latency: "+response.getHeaders("Latency")[0].getValue();

            logUtils.addLongToLongStatisticCollector("http.client.latency", (int)stopWatch.elapsed(TimeUnit.MILLISECONDS));
            logUtils.addLongToLongStatisticCollector("http.server.latency", Integer.parseInt(response.getHeaders("Latency")[0].getValue()));

            answer = analyzeStatusCodeAndMsgBody(numberOfTriesLeft, routingRequestUrl, answer, response, stopWatch);


        } catch (Exception e) {
//            e.printStackTrace();
//            System.out.println(e.getMessage());
            answer.errorMsg = e.getMessage();
            answer.latency = null;
        }
        handleNullResponse(answer);
        return answer;
    }

我经常收到错误:

Timeout waiting for connection from pool

当我从想法中获取请求时,

但导航浏览器时导航效果很好

你认为我应该在哪里调查瓶颈?

2 个答案:

答案 0 :(得分:0)

问题是我还没有关闭httpClient

            //try-with-resources
            try (CloseableHttpClient client = HttpClientBuilder
                    .create()
                    .setDefaultRequestConfig(requestConfig)
                    .build()){
                response = client.execute(new HttpGet(routingRequestUrl));
            stopWatch.stop();
//            String latencyMsg = "after sending http. client-latency: "+stopWatch.elapsed(TimeUnit.MILLISECONDS) +" server-latency: "+response.getHeaders("Latency")[0].getValue();

            logUtils.addLongToLongStatisticCollector("http.client.latency", (int)stopWatch.elapsed(TimeUnit.MILLISECONDS));
            logUtils.addLongToLongStatisticCollector("http.server.latency", Integer.parseInt(response.getHeaders("Latency")[0].getValue()));

            answer = analyzeStatusCodeAndMsgBody(numberOfTriesLeft, routingRequestUrl, answer, response, stopWatch);
            }

答案 1 :(得分:0)

关闭客户端将执行操作但是如果在每次调用后关闭客户端而不重用连接而不使用连接池。

我宁愿确保关闭HttpResponse,它会将连接返回到池中。

    try (CloseableHttpResponse response = client2.execute(get))
    {
        response.getStatusLine();
        // ..... read response and such
    }

有关详细信息,请参阅https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html

当然,您必须小心池配置,因为默认配置默认情况下每个路由只设置2个连接(可能有点低)。