1. 循环式/迭代式服务器
1)短连接(如果是长连接则需要在read与write之间增加一个循环,那样的话外层循环无法退出,接收不到其它连接请求,即只能服务一个客户端);
2)单线程,无法充分利用多核CPU;
3)不适合执行时间较长的服务(encode->compute->decode执行时间过长会影响其他客户端连接的响应速度)。
2. 并发式(concurrent)服务器
1)长连接;
2)one connection per process(主进程每次fork 后要关闭connfd,子进程要关闭listenfd),one connection per thread(线程间共享文件描述符,因此不用也不能关闭socket,否则会影响主线程的监听和子线程与客户端之间的通信);
3)适合执行时间较长的服务。
3. pre-fork or pre-threaded(UNP chapter27)
1)预先创建进程/线程;
2)可以提高连接的响应速度;
3)当多个子进程阻塞于accept时,若有一个客户端连接请求到来,则多个子进程都会被触发,但只有一个accept有成功返回,这种现象称为“惊群”。
4. 反应式服务器(reactor模式)
1)select/poll/epoll;
2)并发处理多个请求,实际上是在一个线程中完成的,无法充分利用多核CPU(单线程轮询);
3)不适合执行时间较长的服务(为了让客户端感觉是在“并发”处理而不是“循环”处理,每个请求必须在相对较短时间内执行)。
5. reactor + thread per request(过渡方案)
6. reactor + worker thread(过渡方案)
每个连接都在一个工作线程中完成,能充分利用多核CPU。
7. reactor + threadpool(能适应密集计算)
第五、第六种方法的改进。
muduo库的/example/suduku/中有一个reactor + threadpool的例子,因为数独求解是计算密集型任务。
在实践中,为了使reactor能快速返回事件循环中去响应请求,经常将读到的数据put到一个环形内存队列(一般内存or共享内存),而threadpool的线程则从这个环形内存队列中读取数据进行计算。
8. multiple reactors(能适应更大的突发I/O请求)
1)reactors in threads(one loop per thread) Memcached就是这种模型,一个主线程,多个工作线程,主线程reactor负责接收客户端连接,每个线程有各自的reactor负责执行任务队列中的任务。
2)reactors in processes;
3)round robin(轮叫);
4)一般来说一个subReactor适用于一个千兆网口。
9. multiple reactors + threadpoll(one loop per thread + threadpool) (能适应突发I/O与密集计算)
Muduo库主推的一种并发服务器模型!!!
多个subReactor共享一个线程池。
10. proactor服务器(proactor模式,基于异步I/O)
1)理论上proactor比reactor效率要高一些;
2)异步I/O能够让I/O操作与计算重叠,充分利用DMA特性;
3)Linux异步I/O:
glibc aio (aio_*),有bug;
kernel native aio (io_*),也不完美。目前仅支持O_DIRECT方式来对磁盘读写,跳过系统缓存。要自己实现缓存,难度不小。
4)boost asio实现的proactor,实际上不是真正意义上的异步I/O,底层是用epoll来实现的,模拟异步I/O。
多种并发服务器之间的对比