事件驱动网络编程中的超时问题


在事件驱动的网络编程中进行超时处理是真正的挑战,常常要面对意想不到的 复杂性,现在有很多新发展出来的网络编程架构、运行时、语言提供某种用户 态线程的抽象,本质上,事件驱动的网络编程架构就是一种用户态协作式多线 程,只是大部分的网络架构仍然没有提供良好的“控制流”的抽象,应用不得 不面对上下文、回调这种本该属于“运行时”层面的问题。但本文还是把关注 点集中在IO调度,尤其是超时处理这个方面。

20.1 定时器

IO调度的本质上把多个阻塞集中为一个阻塞,在这一个阻塞上获取事件,发 生“中断”,挂起或者恢复(调度)原先那些本应该阻塞的控制流。在一个 控制流上并发地生产多个超时事件的东东就叫做定时器。

大体上,定时器是一个线程,接受注册超时事件,在任何一个超时事件的条件 满足时发出事件。基本的思路是用一个并发数据结构维护注册的事件,睡一段 时间醒来去看一下这个数据结构,收集满足条件的事件,根据应用上的要求, 做特定的事情(也就是发出事件)。

这里面就有两个选择,第一:选择何种数据结构,第二,怎么睡,睡多久。

关于第一个问题,使用最小堆或者优先队列应该是比较直观的想法。如果假 设比较后来进入的超时请求,应该概率上比先进入的超时请求更加迟到达, 这大部分应该是成立的,优先队列应该效率不错,但这需要评测,这两种数 据结构在一般的假设下都是合理的选择。

第二个问题,关于睡多久,自然是堆或者是队列首元素距离当前的时间,显 然,每次只要睡这么久就绝对不会错过。但是有一个问题就是当有事件注册 进来的时候,它到达的时间可能比当前堆或者队列的首元素的时间还要早, 也就是说注册之后它就是首元素了,那么这时候就要唤醒定时器,通知他更 新自己的睡眠时间。所以我们就用了一个poll做定时器,在poll上监控了一 个socket pair,用来唤醒定时器。

20.2 如何超时

应用上的超时比较好说,当然是应用要怎么超时就怎么超时。比方说超时30s 接收回复,那当然就是发出30s的超时请求。

麻烦的问题是如何进行连接超时,对连接超时的意思是说,如果连接长期空 闲,我们要把他关闭掉,或者另一种情况,我们是作为客户端,那就要向服 务端进行心跳,否则人家就把我们超时了。这里只谈服务端的情况,要判断 一个连接是不是超时,那就要维护它上面最后的读写操作发生的时间,也就 是说要有时间戳,另外,要间隔一定的时间去检查它是不是超时。

这里面主要的技巧,第一是时间戳缓存,我们还是用定时器去产生时间戳,对 定时器会有一个心跳间隔,也就是照前面的设计,不过他总是睡眠这个心跳间 隔和首元素之间较小的一个时间,每次醒来去更新一下时间戳。而在对连接 进行操作时候更新时间戳,就用定时器缓存的这个。另外,就是分代进行超 时,也就是说,不是针对每个连接,都发出一个超时请求,而是对相近的比 方一百个连接(或者最近1s产生的连接),用同一个超时请求去做超时。

posted on 2012-08-03 07:05 qingant 阅读(586) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

统计

常用链接

留言簿(3)

随笔档案

相册

最新随笔

搜索

最新随笔

最新评论

阅读排行榜

评论排行榜