Web服务器和客户端是一对多关系,Web服务器必须有能力为多个客户端提供服务。完成并处理请求工作有三总方式可供选择:多进程方式,多线程方式 和 异步方式!
多进程方式
多进程是指,服务器每当接收到一个客户端时,就由服务器主进程生成一个子进程出来和该客户端建立连接进行交互,直到连接断开,该进程就结束了。
多进程方式的优点:
- 设计和实现相对简单,各个子进程之间相互独立,处理客户端请求的过程彼此不受到干扰,并且当一个子进程产生问题时,不容易将影响蔓延到其他进程中,这保证了提供服务的稳定性。当子进程退出时,期占用资源会被操作系统回收,也不会留下任何垃圾。
多进程方式的缺点:
- 操作系统生成一个子进程需要进行内存复制等操作,在资源和时间上会产生一定的额外开销,因此,如果 Web 服务器接收大量并发请求,就会对系统资源造成压力,导致系统性能下降。
预生成进程
预生成进程 是 多进程方式 的改进版!
预生成进程就是将生成子进程的时机提前,在客户端请求还没有到来之前就预先生成好,当请求到来时,主进程分配一个子进程和该客户端进行交互,交互完成之后,该进程也不结束,而被主进程管理起来等待下一个客户端请求的到来。改进的多进程方式子一定程度上缓解了大量并发请求情况下 Web 服务器对系统资源造成的压力。但是不能从根本上解决这个问题!
多线程方式
多线程方式 和 多进程方式 类似。
当服务器每当接收到一个客户端时,会由服务器主进程派生一个线程出来和该客户端进行交互。
由于操作系统产生一个线程的开销远远小于一个进程的开销,所以多线程方式在很大程度上减轻了Web服务器对系统资源的要求。但是线程管理方面,该方式有一定的不足。多个线程位于同一个进程内,可以访问同样的内存空间,彼此之间相互影响。同时,在开发过程中不可避免地要由开发者自己对内存进行管理,其增加了出错的风险。
异步方式
在之前有四个概念:
同步、异步 和 堵塞、非堵塞
同步、异步 用来描述通信模式的概念!
堵塞、非堵塞 用来描述进程处理调用的概念!
同步:是指发送方发送请求后,需要等待接收方接收到发回的响应后,才能继续下一个请求。
异步:和同步机制相反!在异步机制中,发送方发出一个请求后,不等待接收方响应这个请求,就继续发送一个请求。
在同步机制中,所有的请求在服务端得到同步,发送方和接收方对请求的处理步骤一致。
在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完成后通知发送方。
堵塞和非堵塞模式,在网络通信中,主要指的是网络套接字Socket的堵塞和非堵塞方式,而Socket的实质就是IO操作。Socket的堵塞调用方式为,调用结果返回之前,当前线程从运行状态被挂起,一直等到调用结果返回之后,才进入就绪状态,获取CPU后继续执行;Socket的非堵塞调用方式和堵塞方式相反,在非堵塞方式中,如果调用结果不能马上返回,当前线程也不会被挂起,而是立即执行下一个调用。
同步、异步 和 堵塞、非堵塞 混合就产生了新的四个概念:
同步堵塞、异步堵塞、同步非堵塞、异步非堵塞
1.同步堵塞方式
发送方向接收方发送请求后,一直等待响应;接收方请求时进行的IO操作如果不能马上得到结果,就一直等到返回结果,才响应发送方,期间不能进行其他工作。比如,在超市排队付账时,客户(发送方)向收款员(接收方)付款(发送请求)后需要等待收款员找零,期间不能做其他的事情;而收款员要等待收款机返回结果(IO操作)后才能把零钱取出来交给客户(响应请求),期间也只能等待,不能做其他事情。这种方式实现简单,但是效率不高。
2.同步非堵塞方式
发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的IO操作如果不能马上得到结果,就立即返回,去做其他事情,但由于没有得到请求处理结果,不响应发送方,发送方一直等待。一直到IO操作完成后,接收方获得结果响应发送方后,接收方才进入下一次请求过程。在实际中不使用这种方式。
3.异步堵塞方式
发送方向接收方发送请求后,不用等待响应,可以接着进行其他工作;接收方处理请求时进行的IO操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不进行其它工作。这种方式在实际中也不使用!
4.异步非堵塞方式
发送方向接收方发送请求后,不用马上等待响应,可以继续其他工作;接收方处理请求时完成进行的IO操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情。当IO操作完成以后,将完成状态和结果通知接收方,接收方在响应发送方。继续使用在超市排队付账的例子。客户(发送方)向收款方(接收方)付款(发送请求)后在等待收款员找零钱的过程中,还可以做其他事,比如打电话、聊天等;而收款方在等待收款机处理交易(IO操作)的过程中可以帮助客户将商品打包,当收款机产生结果后,收款员给顾客结账(响应请求)。在四种方式中,这种方式是发送方和请求方通信效率最高的一种!
Nginx如何处理请求
Nginx服务器可以同时处理大量的并发请求。结合了多进程机制和异步机制对外提供服务。(异步机制使用的是异步非堵塞方式)
nginx启动后会产生一个主进程和多个工作进程。工作进程用于接收和处理客户端的请求。这类似与Apache使用的改进的多进程机制,预先生成多个工作进程,等待处理客户端请求。
nginx服务进程模型有两种:Single模型和Master-worker模型。Single模型为单进程方式,性能较差,一般不使用。Master-Worker模型被称为Master-Slave模型。充当Slave角色的是工作进程。
每个工作进程使用了异步非堵塞方式,可以处理多个客户端请求。当某个工作进程接收到客户端的请求后,调用IO进程处理,如果不能立即得到结果,就去处理其他的请求;而客户端在次期间也无需等待响应,可以去处理其他的事情;当I/O调用返回结果时,就会通知此工作进程;该进程得到通知,暂时挂起当前处理的事务,去响应客户端请求。
客户端请求数量增长,网络负载繁重时,Nginx服务器使用多进程机制能够保证不增长对系统资源的压力;同时使用异步非堵塞方式减少了工作进程在I/O调用上的堵塞延迟,保证了不降低对请求的处理能力。
Nginx事件处理机制
Nginx服务器的工作进程调用I/O后,就去进行其他工作了,当I/O调用返回后,会通知工作进程。这里有个问题,I/O调用是如何把自己的状态通知给工作进程的呢?
一般解决这个问题有两种方案:
1.让工作进程在进行其他工作的过程中隔一小段时间就去检查一下I/O的运行状态,如果完成,就去响应客户端,如果未完成,就继续正在进行的工作。
2.I/O调用在完成后能主动通知工作进程。
对于前者,虽然工作进程在I/O调用过程中没有等待,但是不断的检查仍然在时间和资源上导致了不小的开销,最理想的解决方案是第二种。
解决方案的第二种,一般用事件驱动模型来解决。select/poll/epoll/kqueue 等这样的系统库。它们提供了一种机制,让进程可以同时处理多个并发请求,不用关心I/O调用。I/O调用完全由事件驱动模型来管理,事件准备好之后就通知工作进程事件已经就绪。
网友评论