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


如果连接由于网络或其他原因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. MS SQL SERVER 2008 R2 实例服务启动出现10048错误解决办法

    由于个人癖好,把MSSQLSERVER服务禁止了开机启动,每次需要的时候就输入CMD命令开启.今天在开启的时候,系统提示“发生服务特定错误:10048”. 于是打开SQL Server配置管理器,发现 ...

  2. HTML5 Canvas画数字时钟

    先不说废话,没代码算个蛋. 一些地方注释都写得比较清楚,不过这只是部分,因为只有秒针,但是时针,分针的逻辑都是一致的. 代码中有些坐标不知道为什么较不准,看看就好

  3. An erroroccurred while filtering resources

    maven报错: maven An error occurred while filtering resources Maven -> Update Project... resolved th ...

  4. JS 返回上一步(退回上一步上一个网页)

    链接式: <a href="JavaScript:history.go(-1)">返回上一步</a> <a href="<%=Requ ...

  5. linux 下面 opcache 拓展

    PHP 5.5.0 及后续版本中已经绑定了 OPcache 扩展,只需要在编译安装的时候, 如果你使用--disable-all参数 禁用了默认扩展的构建, 那么必须使用--enable-opcach ...

  6. 商务通代码API

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="content-type" content ...

  7. android 开源项目学习

    1.Android团队提供的示例项目 如果不是从学习Android SDK中提供的那些样例代码开始,可能没有更好的方法来掌握在Android这个框架上开发.由Android的核心开发团队提供了15个优 ...

  8. Spark的RDD编程(二)公众号undefined110

    创建RDD有两种方式:①读取外部数据集,lines=sc.textFile("README.md").②对一个集合进行并行化,lines=sc.parallelize([" ...

  9. c++ 顺序容器学习 - 容器适配器

    摘要: 对 容器适配器 的疑问. 刚开始接触 容器适配器 时,总感觉怪怪的,认为多此一举,顺手搜了搜,原来我在这一点is not alone: STL容器适配器的用途 其中有个老兄说的好,这里 引用一 ...

  10. Hadoop完全分布式集群安装

    转载请注明原地址,谢谢! 本文目的是教大家配置Hadoop的完全分布式的集群,除了完全分布式还有两种分别是单节点和伪分布式部署.伪分布式只需要一台虚拟机,配置的东西也相对较少,大多用作代码调试,大家稍 ...