Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 无法配置";“保持活力”;在Camel HTTP组件中_Java_Sockets_Apache Camel - Fatal编程技术网

Java 无法配置";“保持活力”;在Camel HTTP组件中

Java 无法配置";“保持活力”;在Camel HTTP组件中,java,sockets,apache-camel,Java,Sockets,Apache Camel,我在HTTP组件的正确设置方面遇到了一些问题。目前,微服务从提供者提取JSON内容,对其进行处理,并将其发送到下一个服务进行进一步处理。主要的问题是这个微服务创建了大量的CLOSE_WAIT套接字连接。我知道“KEEP-ALIVE”的整个概念将使连接保持打开状态,直到我关闭它为止,但服务器可能会因为某些原因中断连接并创建此close_WAIT套接字 我创建了一个用于调试/测试目的的小型服务,它向Google发出GET调用,但即使是这个连接,在我关闭程序之前都保持打开状态。我尝试了许多不同的解决方

我在HTTP组件的正确设置方面遇到了一些问题。目前,微服务从提供者提取JSON内容,对其进行处理,并将其发送到下一个服务进行进一步处理。主要的问题是这个微服务创建了大量的CLOSE_WAIT套接字连接。我知道“KEEP-ALIVE”的整个概念将使连接保持打开状态,直到我关闭它为止,但服务器可能会因为某些原因中断连接并创建此close_WAIT套接字

我创建了一个用于调试/测试目的的小型服务,它向Google发出GET调用,但即使是这个连接,在我关闭程序之前都保持打开状态。我尝试了许多不同的解决方案:

  • .setHeader(“连接”,常量(“关闭”))
  • -Dhttp.keepAlive=false作为VM参数
  • 从Camel Http切换到Camel-Http4
  • httpClient.soTimeout=500(驼峰HTTP)、httpClient.socketTimeout=500和ConnectionTimeOlive=500(驼峰-HTTP4)
  • .setHeader(“连接”,简单(“保持活动”))和 .setHeader(“保持活动”,简单(“超时=10”)(Camel-HTTP4)
  • 通过调试DefaultConnectionKeepAlivestStrategy从-1(永无止境)到Camel-HTTP4中的特定值的响应进行设置-这是可行的,但我无法注入自己的策略
但我没有成功。所以也许你们中的一个可以帮助我:

  • 我如何告诉驼峰HTTP在经过特定时间后应该关闭连接?例如,该服务每小时从内容提供商处提取一次。3-4小时后,HttpComponent应在拉动后关闭连接,并在下一次拉动时重新打开连接。目前,每个连接都将放回多线程HttpConnectionManager,并且套接字仍然打开
  • 如果不能用Camel-HTTP实现这一点:如何将HttpClientBuilder注入到路由的创建中?我知道应该可以通过httpClient选项实现,但我不理解文档中的具体部分

感谢大家的帮助

您可以向HTTP4提供自己的
客户端连接管理器
。通常,您应该使用
org.apache.http.impl.conn.poolighttpclientconnectionmanager
的实例,您可以使用自己的
org.apache.http.config.SocketConfig
将其传递给连接管理器的
setDefaultSocketConfig
方法来配置该实例

如果您将Spring与Java配置一起使用,您将有一个方法:

@Bean
PoolingHttpClientConnectionManager connectionManager() {
    SocketConfig socketConfig = SocketConfig.custom()
            .setSoKeepAlive(false)
            .setSoReuseAddress(true)
            .build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    connectionManager.setDefaultSocketConfig(socketConfig);
    return connectionManager;
}

然后您只需在端点定义中使用它,就像这样:
clientConnectionManager=#connectionManager

如果空闲连接在配置的时间内处于空闲状态,则可以通过关闭空闲连接来完成。您可以通过为驼峰Http组件配置空闲连接超时来实现同样的目的。 骆驼Http提供了这样做的接口

将org.apache.camel.component.http4.HttpComponent强制转换为PoolighttpClientConnectionManager

        PoolingHttpClientConnectionManager poolingClientConnectionManager = (PoolingHttpClientConnectionManager) httpComponent
                .getClientConnectionManager();

        poolingClientConnectionManager.closeIdleConnections(5000, TimeUnit.MILLISECONDS);

请访问此处[,java.util.concurrent.TimeUnit)]

不幸的是,在应用程序最终关闭之前,所有建议的答案都没有解决我方的
CLOSE\u WAIT
连接状态

我用以下测试用例重现了这个问题:

公共类HttpInvokationTest扩展了对SpringTest的支持{
私有静态最终记录器LOG=LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@端点注入(uri=“mock:success”)
私有模拟点;
@端点注入(uri=“mock:failure”)
私有模拟端点故障端点;
@凌驾
受保护的AbstractApplicationContext createApplicationContext(){
返回新的AnnotationConfigApplicationContext(ContextConfig.class);
}
@配置
@导入(HttpClientSpringTestConfig.class)
公共静态类ContextConfig扩展了配置{
@凌驾
公共列表路线(){
列表路由=新的ArrayList(1);
routes.add(新RouteBuilder(){
@凌驾
public void configure(){
从(“直接:开始”)
.log(LoggingLevel.INFO,log,机密,“调用外部URL:${header[ERPEL_URL]}”)
.setHeader(“连接”,常量(“关闭”))
.recipientList(标题(“测试URL”))
.log(LoggingLevel.DEBUG,“HTTP响应代码:${header[“+Exchange.HTTP\u response\u code+“]}”)
.bean(CopyBodyToHeaders.class)
.choice()
.when(标头(Exchange.HTTP\u RESPONSE\u CODE).isGreaterThanOrEqualTo(300))
.至(“模拟:失败”)
.否则()
。至(“模仿:成功”);
}
});
返回路线;
}
}
@试验
public void testHttpInvocation()引发异常{
SuccessedPoint.expectedMessageCount(1);
failureEndpoint.expectedMessageCount(0);
ProducerTemplate=context.createProducerTemplate();
sendboyandheader(“direct:start”,null,“TEST_URL”,“http4://meta.stackoverflow.com”);
successedpoint.assertessatified();
failureEndpoint.Assertessatified();
Exchange=successedpoint.getExchanges().get(0);
Map headers=exchange.getIn().getHeaders();
String body=exchange.getIn().getBody(String.class);
for(字符串键:headers.keySet()){
LOG.info(“Header:{}->{}”,key,headers.get(key));
}
LOG.info(“正文:{}”,正文);
睡眠(120000);
}
}
并发出
netstat-ab-ptcp | grep151.101.129.69
请求,其中IP是
meta.stackoverflow.com
中的一个

这给了如下回答:

tcp4       0      0  192.168.0.10.52183     151.101.129.69.https   ESTABLISHED      37562       2118
tcp4       0      0  192.168.0.10.52182     151.101.129.69.http    ESTABLISHED        885        523
就在调用之后

tcp4       0      0  192.168.0.10.52183     151.101.129.69.https   CLOSE_WAIT       37562       2118
tcp4       0      0  192.168.0.10.52182     151.101.129.69.http    CLOSE_WAIT         885        523
响应,直到应用程序由于
连接:keep alive
标题而关闭,即使配置如下:

@配置
@EnableConfigurationProperties(HttpClientSettings.class)
公共类HttpClientSpringTestConfig{
专用最终静态记录器日志=记录器
/**
 * This singleton monitor will check every few seconds for idle and stale connections and perform
 * a cleanup on the connections using the registered connection managers.
 */
public enum IdleConnectionMonitor {

  INSTANCE;

  private final static Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  /** The execution service which runs the cleanup every 5 seconds **/
  private ScheduledExecutorService executorService =
      Executors.newScheduledThreadPool(1, new NamingThreadFactory());
  /** The actual thread which performs the monitoring **/
  private IdleConnectionMonitorThread monitorThread = new IdleConnectionMonitorThread();

  IdleConnectionMonitor() {
    // execute the thread every 5 seconds till the application is shutdown (or the shutdown method
    // is invoked)
    executorService.scheduleAtFixedRate(monitorThread, 5, 5, TimeUnit.SECONDS);
  }

  /**
   * Registers a {@link HttpClientConnectionManager} to monitor for stale connections
   */
  public void registerConnectionManager(HttpClientConnectionManager connMgr) {
    monitorThread.registerConnectionManager(connMgr);
  }

  /**
   * Request to stop the monitoring for stale HTTP connections.
   */
  public void shutdown() {
    executorService.shutdown();
    try {
      if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
        LOG.warn("Connection monitor shutdown not finished after 3 seconds!");
      }
    } catch (InterruptedException iEx) {
      LOG.warn("Execution service was interrupted while waiting for graceful shutdown");
    }
  }

  /**
   * Upon invocation, the list of registered connection managers will be iterated through and if a
   * referenced object is still reachable {@link HttpClientConnectionManager#closeExpiredConnections()}
   * and {@link HttpClientConnectionManager#closeIdleConnections(long, TimeUnit)} will be invoked
   * in order to cleanup stale connections.
   * <p/>
   * This runnable implementation holds a weakly referable list of {@link
   * HttpClientConnectionManager} objects. If a connection manager is only reachable by {@link
   * WeakReference}s or {@link PhantomReference}s it gets eligible for garbage collection and thus
   * may return null values. If this is the case, the connection manager will be removed from the
   * internal list of registered connection managers to monitor.
   */
  private static class IdleConnectionMonitorThread implements Runnable {

    // we store only weak-references to connection managers in the list, as the lifetime of the
    // thread may extend the lifespan of a connection manager and thus allowing the garbage
    // collector to collect unused objects as soon as possible
    private List<WeakReference<HttpClientConnectionManager>> registeredConnectionManagers =
        Collections.synchronizedList(new ArrayList<>());

    @Override
    public void run() {

      LOG.trace("Executing connection cleanup");
      Iterator<WeakReference<HttpClientConnectionManager>> conMgrs =
          registeredConnectionManagers.iterator();
      while (conMgrs.hasNext()) {
        WeakReference<HttpClientConnectionManager> weakConMgr = conMgrs.next();
        HttpClientConnectionManager conMgr = weakConMgr.get();
        if (conMgr != null) {
          LOG.trace("Found connection manager: {}", conMgr);
          conMgr.closeExpiredConnections();
          conMgr.closeIdleConnections(30, TimeUnit.SECONDS);
        } else {
          conMgrs.remove();
        }
      }
    }

    void registerConnectionManager(HttpClientConnectionManager connMgr) {
      registeredConnectionManagers.add(new WeakReference<>(connMgr));
    }
  }

  private static class NamingThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
      Thread t = new Thread(r);
      t.setName("Connection Manager Monitor");
      return t;
    }
  }
}
/**
 * This Camel service with take care of the lifecycle management of {@link IdleConnectionMonitor} 
 * and invoke {@link IdleConnectionMonitor#shutdown()} once Camel is closing down in order to stop
 * listening for stale connetions.
 */
public class IdleConnectionMonitorService extends EventNotifierSupport {

  private final static Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  private IdleConnectionMonitor connectionMonitor;

  @Override
  public void notify(EventObject event) {
    if (event instanceof CamelContextStartedEvent) {
      LOG.info("Start listening for closable HTTP connections");
      connectionMonitor = IdleConnectionMonitor.INSTANCE;
    } else if (event instanceof CamelContextStoppingEvent){
      LOG.info("Shutting down listener for open HTTP connections");
      connectionMonitor.shutdown();
    }
  }

  @Override
  public boolean isEnabled(EventObject event) {
    return event instanceof CamelContextStartedEvent || event instanceof CamelContextStoppingEvent;
  }

  public IdleConnectionMonitor getConnectionMonitor() {
    return this.connectionMonitor;
  }
}
private void registerHttpClientConnectionManager(HttpClientConnectionManager conMgr) {
  if (!getIdleConnectionMonitorService().isPresent()) {
    // register the service with Camel so that on a shutdown the monitoring thread will be stopped
    camelContext.getManagementStrategy().addEventNotifier(new IdleConnectionMonitorService());
  }
  IdleConnectionMonitor.INSTANCE.registerConnectionManager(conMgr);
}

private Optional<IdleConnectionMonitorService> getIdleConnectionMonitorService() {
  for (EventNotifier eventNotifier : camelContext.getManagementStrategy().getEventNotifiers()) {
    if (eventNotifier instanceof IdleConnectionMonitorService) {
      return Optional.of((IdleConnectionMonitorService) eventNotifier);
    }
  }
  return Optional.empty();
}
PoolingHttpClientConnectionManager conMgr = new PoolingHttpClientConnectionManager();
registerHttpClientConnectionManager(conMgr);
@Bean(name = "httpClientConfigurer")
public HttpClientConfigurer httpConfiguration() {
    return builder -> builder.setDefaultSocketConfig(socketConfig)
        .setDefaultRequestConfig(requestConfig)
        .setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE);
}
    HttpComponent http4 = camelContext.getComponent("https4", HttpComponent.class);
    http4.setHttpClientConfigurer(new HttpClientConfigurer() {

        @Override
        public void configureHttpClient(HttpClientBuilder builder) {
            builder.setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE);
        }
    });