当前位置: 首页 > 知识库问答 >
问题:

寻求关于Jetty HttpClient挂起的建议

潘安邦
2023-03-14

根本原因出现在Jetty HttpClient连接管理或线程管理的底层。通常,Jetty HttpClient会生成一组线程来处理HTTP GET(见下文),这些线程会按照您的预期启动和消失。在大约40小时或操作之后,JDK VisualVM显示至少9个连接线程不会立即消失:

  • HttpClient-计划程序x 1
  • HttpClient-选择器客户端SeclectorManager x 4
  • HttpClient x 4

  • RMI TCP连接

总共九到十个线程。在下一次读取时,创建新的线程实例来承载负载,然后客户端继续执行。此外,应用程序。有一个带有专用线程的时钟,它在应用程序锁定后继续运行,这表明JVM、操作系统和机器本身都很好。

有时,我们会看到这些“卡住”的线程在退出VisualVM线程显示之前停留长达一个小时。至少36小时后,我们看到线仍然存在,但我们没有看到它们消失。

 /**
  *   GET
  *   @return null or string returned from server
  **/
 public static String get( final String command ){

    String          rslt        = null;
    final String    reqStr      = "http://www.google.com";  //  (any url)

    HttpClient      httpClient  = new HttpClient();
    Request         request;
    ContentResponse response;

    try {
            //-- Start HttpClient
        httpClient.start();

        request   = httpClient.newRequest( reqStr );

        response  = request.send();

        if( null == response ){
            LOG.error( "NULL returned from previous HTTP request.");
        }
        else {
            if( (501 == response.getStatus()) || (502 == response.getStatus()) ){
                setNetworkUnavailable(String.format("HTTP Server error: %d", response.getStatus() ));
            }
            else {
                if(  404 == response.getStatus() ){
                    Util.puts(LOG,"HTTP Server error: 404");
    //              ignore message since we are talking to an old server
                }
                else if( 200 == response.getStatus() ){
                    rslt = response.getContentAsString();
                }
                else {
                    LOG.error(String.format( "    * Response status: \"%03d\".", response.getStatus() ));
                }
                setNetworkAvailable();
            }
        }
    }
    catch ( InterruptedException iEx ){
        LOG.warn( "InterruptException processing: "+reqStr, iEx );
    }
    catch ( Exception ex ){

        Throwable cause = eEx.getCause();
        if( (cause instanceof NoRouteToHostException) ||
            (cause instanceof EOFException)           ||
            (cause instanceof SocketException)
                && cause.getMessage().startsWith( EX_NETWORK_UNREACHABLE ) ){

            setNetworkUnavailable( cause.getMessage() );
        }
        else {
            LOG.error( "Exception on: "+command, ex );
        }
    }
    finally {
        try {
            httpClient.stop();
        }
        catch ( Exception ex ){
            LOG.error( "Exception httpClient.stop(), ServerManager::get()", ex );
        }
    }

    return rslt;

}//get method

这是基于简单的示例,关于使用HttpClient的细节很少。一切都是按照霍伊尔做的吗?

在不同的执行运行中,我们还会看到以下异常和日志消息:

  • [36822522]WARN 2014-sep-02 02:46:28.464>httpclient@2116772232{STOPPING,8<=0<=200,i=0,q=0}无法停止线程[httpclient@2116772232-729770,5,]

我们想知道这条消息是否与其中一条被卡住的线程有关?或者,这个消息是否表明了我们需要检查的一个单独的、不同的问题?还有:

  • java.util.concurrent.TimeoutException(ExecutionException)

这似乎是线程超时异常。哪条线呢?这与HTTP连接线程有关吗?我认为,服务在内部捕获错误时,至少可以指示错误的位置和堆栈跟踪。

有一些明显的问题:

  • get()方法代码是否按照要求编写,以避免泄漏或为Jetty HttpClient代码保留资源?
  • 我们如何捕捉警告:“无法停止线程”错误?
    • 此错误的影响是什么?有什么办法‘粉碎’这样卡住的线吗?
    • 这是否与10个挂起的连接线程有关?只有一条警告消息。
    • 假设一个挂起的线程需要错误标签,而不是警告。
    • 是否有可以直接影响线程锁定的设置?
    • Jetty调用仅在显示的GET方法中进行(尽管有更多日志记录等)

    另一个观察是,当我们在VisualVM中“卡住”线程时,它会在threads面板中显示多余的守护进程线程,而不是增加非守护进程线程。

    通过在for循环中运行上面所示的代码大约3或4个小时,在HttpClient send()调用之间间隔250毫秒,就会显示线程泄漏--在Linux上重现很简单。日志输出显示在距离线程泄漏至少30分钟的网络上没有警告和只有两个超时错误。

    欢迎提出建议、意见、改进和答复。我们提前表示感谢。

    相关问题:

    这些问题涉及一些非常相似的问题

    • 防波堤无故停止
    • ConnectionPoolTimeoutException:等待从池连接超时
    • 无法关闭Tomcat WebApp中的Neo4j Jetty服务器
    • -

共有1个答案

舒飞捷
2023-03-14

这种情况似乎要通过确保两件事来解决。

  1. 确保应用程序的线程池中有足够的线程
  2. 确保使用Jetty Clean的代码启动并捕获/管理所有异常。

这两种行为是相互关联的。如果HttpClient有时漏掉异常或错误,线程就会挂起。避免这种情况的唯一方法似乎是确保使用的每个HttpCLient都调用HttpCLient.stop()。这需要在最后{...}子句。

  • 如何通知Jetty 9.02的“已消耗内容”。ContentListener?

线程的数量将取决于您的应用程序。我建议使用jVisualVM或类似的工具来确保您的Jetty线程在优化线程池中的线程数量之前都得到了正确的清理。

我觉得文档需要强调清理,并确保调用stop()。而且据我所知,关于如何结束异步调用的信息还没有文档记录。只要您的Jetty调用完全停止,那么提供足够的线程似乎可以解决这一问题--通常需要注意管理并发。

 类似资料:
  • 上下文: Netty 3.6.3。最终,Java1.7,Scala 2.9. x 为了最大限度地减少(可能空闲的)线程数量,我想与不同的NIO套接字通道工厂(TCP)和一个NioDatagramChannelFactory共享NIO客户端/服务器和工作池。我使用至少两个(或三个与Finagle堆栈)服务器/客户端引导集,每个都有自己的NIO套接字通道工厂。为每个老板和工作池使用新的缓存线程池会导致

  • 我很难清楚地理解MySQL5.6使用/r/t memcache引入了什么。 按照我的理解,memcache本身本质上是一个巨大的、共享的、驻留内存的哈希表,由服务器memcached管理。特别是,它对持久数据存储一无所知,也不提供这方面的服务。它只知道键和值(像Perl散列)。 我认为MySQL5.6引入的是NoSQL API,mySQL客户端可以通过键而不是通过SELECT语句从mySQL服务器

  • 当我尝试使用读取此pod的日志时,它不会返回任何内容。如何查看日志以了解状态为“挂起”的原因?

  • 我正在使用路线距离估算大型城市网络的最后一英里交付成本。我有8000多名客户代理和100多名零售店代理,他们使用纬度/经度坐标绘制在GIS地图上。每个客户都会从最近的商店(通过路线)收到货物。目标是在该网络中为每个门店获取两个距离度量: d0_bar:从商店到所有指定客户的平均距离 d1_bar:单个商店共有的所有客户之间的平均距离 我编写了一个启动函数,其中包含一个简单的foreach循环,可以

  • 在React中开发验证功能。我是一个新手,不想在学习的同时养成任何坏习惯,所以我正在寻找关于如何清理这里的代码块的建议。 该函数检查输入字段,如果它们为空,则将适当的消息附加到数组。检查所有输入字段后,如果该数组为空,则继续提交表单。如果该数组包含错误消息,则该消息将显示到屏幕(未显示) 只是在寻找清理我的条件语句的方法,如果可能的话!谢谢

  • 我正在使用Java 8构建一个使用SpringBoot和SpringREST服务的API。我刚刚发现了Swagger API,现在我想让我的API与Swagger兼容。 据我所知,Swagger是一个记录您的APIS的工具,而且还提供了从规范(swagger.jsonv2中)生成客户端和服务器代码的功能,以及与您的API交互的漂亮Web界面。 现在,我想要一些关于如何继续的建议,因为我已经有了一个