jetty链接超时过期

标签: jetty 链接 | 发表时间:2015-04-06 20:20 | 作者:fuaotech
出处:http://www.iteye.com

Jetty误判长连接为超时连接的问题

在上一篇中介绍了jetty的反映器模型,selector线程与业务子线程交互的点有:

1、分发事件给子线程做,启动子线程;

2、子线程发现阻塞或者连接关闭等时间时,注册内部changes,等待selector线程调度;

3、检测超时连接,并且关闭连接。

 

在检测超时连接上面,jetty存在较多的问题,可能会误判。下面是一个典型的问题,问题一步一步定位的过程也是非常艰难和曲折的,但是最终问题找到的时候却发现不过如此。 
具体的问题出在下面这个判断表达式上面,下面这个方法是由主线程派生一个子线程的来调用的,在这个线程里面对所有的连接进行超时检查。

// Idle tick
if (now-_idleTick>__IDLE_TICK)
{
    _idleTick=now;
    
    final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections))
        ?(now+_maxIdleTime-_lowResourcesMaxIdleTime)
        :now;
        
    dispatch(new Runnable()
    {
        public void run()
        {
            for (SelectChannelEndPoint endp:_endPoints.keySet())
            {
                endp.checkIdleTimestamp(idle_now);
            }
        }
    });
}

 

被调用的方法:

/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
    if (_idleTimestamp!=0 && _maxIdleTime!=0 && now>(_idleTimestamp+_maxIdleTime))
    {
        idleExpired();
    }
} 

 

 

_idleTimestamp是每个连接实例中标志连接上次空闲的开始时间,如果该值为0,则说明连接处于非空闲,当子线程在处理请求时会频繁地将该变量在0值与空闲的时间点之间切换,而该变量本身是寄存器变量,可以保证变量本身在多线程之间的同步。但是上面是一个表达式,假如运行的时序是下面这样的:

1、子线程刚刚将连接置为空闲,那么_idleTimestamp大于0;

2、主线程开始判断该连接是否超时,判断到_idleTimestamp>0满足;

3、当程序继续运行时,子线程又将_idleTimestamp切换为0;

4、主线程开始判断now>(_idleTimestamp+_maxIdleTime)的条件,发现也满足;

5、最终,所有判断条件均为真,进入关闭连接的流程,连接被关闭。

这样就形成一个误判。本来连接上的请求正在处理,却被提前关闭了,最终会导致某一个请求处理失败,并且是莫名其妙的失败,网络抓包能发现是服务端关闭了连接,但是到底是谁关闭了连接都很难知道,最终通过在关闭socket的地方记录堆栈,待到堆栈累计到一定程度时,将其打印到日志中,结合抓包数据就能发现问题所在。

问题明确了,修改方法也简单:

/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
    long idleTimestamp = _idleTimestamp;
    if (idleTimestamp!=0 && _maxIdleTime!=0 && now>(idleTimestamp+_maxIdleTime))
    {
        idleExpired();
    }
}

 

 

这样就避免了在计算表达试的过程中全局变量的值被改变了。问题解决。

这个问题解决之后,紧随其后,又发现了另外一个更加奇怪的现象:

发现在连接启动之后,业务已经在处理中,最终业务处理完成,但是对外回复响应时却发现连接已经被关闭了。这个问题与上面的问题很像,但是不是同一个问题。经过上面的分析定位,对这里已经有一定的积累,很快就找到了连接关闭的根源,还是在检查超时连接上面。

经过反复推敲,发现问题出在下面3个函数的配合上面,当一个连接上面接近200秒(连接最大超时时间)都没有任何请求,而此时一个新的请求已经启动,但是还没有来得及调用cancelIdle来置空闲标志为0,这时请求已经开始处理,就在这个时候,主线程开始检查连接是否超时,结果发现已经超过200秒,连接上面没有处理任何数据,走入关闭连接的流程。

而此时业务线程已经在处理数据,等待数据处理完成,需要回复响应的时候才发现此连接已经断开了。这样客户端无法收到任何讯息。服务端记录该请求失败,但实际上请求已经处理成功。

/* ------------------------------------------------------------ */
public void scheduleIdle()
{
    _idleTimestamp=System.currentTimeMillis();
}

/* ------------------------------------------------------------ */
public void cancelIdle()
{
    _idleTimestamp=0;
}

/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
    long idleTimestamp = _idleTimestamp;
    if (idleTimestamp!=0 && _maxIdleTime!=0 && now>(idleTimestamp+_maxIdleTime))
    {
        idleExpired();
    }
}

这个问题的修改方法稍微复杂一点:

 
/* ------------------------------------------------------------ */
public void scheduleIdle() throws IOException
{
    synchronized (idleClosing)
    {
        if (idleClosing.get())
        {
            throw new IOException("the connection was closed right now. this request will be responsed a wrong value.");
        }
        else
        {
            _idleTimestamp=System.currentTimeMillis();
        }
    }
}

/* ------------------------------------------------------------ */
public void cancelIdle()
{
    _idleTimestamp=0;
}

/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
    long idleTimestamp = _idleTimestamp;
    if (idleTimestamp!=0 && _maxIdleTime!=0 && now>(idleTimestamp+_maxIdleTime))
    {
        synchronized (idleClosing )
        {
            if (_idleTimestamp == 0)
            {
                Log.warn("the request is doing. it cannot be closed!");
                return;
            }
            else
            {
                idleClosing.set(true);
            }
        }
        idleExpired();
    }
}

 

 
在两个方法之间用一个标志量来作为同步依据,当关连接的事情先发生,那么切换状态的操作就会因为idleclosing标志已经被置而直接抛出异常,不至于子线程继续处理数据。如果是子线程置连接为非空闲在前,则主线程的关连接操作也会不关连接而直接返回。
 
 
 


已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [jetty 链接] 推荐:

jetty链接超时过期

- - 开源软件 - ITeye博客
Jetty误判长连接为超时连接的问题. 在上一篇中介绍了jetty的反映器模型,selector线程与业务子线程交互的点有:. 1、分发事件给子线程做,启动子线程;. 2、子线程发现阻塞或者连接关闭等时间时,注册内部changes,等待selector线程调度;. 3、检测超时连接,并且关闭连接. 在检测超时连接上面,jetty存在较多的问题,可能会误判.

Jetty main函数执行

- - ITeye博客
在每个项目中都要配置路径什么的,非常的麻烦. 可以用jetty,项目本身就是服务器. 他会找项目中的WebContent. 已有 0 人发表留言,猛击->> 这里<<-参与讨论. —软件人才免语言低担保 赴美带薪读研.

jetty和tomcat比较(转)

- - 行业应用 - ITeye博客
jetty和tomcat比较. Tomcat 主要是作为 JSP/Servlet 最新规范的参考实现而设计,属于学院派,但是显得庞大而杂乱. Tomcat 的性能很差,一般是作为 Http Server(如 Apache)的插件来用. Jetty 主要是作为企业级产品的嵌入式组件来设计的,可以非常方便地嵌入到其它产品中.

Jetty 的工作原理以及与 Tomcat 的比较

- redhobor - IBM developerWorks 中国 : 文档库
Jetty 应该是目前最活跃也是很有前景的一个 Servlet 引擎. 本文将介绍 Jetty 基本架构与基本的工作原理:您将了解到 Jetty 的基本体系结构;Jetty 的启动过程;Jetty 如何接受和处理用户的请求. 你还将了解到 AJP 的一些细节:Jetty 如何基于 AJP 工作;以及 Jetty 如何集成到 Jboss;最后我们将比较一下两个 Servlet 引擎:Tomcat 和 Jetty 的优缺点.

号外号外,Jetty 9 正式版发布!!!

- - 开源中国社区最新新闻
版本标签: Jetty 9.0.0.v20130308. Jetty 9 支持 SPDY 和 WebSocket. Jetty 9.x 特性:. 移植到 Jetty 9.x 的要求:.

一个jetty部署多个项目配置之方法

- - 企业架构 - ITeye博客
原文地址:http://my.oschina.net/wangyongqing/blog/115647. Jetty用户经常想配置他们的web应用到不同的虚拟主机. 通常情况下,一个单一的IP地址的机器有不同的DNS解析名与它相关联的,部署在这个机器上的web应用必须能够通过这些关联的DNS解析名访问到.

Jetty 9.3庆祝20周年生日快乐,并增加HTTP/2支持

- - CSDN博客综合推荐文章
本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2015/06/Building-Distributed-Systems. 今年6月12日,Jetty项目发布了旗舰性开源嵌入式应用服务器的 9.3版,同时这一天也是该项目的20周年纪念日.

HTTP长链接和短链接

- - Web前端 - ITeye博客
HTTP协议与TCP/IP协议的关系. HTTP的长连接和短连接本质上是TCP长连接和短连接. HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议. IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠的传递数据包,使在网络上的另一端收到发端发出的所有包,并且顺序与发出顺序一致.

链接大放送

- Fenix - 增强视觉 | 计算机视觉 增强现实
google收购了PittPatt公司. 该公司主要提供人脸检测,识别,跟踪等技术. Picasa里面不是已经有相当强大的人脸识别了么. 这样算来google已经收购了三家CV的创业公司. Google talk中开始采用SRI Technology的SRI 2D视频稳定技术. SRI是一家独立的非盈利的研发机构,鄙人是第一次听说,官网介绍如下:.

911全链接(1)

- Beardnan - 1416 教室
这几天的假期彻底被911打败了. 看了媒体眼花缭乱的911报道,心里只有一个念头,您这么High,下一次怎么弄. 《纽约时报》的网络特刊The Reckoning,分成9个单元,每个单元内容都很丰富,有深度报道也有邀请读者参与的互动;视觉部分则有专题摄影,视频和互动图表相配合. 整个专题的页面清秀,主图是当年911之后的公民摄影展览Here Is New York: A Democracy of Photographs中最为卖座的照片,摄影师Katie Day Weisberger在911事件之前几个月在飞机上拍到了这张照片,当时还是个刚拿相机不久的学生.