本文共 4583 字,大约阅读时间需要 15 分钟。
内核级功能,i/o prefork,两级结构,一个主进程开启若干个子进程,每个子进程来响应用户请求 worker是三级结构,主进程生成若干子进程,子进程生成多个线程,每个线程来响应用户请求 event是以worker类似,只不过增加了一个监控线程,来回收没有人访问的线程 apache再并发达到过万的时候,性能就受到影响 nginx可以达到3万的并发,为什么性能好,就是因为io模型来决定的 磁盘里的io 事实上,再对于网络中的应用来传输数据的时候,本质上也算是IO,因为在网络编程的时候,(http,python脚本程序,来实现socket通讯),网络通讯的时候也是经过读写机制的,只不过在经过网络的时候,是通过发到socket文件里去的,你发数据到远程主机,也是通过socket文件,对方也是通过socket来接收远程数据 网路也算是一种IO 一个远程用户请求一个html文件,请求到达网卡,根据tcp/ip分层,是应该吧mac层,ip报头,传输层,tcp报文头部到达应用层,就到达了nginx进程(工作在用户空间,但是工作在用户空间的进程是不能直接访问硬件的(要想把文件返回给用户,就需要由内核来完成这个工作,内核有权力去访问磁盘,磁盘把文件先返回给内核,有一个缓冲区, 再通过内核缓冲区把文件复制到应用程序nginx的缓冲区,然后封装报文头部,再发送过去 进行了4个过程 显然从磁盘上获取数据更久 内核空间,复制到nginx的内存空间,因为都是再内存里,所以速度是很快的 再快也比不上cpu,cpu是最快的,内存的数量再怎么着,也慢了一个数量级 nginx收到请求后,转发请求到内核,之后,不会傻等着,这就是涉及到IO模型的问题 同步(synchhronous/异步(asynchronous,阻塞/非阻塞 NFS,数据库,有同步异步,(是把数据立即写磁盘,还是等会再写 nginx的同步异步更关注的是消息通信机制 同步(synchhronous,调用者等待被调用者返回消息(调用者主动地去问被调用者是否完成,调用者消耗的精力更多一些) 异步(asynchronous,被调用者发个消息给调用者,表达事情已经做完了,对于调用者来讲更加省心一点 阻塞和非阻塞的关注点在于 ,调用者发任务给被调用者之后,到底是干等着,还是去忙别的事情 如果是阻塞,就是当调用者发送任务给被调用者之后,傻等着,什么时候被调用者做完之后才能去做别的事情 非阻塞,当调用者发送一个任务给被调用者,被调用者在没有完成任务之前,调用者仍然可以做别的事情, 可以不挂起,不傻等着 同步阻塞,比较消耗精力,只能把事情一件件做完 同步非阻塞,虽然没有阻塞,但是因为是同步机制,就并没有很好地利用这个条件 异步阻塞,洗完了通过你,阻塞(还在等着它),实际上什么也做不了,只是在那里等待浪费资源 异步非阻塞,效率最好,把任务下达了,就可以该做什么就去做什么了 在生产中用到的IO模型,真正用到的有5种 当用户发起请求,用户进程希望得到一个数据(因为用户进程没有权限,就要去系统调用,内核中的API接口,让内核来帮忙完成),这时候有两个阶段,第一阶段把数据从磁盘上把文件获取到内核空间,从内核复制到用户空间的缓存区中,这个就是对应画图的第4步 用户进程发送任务给内核之后,就一直在那里等待,同步阻塞,只能得到任务完成,最终得到数据 用户进程想要工作就需要把3,4步做完了,返回一个成功结果,这样用户进程得到数据了,就可以做别的事情去了,在这期间什么也做不了,是阻塞的状态 访问一个应用程序,应用程序本身的效率高还是内核效率高,让你感受更快一些,一般来讲用户是访问应用程序不是去访问内核,内核是为应用程序提供服务的,所以相对来讲,应用程序反应的响应速度更快 如果应用程序干的活多了,负担较重,自然对于用户的响应就慢了 如果内核做的事情多了,就变相减轻了应用程序干的活 同步,意味做完了任务不通知你,只能自己去看 当需要一个资源,就发送请求,到内核,内核帮你完成,但是完成不完成不知道,就一次次地去询问 数据从磁盘放到内核的时候认为完成(实际上没做完,我们得到数据是需要在用户进程的内存空间里发送到用户) 在磁盘复制到用户空间的过程中,用户是并不了解的(会不断地去询问是否完成) 询问一次就要消耗CPU就做了很多无用功 **之前的是每个进程发送请求给系统调用,跑到内核,内核去磁盘上读取数据 每个进程都是直接去访问系统,调用获取数据的,这样对内核来讲,是直接和进程打交道的 IO多路复用是专门找一个代理人叫select,(select相当于一个办事的大屏幕,当内核从磁盘拿到数据后,就通知某个用户进程,任务完成了) 在第一个阶段,用户的进程是阻塞在select这里的 后续的阶段,是用户进程需要等待数据从内核空间中复制到用户空间来完成的 实际上也是一种阻塞状态,只不过阻塞的位置和场景并不一样 select,利用IO多路复用,可以并发地响应用户请求,相当于专门的人接待客人,不用去和后面打交道 ** 虽然性能上没有提高,但是有专门的select模块,来并发响应用户请求 可以多路请求复用这个select(实际上并不是select才能实现这个功能,还有poll,也能使用系统调用功能,能够实现类似的功能 IO复用模型应用场景主要在如下环境中使用 一个文件需要占用一个描述符(比如交互输入和网络套接字) 最多的是下面这个场景,tcp服务器要处理多个套接字的时候,比如有多个用户发送请求,nginx还是apache都同时收到很多用户请求,这时候就会打开多个套接字请求来进行处理,有的是监听套接字,或者已经链接上了(监听状态和链接状态) 信号驱动IO模型,有些异步特性,调用者不需要主动去问被调用者,被调用者做完,主动通知你 内核从磁盘读取数据的时候,第三个过程,还没得到数据,进程就可以做点别的事情, 内核把数据准备好之后通知用户进程,接下来,第4个状态 内核数据复制到用户进程中,这个过程用户进程是处于等待的 所以有一部分实现了异步,有一部分实现了同步 用户发起请求,用户进程,告诉内核需要数据,内核从磁盘获取数据,从内核空间把数复制到用户空间,这个用户程序一直在持续运行,一直没有阻塞,一直在忙自己的,所有的工作交由内核做 用户程序发现很不操心,内核做的事情较多一点,进程做的时候越少,同时就能响应更多用户请求 5种IO模型的总结 1.同步一直在阻塞,什么时候内核把事情做完了,才能做其他的事情,同步阻塞模型 2.同步非阻塞模型,不是完全非阻塞,第三个简单不阻塞,但是同步,就需要不断地去询问是否完成 表明上不阻塞,其实还不如阻塞,第4阶段,什么时候把内核空间数据复制到用户进程空间,就算结束 3.IO复用模型,这两个阶段其实都是阻塞的,只不过对于前面的阶段,阻塞在select上面,把任务阻塞在select。其他进程不用直接联系内核(实际还是阻塞,无非是换个地方) 4.信号驱动模型,第三阶段不阻塞,可以做别的事情,相对来讲性能提高了,第4阶段阻塞,自己去吧内核空间数据复制到用户空间 5.最理想的异步模型, 越往左偏同步的,右边是异步 重点掌握同步,异步,阻塞,非阻塞 select,poll,epoll.kqueue,/dev/poll/iocp,都是和IO复用相关的 其中select是跨平台的,linux,windows也是支持的,用的 IO复用模型 poll是改进版的select(可以理解为select和poll是一个级别的,没有什么根本性变化) EPOll相对select和poll来讲有极大的提升,具用的是信号驱动IO模型的一些特性,性能就相对来讲是更好一点。 locp是windows实现的,用的是真正的异步模型 select,poll,epoll都可以面对多个用户并发请求,相当于一个代理人,手机很多 的用户请求过来,手机以后,它去帮你从内核到磁盘上得到数据,但是这个数据有没有准备好,是不一样的,select和poll用 的是遍历机制。select和poll相当于代理好多人的请求,有些用户数据准备好了,但是还有很多用户数据没有准备好,那就需要和进程用户打交道,并且告诉对方 (如何知道谁的进程准备好,select和poll是遍历的,就需要一个个去找,(比如用户询问,数据有没有好,你说等会,你需要去查,一个个去查,到最后结束告诉你结果,这样全表扫描,效率是偏低的)) epoll是异步的机制,就有信号驱动的一些特性,数据准备好后,会主动通知你去拿,相对来讲效率更高 select和poll 用户请求越多,遍历时间就越长 epol因为是回调机制,和你的请求个数是没有关系的 slect最大并发数是1000个,内核来决定的,poll和epoll是无上限的 变相描述了select和poll,epoll select最大并发1000,修改这个值只能重新编译内核 了 水平触发 跨平台使用 poll 只支持linux 无限制并发 这两个都属于同步IO epoll属于异步IO 支持水平触发和边缘触发 水平触发通知多次 边缘触发只通知一次 epoll支持MMAAP (内存映射) 数据在磁盘上存放,是以文件系统来组织的(有节点表,inode),数据和节点表是相分离的,通过节点表层层地去目录结构找到最终数据,相对效率不是很高 可以在磁盘上划一块空间,这个空间就是文件,把他映射到内存里,让它在内存中有一块一模一样的大小空间,需要一一对应,假设这个磁盘空间是16M,内存也是16M,每个字节也一一对应,将来访问数据的时候,就可以直接访问内存空间,这个内存空间是和磁盘一一对应的,这样就不要分析节点表,一层层下去找了,比如找第100个字节,就直接可以找到,不用通过inode层层去找 直接内存映射,写数据,因为是直接对应的关系, 之前修改index文件,需要现在内存中进行修改,改了之后再复制到磁盘里去 为什么nginx性能好,是因为nginx用 就是epoll的方式 而apache用的是select的方式,所以性能相对nginx要差一些 支持更多并发链接就是因为使用的是epoll,但是虽然号称,并发无限,但是官方最多指出也是30000的并发 即使用epoll,也不可能去消耗所有的资源 每个链接过来是要消耗系统资源的,消耗的时候,实际上也有一定的极限 还有一个端口号消耗的问题, 有时候会承担一个代理服务器 的角色 nginx不仅可以做web服务器,还可以做为反向代理 lvs是工作在内核级,nginx是应用层的,代替远程客户端来访问后端服务器的,既然是客户端,同时并发请求连接到服务器,太多的用户就要打开太多 的端口号,是客户端就需要消耗端口号,tcp端口号最多才65535,有一些还是给服务预留的,真正的端口最多也就3万到6万 多 nginx服务器并发访问达到2,3万已经达到j极限了 如果并发实在太大,就需要用到lvs,多台nginx nginx也开始有商业化了,社区版和商业版 ,org组织,.com商业公司 淘宝的Tengine,就是用nginx做的二次开发 openresty转载地址:http://sfkgn.baihongyu.com/