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


如果连接由于网络或其他原因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. POJ 3468.A Simple Problem with Integers 解题报告

    用树状数组和线段树会比较简单,这里用这道题来学习Splay. 第一次写,代码比较丑 /* 初始化添加一个key值足够大的结点 保证每个需要的结点都有后继 */ #include <iostrea ...

  2. 安装完 MySQL 后必须调整的 10 项配置

    原文出处: mysqlperformanceblog   译文出处:开源中国   欢迎分享原创到伯乐头条 当我们被人雇来监测MySQL性能时,人们希望我们能够检视一下MySQL配置然后给出一些提高建议 ...

  3. .getBoundingClientRect()

    .getBoundingClientRect() 该方法获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置,他返回的是一个对象,即Object,该对象有4个属性:top,left,right, ...

  4. 一个基于nodejs,支持http/https的中间人(MITM)代理,便于渗透测试和开发调试。

    源码地址:https://github.com/wuchangming/node-mitmproxy node-mitmproxy node-mitmproxy是一个基于nodejs,支持http/h ...

  5. 一站式远程页面调试工具spy-debugger 2.0,已支持HTTPS

    项目名称: spy-debugger 项目地址:https://github.com/wuchangming/spy-debugger 关于spy-debugger npm Build Status ...

  6. document模板

    http://bce.baidu.com/doc/CDS/GettingStarted.html

  7. Android RecyclerView Adapter 新式用法之SortedListAdapterCallback

    引言 前几天在同事的提醒下发现V7中有了一个新的工具类SortedListAdapterCallback,配合RecyclerView Adapter和SortedList一起使用更加方便的管理我们在 ...

  8. 长期支持版本(即不自动更新版本) - Flash Player 18.0.0.268

    无意中发现,适合不喜欢折腾的朋友. 下载链接:(官方:http://www.adobe.com/cn/products/flashplayer/distribution3.html) (分流:http ...

  9. GPUImage 自定义滤镜

    GPUImage 自定义滤镜 GPUImage 是一个基于 GPU 图像和视频处理的开源 iOS 框架.由于使用 GPU 来处理图像和视频,所以速度非常快,它的作者 BradLarson 称在 iPh ...

  10. Transformation

    hdu4578:http://acm.hdu.edu.cn/showproblem.php?pid=4578 题意:给一个序列 {an},有 4 种操作.1.将一段区间的数全部加 c.2.将一段区间的 ...