[其它] 如何处理大量并发连接的超时

qiezi 2007-08-08
最近用epoll实现了一个reactor架构的网络框架,利用epoll的一些特性,实现了Reactor/LFReactor/HSHAReactor。Reactor是单线程的;LFReactor利用epoll_wait允许多个线程调用的特点,多个线程排队不用线程锁就可以完成;只有HSHAReactor使用了一个同步队列,测试性能也还不错。

另一个一直在犹豫的功能没加进去,就是连接超时。由于TCP本身没有提供这个特性(SCTP提供了这个),要实现就得自己处理。以前做了一个不完整版本,倒是把这个加进去了,就是一个callLater方法(仿twisted的),它本来是个定时器的功能,不过可以利用它完成连接超时。把所有要回调的方法放在队列中按时间排序,epoll_wait的超时取最近的一个就行了,单线程版本很容易做。多线程版本就得加上线程锁了,而且在一个socket事件发生后,还需要把它的超时回调方法从队列中移除,防止多个线程操作同一个处理对象。这个有点麻烦,需要从队列中快速找到并移除它,如果是非常多的并发连接,每个连接都设置了超时,这个对性能的影响会比较严重。前段时间有个项目的网络模块换成libevent后,负载比其它机器高了近一倍,而且高出来的都在用户空间中,我猜想和超时也有关系,因为其它地方几乎没有差别。

不知道其它项目如何处理这种?我看ACE做这个也不是很容易,以前用的版本在发生一个事件时,甚至没有取消其它注册的事件。我用strace看过erlang的调用,应该和我上面的想法差不多,基本上处理超时都不是很高效。难道说这个是不合理的需求?没有好的解决办法?

每次想到这些都不禁垂涎起SCTP来。。。
qiezi 2007-08-09
写完时想起一个简单的优化:

发生socket事件时,判断对应的对象有没有注册计时器,如果注册了就用该对象自己保存的第一个计时器去查找位置,因为它保存的自己的计时器是排序过的,reactor的计时器队列是按计时器时间排序的。不过也有麻烦的地方,为了方便插入计时器时插到合适位置,可能用list比较合适,但为了查找迅速,又需要随机访问的容器了。
iunknown 2007-08-11
qiezi 写道
不过也有麻烦的地方,为了方便插入计时器时插到合适位置,可能用list比较合适,但为了查找迅速,又需要随机访问的容器了。


在这方面,libevent 是使用 RBTree 来保存。在 event_base 中
struct event_base {

        RB_HEAD(event_tree, event) timetree;
};


但是 libevent 的比较函数有点奇怪,居然直接用指针来比较。估计是无可奈何了,只能用这个了。

static int
compare(struct event *a, struct event *b)
{
        if (timercmp(&a->ev_timeout, &b->ev_timeout, <))
                return (-1);
        else if (timercmp(&a->ev_timeout, &b->ev_timeout, >))
                return (1);
        if (a < b)
                return (-1);
        else if (a > b)
                return (1);
        return (0);
}

RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);

RB_GENERATE(event_tree, event, ev_timeout_node, compare);


Global site tag (gtag.js) - Google Analytics