http://blog.csdn.net/jnu_simba/article/details/14141245
https://www.zhihu.com/people/swxlion
http://my.oschina.net/zhangjie830621/blog/355632
http://my.oschina.net/zhangjie830621/blog/355326
http://ifeve.com/netty-reactor-4/
常见并发服务器方案
1、循环式/迭代式( iterative )服务器
无法充分利用多核CPU,不适合执行时间较长的服务
2、并发式(concurrent)服务器
one connection per process/one connection per thread
适合执行时间比较长的服务
3、prefork or pre threaded(UNP2e 第27章)
4、反应式( reactive )服务器 (reactor模式)
并发处理多个请求,实际上是在一个线程中完成。无法充分利用多核CPU
不适合执行时间比较长的服务,所以为了让客户感觉是在“并发”处理而不是“循环”处理,每个请求必须在相对较短时间内执行。
5、reactor + thread per request(过渡方案)
6、reactor + worker thread(过渡方案)
7、reactor + thread pool(能适应密集计算)
8、multiple reactors(能适应更大的突发I/O)
reactors in threads(one loop per thread)
reactors in processes
9、multiple reactors + thread pool(one loop per thread + threadpool)(突发I/O与密集计算)
10、proactor服务器(proactor模式,基于异步I/O)
理论上proactor比reactor效率要高一些
异步I/O能够让I/O操作与计算重叠。充分利用DMA特性。
Linux异步IO
glibc aio(aio_*),有bug
kernel native aio(io_*),也不完美。目前仅支持 O_DIRECT 方式来对磁盘读写,跳过系统缓存。要自已实现缓存,难度不小。
boost asio实现的proactor,实际上不是真正意义上的异步I/O,底层是用epoll来实现的,模拟异步I/O的。
iterative服务器
iterative 只能使用短连接,只有一个 线程,如果使用长连接,那么其他请求就无法得到响应!
处理完一个连接,然后关闭连接。
这种服务器有很多缺陷 :
-
单线程,不能充分利用多核cpu
-
因为是短链接,有可能上一次断开的连接就是本次的连接,这样效率明显下降
-
不能并发处理
无法充分利用多核CPU,不适合执行时间较长的服务,即适用于短连接。如果是长连接则需要在read/write之间循环,那么只能服务一个客户端。
one connection per process/one connection per thread
这种服务器,因为是多线程或者多进程的,所以能并发处理请求。
注:如果是多进程,记得关闭监听套接字,因为子进程会继承套接字。
如果是多线程,就不用关闭监听套接字了,因为线程没有继承打开的套接字。
并发处理多个请求,实际上是在一个线程中完成。无法充分利用多核CPU
不适合执行时间比较长的服务,所以为了让客户感觉是在“并发”处理而不是“循环”处理,每个请求必须在相对较短时间内执行。
5、reactor + thread per request(过渡方案)
6、reactor + worker thread(过渡方案)
reactors in processes
理论上proactor比reactor效率要高一些异步I/O能够让I/O操作与计算重叠。充分利用DMA特性。Linux异步IO
glibc aio(aio_*),有bugkernel native aio(io_*),也不完美。目前仅支持 O_DIRECT 方式来对磁盘读写,跳过系统缓存。要自已实现缓存,难度不小。
boost asio实现的proactor,实际上不是真正意义上的异步I/O,底层是用epoll来实现的,模拟异步I/O的。
假如单纯采用 thread per connection 的模型,那么并发连接数大约350,这远远低于基于事件的单线程程序所能轻松达到的并发连接数(几千上万,甚至几万)。所谓“基于事件”,指的是用 IO multiplexing event loop 的编程模型,又称 Reactor 模式。
如果要在一个8核的机器上压缩100个1G的文本文件,每个core的处理能力为200MB/s,那么“每次起8个进程,一个进程压缩一个文件”与“只启动一个进程(8个线程并发压缩一个文件)”,这两种方式总耗时相当,但是第二种方式能较快的拿到第一个压缩完的文件。
用一个全局的mutex保护IO每个线程单独写一个日志文件
后者有可能让业务线程阻塞在写磁盘操作上。(磁盘IO时间比较长)
解决办法:用一个logging线程负责收集日志消息,并写入日志文件,其他业务线程只管往这个“日志线程”发送日志消息(如通过BlockingQueue提供接口),这称为“异步日志”,也是一个经典的生产者消费者模型。
假设C=8,P=1.0,线程池的任务完全密集计算,只要8个活动线程就能让CPU饱和假设C=8,P=0.5,线程池的任务有一半是计算,一半是IO,那么T=16,也就是16个“50%繁忙的线程”能让8个CPU忙个不停。
计算线程
第三方库所用线程,如logging,又比如database
浙公网安备 33010602011771号