web服务器从概念上来讲, 可以区分成两类, 一类是http服务器, 一类是应用服务器。
严格来讲, 叫http服务器不太正确, 因为他也可以是udp, 而http依赖于tcp。此类服务器就是nginx、apache、 node等, 在这里可以认为他们关心的是 HTTP 协议层面的传输和访问控制,所以在 Apache/Nginx 上你可以看到代理、负载均衡等功能。 访问静态资源, 转发动态请求等。
应用服务器, 即是tomcat, node等。 即支持开发语言的运行时,如tomcat => java, node => js, 简单来说就是能够动态的通过运行我们的业务代码对我们的请求进行处理。
node即可以作为http服务器,也可以作为应用服务器。
tomcat实际上也是用java编写的一个运行程序。
这里的讨论限制在linux的环境下。
io分为两个操作, 即
阻塞: 即io操作时, 在等待数据准备时, IO进程被阻塞了,必须等到数据准备完成后, 这个进程才被唤醒从而进行第二个操作即把数据从内核拷贝到进程中。
非阻塞: 即io操作时, 在等待数据准备时, IO进程通过不断的轮询数据是否准备后, 如果是则进行操作2。
同步: 即当发起io后, 必须等待数据从内核拷贝到进程中, 才继续后面的操作。(进程可以干别的事, 只是对于这个io动作的后系列, 必须等待数据拷贝完成后才可以继续)
异步: 即发起io后, 可以马上进行后面的操作, 当数据拷贝完成后, 会采用回调等方式来通知io进程。(同理于js中的异步操作, 发起http请求后, 可以注册一个函数来等待完成后调用,然后可以马上进行后面的代码块执行, 不必等待http)。
当数据准备完成时, 发起一个信号通知IO线程。
该模型在tcp中几乎无用, 问题在于该信号产生的过于频繁,并且它的出现并没有告诉我们发生了什么事情。下列条件均导致对于一个TCP套接字产生SIGIO信号
多路复用即 通过一个进程来监听n个socket, 当某个socket准备完成时, 进程会通知对应的用户进程。 用户进程进行read操作把数据从内核考到自己的进程中。I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。
select poll epoll
select,poll每次调用的时候都需要把fd从进程复制到内核, 并不断轮询所有fd集合直到设备就绪, 并且select的fd的个数有限制。
epoll通过拆分步骤完成(三个方法), 只在注册事件时把fd拷贝到内核(即一个fd只复制一次),同时遍历的时候会判断就绪列表是否为空, 只遍历就绪列表(一般来说,未就绪的比就绪的多得多), 并且epoll对于fd没有个数限制。
一些服务器or协议的IO实现。
Node的IO是异步非阻塞的, 对于磁盘io,他是通过线程池来实现的, 对于网络io,则是多路复用epoll。 具体参考之前写过的文章Node - 异步IO和事件循环.
Ng也是通过多路复用的epoll模型来实现的。
主进程:负责执行特权操作,如阅读配置文件、绑定套接字、创建 / 通知协调(Signalling)子进程。
工作进程:负责接收和处理连接请求,读取和写入磁盘,并与上游服务器通信。当 NGINX 处于活跃状态时,只有工作进程是忙碌的,工作进程采用单线程,并以非阻塞的方式处理多个并发连接。即一个工作进程对应多个套接字。
apache也是基于多路复用的模型, 只是在2.4.1之前使用的是select模式, 之后使用的是epoll。
tomcat是apache的扩展, 其IO拥有三种模式。 分别是bio,nio,apr。
bio, 即阻塞io, 每请求每线程, 效率最低。
nio, 非阻塞io, 底层的模型也是多路复用。
tomcat的nio有五类组件,分别是(参考文章tomcat nio,链接在最后)
大量的服务器开始使用多路复用的模式,主要在于bio在阻塞情况下虽然不会占用cpu,但是频繁的切换上下文浪费了大量资源,另外bio在并发量不高的情况下, 性能会优于nio。
知乎问题-tomcat 与 nginx,apache的区别是什么?
Linux IO模式及 select、poll、epoll详解
select、poll、epoll之间的区别总结[整理]
NGINX 如何实现高性能和可扩展性
Tomcat nio
深度解读Tomcat中的NIO模型