《Unix网络编程》30章详细介绍了几种服务器设计范式。总结了其中的几种,记录一下;
多进程的做法:
1.每次创建一个新的请求,fork一个子进程,处理该连接的数据传输。
2.预先派生一定数量的子进程,每个子进程都调用accept接收连接请求。当一个请求到来之后会触发所有进程的accept,但是只有最先的子进程会处理该请求。这就是所说的“惊群”。
3.为了解决“惊群”,在各个子进程的accept前后都用线程的互斥锁来做同步保护。一般来说互斥锁用于线程之间的同步,但是也可用作多个进程之间同步,具体用法参考链接。http://blog.csdn.net/dlutbrucezhang/article/details/8834387
和多进程的做法相对应,只是线程更轻,理论上开销更小。
1.每次创建一个新的请求,fork一个子线程,处理该连接的数据传输。
2.预先派生一定数量的子线程,每个子进程都调用accept接收连接请求。当一个请求到来之后会触发所有线程的accept,但是只有最先的子线程会处理该请求。这就是所说的“惊群”。
3.为了解决“惊群”,在各个子线程的accept前后都用线程的互斥锁来做同步保护。
一般来说,第一种方法可以对付一般的连接请求量,比如我研究生科研做的每次就我一个人访问的,或者我和老师同时访问的一个小型服务器,这样的足够了。第三种就比较好了,响应非常迅速,时间上差不多比第一种快了十倍以上,而且第三种编码也比较简单。
这本书上还提供了对文件加锁,主线程accept传递给子线程等等办法,编码都比较麻烦,效果也一般。
另外之前我的博客http://www.cnblogs.com/shenshenlei/p/5535853.html 中提到epoll 的问题。其实那个源代码中派生几个线程,每个线程都是epoll_wait,这个编码和在多线程中accept非常相似,但是也没有用到互斥量做线程安全。参考链接https://rocfang.gitbooks.io/dev-notes/content/acceptyu_epoll_liang_qun.html给出了关于该问题的一些描述,“accept 已经不存在惊群问题,但 epoll 上还是存在惊群问题。即,如果多个进程/线程阻塞在监听同一个 listening socket fd 的 epoll_wait 上,当有一个新的连接到来时,所有的进程都会被唤醒。”如作者所说,关于此问题nginx给出的解决方案也是加一个互斥锁。
(2016-6-2 15:21:01再次更新)
在Linux2.6内核中已经解决了accept导致的惊群问题。
在Linux3.9内核中提出了要解决epoll_wait惊群问题,而且在内核4.5中,正式得到解决。在这个版本中添加了一个EPOLLEXCLUSIVE 标记。内核代码根据此标记为会有选择性的唤醒一个阻塞在epoll_wait上的进程(线程)。但显然这个版本距离大规模的使用还有很遥远的距离。参考链接:https://github.com/torvalds/linux/commit/df0108c5da561c66c333bb46bfe3c1fc65905898
参考链接:
http://blog.csdn.net/dlutbrucezhang/article/details/8834387
http://www.cnblogs.com/shenshenlei/p/5535853.html
https://rocfang.gitbooks.io/dev-notes/content/acceptyu_epoll_liang_qun.html