Apache HttpClient: setConnectTimeout() vs. setConnectionTimeToLive() vs. setSocketTimeout()

前端 未结 2 1525
栀梦
栀梦 2021-02-07 09:38

Can someone please explain what is the difference between these two:

client = HttpClientBuilder.create()
    .setConnectionTimeToLive(1, TimeUnit.MINUTES)
    .b         


        
相关标签:
2条回答
  • 2021-02-07 10:37

    Connection Timeout: It is the timeout until a connection with the server is established.

    Socket Timeout: this is the time of inactivity to wait for packets[data] to receive.

    setConnectionRequestTimeout:

    However it is specific for configuring the connection manager. It is the time to fetch a connection from the connection pool.

    It returns the timeout in milliseconds used when requesting a connection from the connection manager. 0(zero) is used for an infinite timeout.

    setConnectionTimeToLive

    public final HttpClientBuilder setConnectionTimeToLive(long connTimeToLive, TimeUnit connTimeToLiveTimeUnit)

    Sets maximum time to live for persistent connections

    Please note this value can be overridden by the setConnectionManager(org.apache.http.conn.HttpClientConnectionManager) method.

    Since: 4.4

    Example: HttpClientStarter.java

    @Override
    public boolean start() {
    
        RegistryBuilder<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory> create();
    
        // Register http and his plain socket factory
        final SocketFactory ss = getLevel().find(SocketFactory.class);
        ConnectionSocketFactory plainsf = new PlainConnectionSocketFactory() {
            @Override
            public Socket createSocket(HttpContext context) throws IOException {
                return ss.createSocket();
            }
        };
        r.register("http", plainsf);
    
        // Register https
        ConnectionSocketFactory sslfactory = getSSLSocketFactory();
        if (sslfactory != null) {
            r.register("https", getSSLSocketFactory());
        } else {
            log(Level.WARN, "ssl factory not found, won't manage https");
        }
    
        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setUserAgent(USERAGENT);
        builder.setConnectionTimeToLive(timeout, TimeUnit.SECONDS);
        builder.evictIdleConnections((long) timeout, TimeUnit.SECONDS);
    
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r.build());
        cm.setMaxTotal(maxConnect * 2);
        cm.setDefaultMaxPerRoute(2);
        cm.setValidateAfterInactivity(timeout * 1000);
        builder.setConnectionManager(cm);
    
        RequestConfig rc = RequestConfig.custom()
                .setConnectionRequestTimeout(timeout * 1000)
                .setConnectTimeout(timeout * 1000)
                .setSocketTimeout(timeout * 1000)
                .build();
        builder.setDefaultRequestConfig(rc);
    
        client = builder.build();
    
        return true;
    }
    

    Resource Link:

    1. HttpClientStarter.java

    2. HttpClient 4.x Timeout

    The HTTP specification does not determine how long a persistent connection may or should remain active. Some HTTP servers use a non-standard header, Keep-Alive, to tell clients the number of seconds they want to stay connected on the server side. HttClient will take advantage of this if this information is available. If the header information Keep-Alive does not exist in the response, HttpClient assumes the connection remains active indefinitely. However, many real-world HTTP servers are configured to discard persistent connections after certain periods of inactivity to conserve system resources, often without notification to the client.

    Here you can rewrite one, here is set to 5 seconds

    ConnectionKeepAliveStrategy keepAliveStrategy = new DefaultConnectionKeepAliveStrategy() {
                @Override
                public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
                    long keepAlive = super.getKeepAliveDuration(response, context);
                    if (keepAlive == -1) {
                        keepAlive = 5000;
                    }
                    return keepAlive;
                }
            };
    

    Connection eviction policy

    The main disadvantage of a classic blocking I/O model is that network sockets respond to I/O events only when I/O operations are blocked. When a connection is released back to the manager, it can be kept alive without monitoring the status of the socket and responding to any I/O events. If the connection is closed on the server side, then the client connection can not detect changes in the connection status and shut down the local socket to respond properly.

    HttpClient tries to alleviate this problem by testing if the connection is outdated, which is no longer valid as it is already closed on the server side before using the connection that made the HTTP request. Outdated connection check is not 100% stable, but instead requires 10 to 30 milliseconds for each request execution. The only workable socket model thread solution that does not involve every free connection is to use a dedicated monitoring thread to reclaim the connection that is considered expired because of prolonged inactivity. Monitoring thread can periodically call ClientConnectionManager#closeExpiredConnections() method to close all expired connections, withdraw from the connection pool closed connection. It can also optionally call the ClientConnectionManager#closeIdleConnections() method to close all connections that have been idle for more than a given period of time.

    Resource Link:

    http://dev.dafan.info/detail/513285

    0 讨论(0)
  • 2021-02-07 10:39

    A ConnectTimeout determines the maximum time to wait for the other side to answer "yes, I'm here, let's talk" when creating a new connection (ConnectTimeout eventually calls socket.connect(address, timeout). The wait-time is usually less than a second, unless the other side is really busy with just accepting new incoming connections or you have to go through the great firewall of China. In the latter cases it can be a minute (or more) before the new connection is created. If the connection is not established within the ConnectTimeout, you get an error (1).

    setSocketTimeout eventually calls socket.setSoTimeout which is explained in this answer.

    The ConnectionTimeToLive determines the maximum age of a connection (after which it will be closed), regardless of when the connection was last used. Normally, there is an "idle timeout" to cleanup connections, i.e. you or the other side will close a connection that is not used for a while. Typically, you will close an idle connection before the other side does to prevent errors. But there are two other cases I can think of where a maximum age for a connection is useful:

    • Bad network components: count yourself lucky if you have not met them. Some bad routers, firewalls, proxies, etc. will just drop (actively being used) connections after something like 30 minutes. Since you and the other side may not even be aware that a connection was dropped, you can get "connection reset" errors for no obvious reason at weird times.
    • Cached meta-data: most systems keep some meta-data about a connection in some sort of cache. Some systems manage this cache badly - cache size just grows with the age of the connection.

    A note about the ConnectionTimeToLive implementation in Apache HttpClient 4.5.4: I think you must use the PoolingHttpClientConnectionManager for the option to work (it eventually all comes down to a call to this isExpired method). If you do not use this connection manager, test the option to make sure it really works.

    (1) Interesting comment from EJP on this related answer

    0 讨论(0)
提交回复
热议问题