Java 8 CloseableHttpClient.execute在超时情况下每隔几周冻结一次

Java 8 CloseableHttpClient.execute在超时情况下每隔几周冻结一次,java-8,apache-httpclient-4.x,Java 8,Apache Httpclient 4.x,我们有一个groovy singleton,它使用池大小为200的PoolightTPClientConnectionManager(httpclient:4.3.6)来处理到搜索服务的非常高的并发连接,并处理xml响应 尽管有指定的超时时间,它大约每月冻结一次,但在其余时间运行得非常好 下面是groovy singleton。retrieveInputFromURL方法似乎在client.execute(get)上被阻止 我在日志中也发现了这一点,这让我相信这是在等待响应数据时发生的 ja

我们有一个groovy singleton,它使用池大小为200的PoolightTPClientConnectionManager(httpclient:4.3.6)来处理到搜索服务的非常高的并发连接,并处理xml响应

尽管有指定的超时时间,它大约每月冻结一次,但在其余时间运行得非常好

下面是groovy singleton。retrieveInputFromURL方法似乎在client.execute(get)上被阻止

我在日志中也发现了这一点,这让我相信这是在等待响应数据时发生的

java.net.SocketTimeoutException:java.net.SocketInputStream.socketRead0(本机方法)处java.net.SocketInputStream.Read(SocketInputStream.java:150)处java.net.SocketInputStream.Read(socketInputInputStream.java:121)处sun.security.ssl.InputRecord.readFully(InputRecord.java:465)处的读取超时

迄今为止的调查结果:
  • 我们使用的是Java1.8u25。在类似的情况下,还有一个悬而未决的问题
  • HttpClient有一个类似的报告,但这在 我们正在使用的4.3.6版本
问题
  • 这可能是同步问题吗?根据我的理解,即使单例被多个线程访问,唯一的共享数据是缓存的CloseableHttpClient
  • 此代码、方法是否还有其他根本错误,可能导致此行为

    • 我看不出您的代码有任何明显的错误。不过,我强烈建议在连接管理器上设置SO_TIMEOUT参数,以确保它在创建时而不是在请求执行时应用于所有新套接字

      我还想知道“冻结”的确切含义。工作线程是否在等待从池获取连接或等待响应数据时被阻塞

      还请注意,如果服务器继续发送块编码数据,工作线程可能会显示为“冻结”。像往常一样,客户端会话的连接/上下文日志会有很大帮助

      我确实在RequestConfig中指定了用于构建CloseableHttpClient的SocketTimeout。这在创建时不适用于套接字吗?不,如果连接初始化涉及中间握手,例如TLS/SSL会话设置或使用CONNECT方法的连接隧道设置,则不适用。我假设丢失的分号是无意的?您能否提供客户端挂起线程堆栈的一部分。执行(get)到顶部(apache代码)。
      @Singleton(strict=false)
      class StreamManagerUtil {
         // Instantiate once and cache for lifetime of Signleton class
      
         private static PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
      
         private static CloseableHttpClient client;
      
         private static final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager);
      
         private int warningLimit;
         private int readTimeout;
         private int connectionTimeout;
         private int connectionFetchTimeout;
      
         private int poolSize;
         private int routeSize;
      
         PropertyManager propertyManager  = PropertyManagerFactory.getInstance().getPropertyManager("sebe.properties")
      
         StreamManagerUtil() {
            // Initialize all instance variables in singleton from properties file
      
            readTimeout = 6
            connectionTimeout = 6
            connectionFetchTimeout =6
      
            // Pooling
            poolSize = 200
            routeSize = 50
      
            // Connection pool size and number of routes to cache
            connManager.setMaxTotal(poolSize);
            connManager.setDefaultMaxPerRoute(routeSize);
      
            // ConnectTimeout : time to establish connection with GSA
            // ConnectionRequestTimeout : time to get connection from pool
            // SocketTimeout : waiting for packets form GSA
      
            RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(connectionTimeout * 1000)
            .setConnectionRequestTimeout(connectionFetchTimeout * 1000)
            .setSocketTimeout(readTimeout * 1000).build();
      
            // Keep alive for 5 seconds if server does not have keep alive header
            ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
               @Override
               public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                  HeaderElementIterator it = new BasicHeaderElementIterator
                     (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                  while (it.hasNext()) {
                     HeaderElement he = it.nextElement();
                     String param = he.getName();
                     String value = he.getValue();
                     if (value != null && param.equalsIgnoreCase
                        ("timeout")) {
                        return Long.parseLong(value) * 1000;
                     }
                  }
                  return 5 * 1000;
               }
            };
      
            // Close all connection older than 5 seconds. Run as separate thread.
            staleMonitor.start();
            staleMonitor.join(1000);
      
            client = HttpClients.custom().setDefaultRequestConfig(config).setKeepAliveStrategy(myStrategy).setConnectionManager(connManager).build();
         }     
      
         private retrieveInputFromURL (String categoryUrl, String xForwFor, boolean isXml) throws Exception {
      
            URL url = new URL( categoryUrl );
      
            GPathResult searchResponse = null
            InputStream inputStream = null
            HttpResponse response;
            HttpGet get;
            try {
               long startTime = System.nanoTime();
      
               get = new HttpGet(categoryUrl);
               response =  client.execute(get);
      
               int resCode = response.getStatusLine().getStatusCode();
      
               if (xForwFor != null) {
                  get.setHeader("X-Forwarded-For", xForwFor)
               }
      
               if (resCode == HttpStatus.SC_OK) {
                  if (isXml) {
                     extractXmlString(response)
                  } else {
                     StringBuffer buffer = buildStringFromResponse(response)
                     return buffer.toString();
                  }
               }
      
            }
            catch (Exception e)
            {
               throw e;
            }
            finally {
               // Release connection back to pool
               if (response != null) {
                  EntityUtils.consume(response.getEntity());
               }
            }
      
         }
      
         private extractXmlString(HttpResponse response) {
            InputStream inputStream = response.getEntity().getContent()
      
            XmlSlurper slurper = new XmlSlurper()
            slurper.setFeature("http://xml.org/sax/features/validation", false)
            slurper.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
            slurper.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false)
            slurper.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
      
            return slurper.parse(inputStream)
         }
      
         private StringBuffer buildStringFromResponse(HttpResponse response) {
            StringBuffer buffer= new StringBuffer();
            BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            String line = "";
            while ((line = rd.readLine()) != null) {
               buffer.append(line);
               System.out.println(line);
            }
            return buffer
         }
      
      public class IdleConnectionMonitorThread extends Thread {
      
          private final HttpClientConnectionManager connMgr;
          private volatile boolean shutdown;
      
          public IdleConnectionMonitorThread
            (PoolingHttpClientConnectionManager connMgr) {
              super();
              this.connMgr = connMgr;
          }
      
          @Override
          public void run() {
              try {
                  while (!shutdown) {
                      synchronized (this) {
                          wait(5000);
                          connMgr.closeExpiredConnections();
                          connMgr.closeIdleConnections(10, TimeUnit.SECONDS);
                      }
                  }
              } catch (InterruptedException ex) {
                  // Ignore
              }
          }
          public void shutdown() {
              shutdown = true;
              synchronized (this) {
                  notifyAll();
              }
          }
      }