`
xiaoZ5919
  • 浏览: 404677 次
  • 性别: Icon_minigender_1
  • 来自: 安平人@北京
博客专栏
Group-logo
Netty学习笔记
浏览量:73191
社区版块
存档分类
最新评论

话说Connect reset异常

    博客分类:
  • java
 
阅读更多

     起因是这样的,线上log经常出现Connection Reset异常,从堆栈上分析是solr进行sharding request时发生的,solr部署在tomcat上。从现场来看,原因很明白Server端发出RST包。但具体原因是什么就得经过一番分析了,

    经过google百度以及和网友沟通,发现会有以下场景导致RST:
    1. 设置SoLinger,并设置停留时间为0
     显然不是这样的场景,如是则会经常出现,而不是偶尔出现。还有其他的吗?我翻看了一下TCP/IP详解,TCP的连接与终止以及复位报文段。有点收获但还是没有看太懂,呵呵答案就在书上,也许没有沉下心去,一开始并没有书上介绍套出问题的场景。后来看到oracle的一篇文章http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html.
发现异常关闭非常适合出现问题的场景。啥叫异常关闭呢,正常的close是四次挥手
例如客户端执行close的时候,发出FIN,告诉对端我不再接受和发送数据,而对端也应该由应用程序调用close结束链接,也许你会说发出FIN只是告诉对端不再发送数据还能接收数据,事实上也是可以的,这样的关闭叫做半关闭,通过调用shutdown方法来实现。
   solr为什么会遇到这样的问题,httpclient为了减少链接的建立开销使用connection manager的连接池管理链接,我们知道虽然Http1.1支持keep alive,但仍有条件限制,例如keepalivetimeout以及keepalive的个数。当tomcat进行keepalive的connectin timeout处理的处理的,只是单方面的close,对端趟在连接池中的connection并不知道也不会执行相应的close,恰巧这时候有一个reuest使用这个connection发出请求,这一点特别重要,还是能发送数据的,最初的时候我以为服务端close了客户端就不能再使用conneciton发送数据了。服务端不会读取client端发过来的数据坚决执行关闭,这时候这个关闭就是RST而不是FIN了。
B's TCP stack knows that some data is effectively lost and it will forcibly terminate with RST rather than use the orderly FIN procedure.
   有两种这样的场景:
   1. A向B 发送数据,B的应用执行close,而这时A试图继续发而不是由应用调用close。
   2. A向B发送数据,B不做任何处理,不读取任何数据坚决地close,这时候这个close发的就是RST。
   我写了一段代码来模拟以上两种情况
Server
public static void run(){
                try{
                        //InetSocketAddress address = new InetSocketAddress("10.58.99.27", 9090);
                    //InetAddress address =     InetAddress.getByName("10.58.99.27");
            ServerSocket serverSocket = new ServerSocket(9090,1);
            ExecutorService threadPool = Executors.newCachedThreadPool();
//            for(int i = 0; i < 1;i++){
//              new Thread(new BioHttpServer.Connector()).start();
//            }
//            latch.countDown();
            while(true){
                   Socket client = serverSocket.accept();
                   Thread.sleep(1000);//调整这个时间 如调整为100 则为情况1 1000为情况2
                   client.close();
                 //  client.shutdownOutput();
//                   if(isDistribute){
//                         threadPool.execute(new SocketProcessor(client));
//                   }else{
//                         new SocketProcessor(client).run();
//                   }
    
            }   
    
        }catch(Exception e){ 
            e.printStackTrace();
        }finally{
    
        }   
        }  
 Client
try {
                        Socket client = new Socket("10.58.99.74", 9090);
                        //      client.setSoTimeout(5000);
                                System.out.println(client);
                                InputStream ins =client.getInputStream();
                                int i = 0;
                //              System.out.println(ins.read());
                                while(i++ < 100000){
                                   client.getOutputStream().write(64);
                                }   
                                System.out.println(ins.read());
                } catch (UnknownHostException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }   
 


  • 大小: 24.8 KB
  • 大小: 39.1 KB
分享到:
评论
10 楼 xiaoZ5919 2013-08-15  
blueswind8306 写道
没有使用过solr,不过个人感觉这个根本原因应该是solr维护的连接池的问题,一般连接池在维护过程中是需要考虑对端关闭的情况的,最简单的做法是在从池中borrow出来一个连接时,先要验证一下这个连接是否可用,如下是Jedis的验证连接可用的方法:
        public boolean validateObject(final Object obj) {
            if (obj instanceof Jedis) {
                final Jedis jedis = (Jedis) obj;
                try {
                    return jedis.isConnected() && jedis.ping().equals("PONG");
                } catch (final Exception e) {
                    return false;
                }
            } else {
                return false;
            }
        }


具体jedis.isConnected()方法中是这样实现的:
    public boolean isConnected() {
        return socket != null && socket.isBound() && !socket.isClosed()
                && socket.isConnected() && !socket.isInputShutdown()
                && !socket.isOutputShutdown();
    }


如果考虑这种方法的性能问题(jedis为了保险,还发了一个ping包过去),可以在连接池的管理线程内定时轮询所有闲置连接,这样就将每次borrow都validate变为了异步定时轮询validate。当然,在轮询间隔中还是有可能出现对端关闭的情况,此时就需要在应用内部将这个连接关闭,并retry一下了。


你的方案扩宽了我的思路,关于第一种方案,我又重新思考了当时的场景,httpclient是不是也提供了validate,如果提供了,每次借出的时候先检查一下应该能避免这样的情况哪为什么还会出现connection reset。我重新看了下httpclient的连接池源码发现了也做了validate。
if (entry.isClosed() || entry.isExpired(System.currentTimeMillis())) {
                        entry.close();
                        this.available.remove(entry);
                        pool.free(entry, false);
                    } else {
                        break;
                    }

    接下来怀疑isClosed()能否检测只是对端关闭的socket,写个程序证实了一下,只有对端关闭的话,本端的socket的isClosed依然为flase,这样看来jedis的ping还是用处的

关于异步轮询闲置连接,HttpClient的Connection连接池也给出了类似的方案。
public void run() {
        try {
            while (!shutdown) {
                synchronized (this) {
                    wait(5000);
                    // Close expired connections
                    connMgr.closeExpiredConnections();
                    // Optionally, close connections
                    // that have been idle longer than 30 sec
                    connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
                }
            }
        } catch (InterruptedException ex) {
            // terminate
        }
    }
9 楼 blueswind8306 2013-08-14  
没有使用过solr,不过个人感觉这个根本原因应该是solr维护的连接池的问题,一般连接池在维护过程中是需要考虑对端关闭的情况的,最简单的做法是在从池中borrow出来一个连接时,先要验证一下这个连接是否可用,如下是Jedis的验证连接可用的方法:
        public boolean validateObject(final Object obj) {
            if (obj instanceof Jedis) {
                final Jedis jedis = (Jedis) obj;
                try {
                    return jedis.isConnected() && jedis.ping().equals("PONG");
                } catch (final Exception e) {
                    return false;
                }
            } else {
                return false;
            }
        }


具体jedis.isConnected()方法中是这样实现的:
    public boolean isConnected() {
        return socket != null && socket.isBound() && !socket.isClosed()
                && socket.isConnected() && !socket.isInputShutdown()
                && !socket.isOutputShutdown();
    }


如果考虑这种方法的性能问题(jedis为了保险,还发了一个ping包过去),可以在连接池的管理线程内定时轮询所有闲置连接,这样就将每次borrow都validate变为了异步定时轮询validate。当然,在轮询间隔中还是有可能出现对端关闭的情况,此时就需要在应用内部将这个连接关闭,并retry一下了。

8 楼 xiaoZ5919 2012-11-15  
cuisuqiang 写道
我怎么听说是三次握手?
另外这无法解决网线中断引起的异常,心跳包都检测不到http://cuisuqiang.iteye.com/blog/1725348
不过还是感谢你的分享

三次握手,四次挥手
7 楼 xiaoZ5919 2012-11-15  
zhanlanlubai921 写道
反馈结果如下:
第一种方案:关闭keepalive。 这样会影响tomcat的效率,在高并发压力情况下,不太好。因此只好舍弃。
第二种方案:在tomcat端可以进行设置,但是在solrj进行设置就比较麻烦,目前solrj没有提供可以设置connection live时间的方法。如果自己创建httpclient又要进行管理,麻烦了,也只好舍弃。

我的最终解决办法:大概原理是:当出现connection reset时,捕获住异常,再向服务端(可多个)请求一次,第二次访问应该就不会出现reset异常了。

好吧 这也是一个办法
6 楼 cuisuqiang 2012-11-15  
我怎么听说是三次握手?
另外这无法解决网线中断引起的异常,心跳包都检测不到http://cuisuqiang.iteye.com/blog/1725348
不过还是感谢你的分享
5 楼 zhanlanlubai921 2012-11-10  
反馈结果如下:
第一种方案:关闭keepalive。 这样会影响tomcat的效率,在高并发压力情况下,不太好。因此只好舍弃。
第二种方案:在tomcat端可以进行设置,但是在solrj进行设置就比较麻烦,目前solrj没有提供可以设置connection live时间的方法。如果自己创建httpclient又要进行管理,麻烦了,也只好舍弃。

我的最终解决办法:大概原理是:当出现connection reset时,捕获住异常,再向服务端(可多个)请求一次,第二次访问应该就不会出现reset异常了。
4 楼 zhanlanlubai921 2012-11-09  
感谢楼主的细心回答,我试试看。有结果我及时反馈给你。
3 楼 xiaoZ5919 2012-11-08  
xiaoZ5919 写道
方案一 关闭keepalive 保证了顺序关闭
方案二 假如solr host在tomcat上,把maxKeeplive设置大些,并设置timeout时间长些,这样类似伪的长连接。同时solrj基于httpclient并使用threadsafeconnectionmanger维持一个connection pool。把connection的有效期设置小于服务端的timeout。这样能避免再次使用半关闭的connection。
这是我当时提出的方案,由于某些原因我的方案并没有实施 你可以试试!
zhanlanlubai921 写道
楼主我也遇到了这个问题,使用solrj过程中经常会发生Connection Reset这样的异常。
看完你的文章,觉得你描述问题成因很详细,但是却没有解决办法啊。
楼主最后是怎么解决这个问题的呢?


2 楼 xiaoZ5919 2012-11-08  
方案一 关闭keepalive 保证了顺序关闭
方案二 假如solr host在tomcat上,把maxKeeplive设置大些,并设置timeout时间长些,这样类似伪的长连接。同时solrj基于httpclient并使用threadsafeconnectionmanger维持一个connection pool。把connection的有效期设置小于服务端的timeout。这样能避免再次使用半关闭的connection。
这是我当时提出的方案,由于某些原因我的方案并没有实施 你可以试试!
1 楼 zhanlanlubai921 2012-11-08  
楼主我也遇到了这个问题,使用solrj过程中经常会发生Connection Reset这样的异常。
看完你的文章,觉得你描述问题成因很详细,但是却没有解决办法啊。
楼主最后是怎么解决这个问题的呢?

相关推荐

    java中的connection reset 异常处理分析

    在Java编程中,"connection reset"异常通常表示网络连接在数据传输过程中突然中断,这可能是由多种原因导致的。在本文中,我们将深入探讨这种异常的处理和分析,特别是与Java中的Socket通信相关的方面。 首先,`...

    easy-connect.exe

    easy-connect的安装包,深信服EasyConnect远程应用发布解决方案凭借应用虚拟化技术,快速实现客户的移动信息化建设,减少客户在APP和应用系统开发中投入的成本和实践,并保证数据信息安全。

    java.net.SocketException Connection reset 解决方法

    Conexion reset by peer 是一种特殊的 SocketException,它发生在客户端和服务器端之间的连接断开后,导致连接的一端继续发送数据,引发该异常。 本文将详细介绍 Conexion reset by peer 的原因、解决方法和相关...

    www.w3.org被qiang导致logback报错:Connect reset

    NULL 博文链接:https://desert3.iteye.com/blog/1041016

    Retrying connect to server 0.0.0.08032异常.md

    向yarn提交任务时Retrying connect to server 0.0.0.0:8032异常

    关于eclispe的“cannot connect to VM”

    标题中的“关于Eclipse的'cannot connect to VM'”指的是在使用Eclipse集成开发环境时,用户遇到的一个常见错误提示。这个错误通常发生在尝试启动Java虚拟机(JVM)时,Eclipse无法成功连接到它。这可能是由于多种原因...

    RocketMQ-Connect 二次开发源码

    RocketMQ-Connect 二次开发源码。RocketMQ-Connect 二次开发源码。RocketMQ-Connect 二次开发源码。RocketMQ-Connect 二次开发源码。RocketMQ-Connect 二次开发源码。RocketMQ-Connect 二次开发源码。RocketMQ-...

    shell脚本监控kafka-connect集群节点异常发送邮件通知.rar

    然而,当Kafka Connect集群中的节点出现异常时,及时发现并采取行动是必要的,以免数据丢失或系统故障。这就是“shell脚本监控kafka-connect集群节点异常发送邮件通知”所解决的问题。 首先,让我们深入了解Kafka ...

    nrf Connect.zip

    **nrf Connect** 是一款由Nordic Semiconductor公司开发的跨平台移动应用,主要用于蓝牙低功耗(BLE)和Zigbee设备的测试、调试和配对。它为开发者提供了便利的工具,以便于与Nordic的蓝牙智能硬件进行交互。在这款...

    EasyConnect lib for ubuntu20.4

    标题“EasyConnect lib for ubuntu20.4”指的是在Ubuntu 20.4操作系统上针对EasyConnect应用的一个特定库文件的解决方案。EasyConnect通常是一款远程桌面连接软件,它允许用户从Linux系统访问Windows桌面环境或其他...

    Mirth Connect V3.0.1 使用文档

    ### Mirth Connect V3.0.1 使用文档关键知识点 #### 一、Mirth Corporation简介与Mirth Connect概述 - **Mirth Corporation**: Mirth Corporation是一家专注于医疗信息集成解决方案的公司,提供了一系列强大的工具...

    java.net.SocketException: Connection reset 解决方法

    当另一端尝试读取数据时,由于连接已无效,会抛出"Connection reset"异常。 在上述描述中,开发者遇到的问题是由于一个定时任务(Timer)的不当使用导致的。这个任务负责在一个循环中频繁地执行一个方法,该方法...

    Mirth+Connect在医疗信息集成中的应用

    Mirth Connect在医疗信息集成中的应用 Mirth Connect是一款开源、跨平台、专门针对医疗信息领域的接口集成引擎。它支持多种协议,包括HL7、DICOM、JMS、SOAP等,可以对信息进行转换、映射、过滤和路由等多种处理,...

    DB2Connect用户指南

    ### DB2Connect用户指南知识点详解 #### 一、DB2Connect产品概述 - **产品版本**: DB2Connect 9.7 版本。 - **功能介绍**: - **数据库目录管理**: 支持对数据库目录进行管理和维护,确保用户能够高效地查找和访问...

    RRTconnect的matlab代码

    RRTconnect是RRT算法的一种变体,它专注于连接两个已知点之间的最短路径,而不仅仅是探索环境。在这个场景中,我们讨论的是使用MATLAB实现的RRTconnect算法。 RRT算法的核心思想是随机采样和局部搜索。它通过生成...

    easyconnect.rar

    EasyConnect用于连接内网

    Novatel connect工具软件

    Novatel Connect工具软件是一款专为Novatel GPS接收机设计的应用程序,它提供了全面的监控和管理功能,使得用户能够实时追踪和分析GPS接收机的数据。这个软件是Novatel公司为专业用户和开发者提供的一个强大平台,它...

    nrfconnect_pc_V3.10.0

    《nRFconnect PC工具V3.10.0详解及应用指南》 nRFconnect PC是Nordic Semiconductor推出的一款强大的开发工具,主要用于配合nRF5系列蓝牙低功耗(BLE)芯片进行无线连接和应用开发。本次我们关注的是nRFconnect PC...

    EasyConnect官方最新版|EasyConnect6.3.0.1

    EasyConnect最新版,下载解开压缩包后一键安装,亲测,可用。

    nrf Connect Desktop 蓝牙 桌面 连接工具 下载

    **nrf Connect Desktop:全方位蓝牙桌面连接工具** **一、nrf Connect Desktop简介** nrf Connect Desktop是一款由Nordic Semiconductor公司开发的专业蓝牙(Bluetooth)开发工具,它为开发者提供了全面的功能,...

Global site tag (gtag.js) - Google Analytics