某些用户,机器重启后,到第三方服务器的连接起不来,而到我们自己服务器的连接就没事。


如果连接由于网络或其他原因fail掉,过一定时间后应该会重新尝试建立连接的。

测试组做初步调查,他们能在本地环境复现,只是不是稳定复现,时而有时而没有。(嗯,race condition的问题就常常比较飘忽不定,并且往往在系统繁忙负载高的时候爆发)。我开始参与。

分析了一下现有的log,不能得出任何结论。所以在代码中另外增加了一些debug log,然后测试组再跑... 最后终于看到问题根本。

我们有两种类型的链路,分开管理,但基本的socket特性是共享代码的。


这个到第三方服务器的接口,是没有应用层的保活(或者说心跳)协议的。需要依靠TCP层的状态和事件来管理连接。并且这个第三方也禁止持久连接,只能需要发请求的时候按需建立连接。空闲时(没有请求需要发送),需要把连接关闭。所以连接内部有一种状态是"Idle Closed", 表示连接因为闲置而关闭但相信是健康的。


最初代码里的设计是有点倾向异步的。跟我们自己的服务器的链路,连接是这样建立的:一个线程对一个非阻塞socket调用connect() ,(将状态标识为Connecting),然后另外一个线程对所有在Connecting 状态的socket做select()来探测可写事件。如果捕获可写事件,则连接状态变为Connected。


也许部分是由于第三方链路的非持久特性,或是写代码的简易性(调用一个函数返回之后连接要么建立成功要么失败,明显代码流简单很多),跟第三方服务器的连接是同步地建立的。一个线程调用名字像****ConnectSync()这样的一个函数来同步地建立连接。然而,里面用到的系统调用却不是同步的那一个connect:对一个非阻塞socket调用connect(),(将状态标识为Connecting),然后阻塞在一个select()调用。select() 得到可写事件或者超时****ConnectSync()就返回,这样****ConnectSync() 就看起来像同步的。
 
如果一个socket在****ConnectSync()被设为Connecting状态,另外一个线程会对这个socket调用select() 来探测可写事件。


两个线程对同一个socket调用select(),只有其中一个线程可以获得代表连接被建立起来的可写事件 (至少在Windows平台上是这样)。
所以,一个线程把连接标识为connected 然后idle closed掉它,另外一个线程认为连接失败(因为没得到可写事件)所以把连接标识为not Available。

如果一个链路即是 idle closed的又是not Available的,那将不再对它做链路测试(因为idle closed表明链路是健康的),也不会再有请求来的时候选中它来建立连接(not Available所以不会被选中)。(嗯,链路的多个标志位也让人看起来有点混乱) 所以到第三方服务器的链路才会永久性失败,因为再也不会尝试它了。


修复很明显...

-------------------------------------------------------------------------------------------------

阅读更多博文可订阅RSS,了解更多最新动态可关注微博 @千里孤行Nerd

遭遇多线程bug (1)的更多相关文章

  1. 实现TOLock过程中的一处多线程bug

    背景 最近在啃<多处理器编程的艺术>,书中的7.6节介绍了时限锁--实现了tryLock方法的队列锁. 书中重点讲解了tryLock的实现,也就是如何实现在等待超时后退出队列,放弃锁请求, ...

  2. AppStore遭遇大BUG

    用AppLoader上传,提示这个 The u option must have a non-empty value.The password must have a non-empty value. ...

  3. jdk1.6空轮询Bug的原因及解决方法

    简述 本文主要介绍一下jdk1.6版本中的NIO Selector空轮询BUG,描述一下BUG的现象及原因,以及Netty中如何巧妙的规避了这个bug. 为什么要写这篇文章,说来惭愧,很久以前面试官问 ...

  4. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  5. 第二单元总结:基于synchronize锁的简单多线程设计

    单元统一的多线程设计策略 类的设计 电梯 每部电梯为一个线程. 电梯从调度器接收原子指令,知晓自己的状态(内部的人/服务的人.运行方向.所在楼层) 原子指令包括且仅包括: 向上走一层 / 向下走一层 ...

  6. j2ee高并发时使用全局变量需要注意的问题

    原文:https://blog.csdn.net/jston_learn/article/details/21617311 开发中,全局变量的使用很频繁,但对于多线程的访问,使用全局变量需要注意的地方 ...

  7. Qt on Android 核心编程

    Qt on Android 核心编程(最好看的Qt编程书!CSDN博主foruok倾力奉献!) 安晓辉 著   ISBN 978-7-121-24457-5 2015年1月出版 定价:65.00元 4 ...

  8. IOS学习之路--OC的基础知识

    1.项目经验 2.基础问题 3.指南认识 4.解决思路 ios开发三大块: 1.Oc基础 2.CocoaTouch框架 3.Xcode使用 -------------------- CocoaTouc ...

  9. iOS求职之OC面试题

    1.Objective-C的类可以多重继承么?可以采用多个协议么? 答:不可以多重继承,可以采用多个协议. 2.#import和#include的区别是什么?#import<> 跟 #im ...

随机推荐

  1. c#与c++交互的一些东西

    最近做一个项目,对方公司只提供了一个c++的DLL,但没封住,c#无法DllImport.所以只能自己写c++来封住了. 对方的Dll只接收yuv420的图片格式,所以在c++里用opencv来转换. ...

  2. CSS布局模型思考

    flow模型:默认布局模型,元素从左向右.从上到下依次排列,块状元素独占一行.Position属性对应值static. float模型:主要效果是让本来独占一行的块状元素变成内联-块状元素,并到一排显 ...

  3. servlet从xml提取数据登陆

    在xml文档下可以设置参数的初始值,在这里把他当成了数据库在用 <servlet> <description>This is the description of my J2E ...

  4. URPF 简单流程

    主要功能是防止基于源地址欺骗的网络攻击. 路由器接口一旦使能URPF功能,当该接口收到数据报文时,首先会对数据报文的源地址进行合法性检查,对于源地址合法性检查通过的报文,才会进一步查找去往目的地址的转 ...

  5. Bootstrap_Javascript_提示框

    一. 结构分析 在Bootstrap框架中的提示框,结构非常简单,常常使用的是按钮<button>标签或者链接<a>标签来制作.不管是使用按钮还是链接来制作提示框,他们都有一个 ...

  6. how to make choices about girls?

    yb ldge nvhl, yige hf csmn, hv bmig, hv zofj, hfyb uhjnxn;ldyige ybdm bfbfde, gjjt hf djip, djui hfk ...

  7. 访问Github过慢解决

    在这个地址查找响应最快的地址:http://tool.chinaz.com/dns?type=1&host=assets-cdn.github.com&ip= 查找:assets-cd ...

  8. iOS中MVC等设计模式详解

    iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...

  9. iOS证书详解--再转

    一.成员介绍1.    Certification(证书)证书是对电脑开发资格的认证,每个开发者帐号有一套,分为两种:1)    Developer Certification(开发证书)安装在电脑上 ...

  10. div+css知识点

    前端书写规范: 1.所有书写均在英文半角状态下的小写: 2.id,class必须以字母开头: 3.所有标签必须闭合: 4.html标签用tab键缩进: 5.属性值必须带引号: 6.<!-- ht ...