Loading

IO模型

网上的总结

 一、多进程单线程+堵塞+同步IO。 每个IO都是堵塞的,上一个IO未处理完或未就绪,整个进程会被阻塞在次,因此要想并发的处理多个请求,就必须为每个请求fork一个进程。由于是堵塞IO,每个进程同时只能处理一个请求。这种是最简单的模型。
 二、多进程多线程+堵塞+同步IO 。和第一种的区别在于每个进程又可以new多个线程来处理每个请求。
 三、多进程单线程+多路复用(select)+同步IO。apache的prefork是这种的代表。预先fork几个进程,但是每个进程可以使用多路复用的IO,同时处理多个请求。
 四、多进程多线程+多路复用(select)+同步IO。apache的worker模式是这种的代表。预先fork几个进程,每个进程又可以为每个请求new一个线程。
 五、多进程单线程+多路复用(epool)+基于事件异步IO。nginx的模型。 预先fork几个进程,采用epool的基于事件的多路复用IO模型,每个进程可以同时处理多个请求。
 六、单进程单线程+非堵塞+异步IO。node.js宣称自己的服务器是这种模型。只有一个进程、一个线程,整个请求都是非堵塞的,且每个IO都是异步的。
prefork:多进程,每个请求用一个进程响应,这个过程会用到select机制来通知。
prefork本身并没有使用到线程,另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,


worker:多线程,一个进程可以生成多个线程,每个线程响应一个请求,但通知机制还是select不过可以接受更多的请求。
支持多线程和多进程混合模型的MPM。由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。但是,worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性

event:基于异步I/O模型,一个进程或线程,每个进程或线程响应多个用户请求,它是基于事件驱动(也就是epoll机制)实现的
一个进程响应多个用户请求,利用callback机制,让套接字复用,请求过来后进程并不处理请求,而是直接交由其他机制来处理,通过epoll机制来通知请求是否完成;在这个过程中,进程本身一直处于空闲状态,可以一直接收用户请求。可以实现一个进程程响应多个用户请求。支持持海量并发连接数,消耗更少的资源。

  如何提高web服务器的并发处理

基于线程,即一个进程生成多个线程,每个线程响应用户的每个请求。
基于事件的模型,一个进程处理多个请求,并且通过epoll机制来通知用户请求完成。
基于磁盘的AIO(异步I/O)
支持mmap内存映射,mmap传统的web服务器,进行页面输入时,都是将磁盘的页面先输入到内核缓存中,再由内核缓存中复制一份到web服务器上,mmap机制就是让内核缓存与磁盘进行映射,web服务器,直接复制页面内容即可。不需要先把磁盘的上的页面先输入到内核缓存去
Nginx 支持以上所有特性
##在nginx中,连接请求由为数不多的几个仅包含一个线程的进程worker以高效的回环(run-loop)机制进行处理,而每个worker可以并行处理数千个的并发连接及请求

  关于nginx

Nginx会按需同时运行多个进程:一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等。所有进程均是仅含有一个线程,并主要通过“共享内存”的机制实现进程间通信。主进程以root用户身份运行,而worker、cache loader和cache manager均应以非特权用户身份运行


主进程主要完成如下工作:

读取并验正配置信息;
创建、绑定及关闭套接字;
启动、终止及维护worker进程的个数;
无须中止服务而重新配置工作特性;
控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本;
重新打开日志文件;
编译嵌入式perl脚本;
worker进程主要完成的任务包括:
接收、传入并处理来自客户端的连接;
提供反向代理及过滤功能;
nginx任何能完成的其它任务;

 同步异步与阻塞

同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致

异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列

消息通知:
当一个同步调用发出后,调用者要一直等待返回消息(结果)通知后,才能进行后续的执行;当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者




'阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关'。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的
阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回

1,对于同步调用来说,很多时候当前线程可能还是激活的,只是从逻辑上当前函数没有返回而已,此时,这个线程可能也会处理其他的消息
(a) 如果这个线程在等待当前函数返回时,仍在执行其他消息处理,那这种情况就叫做同步非阻塞;
(b) 如果这个线程在等待当前函数返回时,没有执行其他消息处理,而是处于挂起等待状态,那这种情况就叫做同步阻塞;

同步的实现方式会有两种:同步阻塞、同步非阻塞;同理,异步也会有两种实现:异步阻塞、异步非阻塞;
2,对于阻塞调用来说,则当前线程就会被挂起等待当前函数返回

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。虽然表面上看非阻塞的方式可以明显的提高CPU的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的CPU执行时间能不能补偿系统的切换成本需要好好评估


总结

1.同步与异步是站在消息通知机制角度来说的(同步可能需要时刻去关心询问线程处理结果,异步注册了回调机制,无需关心)
2.阻塞和非阻塞是站在线程等待调用结果的线程状态这个角度来说的,阻塞则是线程挂起等待调用结果返回;非阻塞是在等待结果的过程中,线程任然是活动状态,可能处理其他的任务罢了

  重点:

所有I/O多路复用操作都是同步的,涵盖select/poll。
阻塞/非阻塞是相对于同步I/O来说的,与异步I/O无关。
select/poll/epoll本身是同步的,可以阻塞也可以不阻塞。

apache 工作模型

prefork


预派生模式,有一个主控制进程,然后生成多个子进程,'使用select模型',最大并发1024,每个子进程有一个独立
的线程响应用户请求,相对比较占用内存,但是比较稳定,可以设置最大和最小进程数,是最古老的一种模式,也
是最稳定的模式,适用于访问量不是很大的场景。 优点:稳定 缺点:慢,占用资源,1024个进程不适用于高并发
场景

worker


一种多进程和多线程混合的模型,有一个控制进程,启动多个子进程,每个子进程里面包含固定的线程,使用线程
程来处理请求,当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,由于其使
用了线程处理请求,因此可以承受更高的并发
#优点:相比prefork 占用的内存较少,可以同时处理更多的请求
缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释
放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用

 

event


属于事件驱动模型(epoll),每个进程响应多个请求,'它解决了keepalive场景下,长期被占用的线程的资源浪费问题'(某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)。event MPM中,会有一个专门的线程来管理这些keepalive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力。
优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:没有线程安全控制



 

posted @ 2019-06-03 08:48  Lust4Life  阅读(171)  评论(0编辑  收藏  举报