您的位置:首页 > 其它

高性能IO设计模式及其应用

2016-03-31 17:08 417 查看
转自:http://blog.sina.com.cn/s/blog_6a4c492f0100o6lr.html

想当然的服务器设计模式

服务器一般需要支持高性能的I/O,大并发等。先来看看大多数工程师准备自主开发一个服务器之前,自然而然想到的一些设计模式。准确的讲是实现的方法,远远谈不上设计模式。

第一种实现一个服务器的想当然的方法是,当有请求过来时,就fork一个子进程进行处理。下面这段示例代码是一个按照这种方法实现的服务器。这种方法易于理解,实现简单,如果并发量比较小,应该也能应付。但是如果是高并发的服务器就不理想了,因为fork大量的进程,并在不同的进程之间切换会消耗大量资源,造成服务器运行的效率下降。

int main(int argc, char **argv)
{
listenfd = Socket (AF_INET, SOCK_STREAM, 0);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);

for ( ; ; ) {
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
if ( (childpid = Fork()) == 0) {
process(connfd);
exit (0);
}
}
}

第二种实现服务器的方法是所谓的preforking,也就是预先创建”足够的“进程,每个进程通过accept阻塞在被侦听的端口上。也就是所谓的线程池的方法。这里不再示例代码,想了解细节请参照《UNIX Network Programming Volume
1, Third Edition》的30.6。

顺便提一下,第二种实现服务器的方法中,多个线程阻塞在同一个侦听端口上accept,存在所谓的 thundering
herd 问题,因此select(epoll,kqueue,iocp)就成了服务器编程的想当然的选择。

高性能I/O设计模式 - Reactor

Reactor设计模式中的要素如下:

Handles,也就是网络连接,文件句柄等。是事件源。

Synchronous Event Demultiplexer,同步事件的解复用(或者说派发),具体的比如select调用。比select更加高效的有linux下的epoll,freebsd下的kqueue以及windows下的iocp(IO Completion
port)。

Initiation Dispatcher,注册、移除和分派事件处理句柄。

Event Handler,就是事件处理句柄。

结合上面的描述,给出来自参考资料[3]图片如下:




无论是Reator还是Proactor,都包含了事件分离器和事件处理器。在接下来的对于Darwin视频服务器的分析中会发现其中也包含了事件分离器和事件处理器。
如下图所示,Reactor模式运行的顺序如下:

应用程序调用Initiation_Dispatcher注册一个Event_Handler,并给出对应的。Handler及事件类型。

注册完所有的Event_Handler后启动监听事件。

当有事件发生时,Synchronous Event Demultiplexer通知Initiation Dispatcher。

Initiation Dispatcher触发与Handler对应的Event Handler。





Reactor设计模式相关产品

Node.js
libev
libevent
boot.asio
ace

参考资料

Proactor和Reactor模式_继续并发系统设计的扫盲

QuickTime Streaming Server Modules Programming Guide。

An Object Behavioral Pattern for Demultiplexing and Dispatching Handles
for Synchronous Events

libevent,跨平台的Reactor的实现,地址: http://monkey.org/~provos/libevent/

libev,同libevent类似,据说性能稍好,地址: http://software.schmorp.de/pkg/libev.html

node.js

Architecture of a Highly Scalable NIO-Based
Server
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: