****简单分析nginx与apache的性能*****
"Apache就像Microsoft的Word,它有一百万个选项,但你只须要作六个。Nginx只作了这六件事,但他作的这六件事中有五件事比Apache快50倍"
常见的web服务器:nginx apache lighttpd tomcat jetty iis
web服务器的基本功能:基于REST架构风格,以统一资源描述符或者统一资源定位符做为沟通依据,经过HTTP为浏览器等客户端程序提供各类网络服务
tomcat和jetty面向java语言,先天就是重量级的WEB服务器,他的性能与nginx没有可比性,iis只能在windows上运行,windows做为服务器在稳定性上与其它一些性能上都不如类UNIX操做系统
apache有不少优势,如稳定,开源,跨平台等,可是它是一个重量级的,不支持高并发的web服务器
nginx和lighttpd同样,都是轻量级的,高性能的web服务器,欧美开发者更钟爱lighttpd,而国内的开发者更青睐nginx
###nginx###
nginx是一个跨平台的web服务器,能够运行在linux,freebsd,solaris,aix,macos,windows等操做系统上,而且它可使用当前操做系统特有的一些高效API来提升性能
nginx设计的目的是为了解决c10k问题
对于处理大规模并发链接,他支持linux上的epoll,windows无epoll,因此在windows下的nginx服务器会损失性能
对于linux,nginx支持其独有的sendfile系统调用,这个系统调用能够高效的把硬盘上的数据发送到网络上,不须要先把硬盘数据复制到用户态内存上再发送,这极大减小了内核态与用户态数据间的复制动做
nginx使用基于事件驱动的架构可以并发处理百万级别的TCP链接:
事件驱动架构:由一些事件发生源来产生事件,由一个或者多个事件收集器来收集,分发事件而后许多事件处理器会注册本身感兴趣的事件,同时会消费这些事件
nginx采用彻底的事件驱动架构来处理业务,这与传统的WEB服务器(如apache)是不一样的。对于传统的web服务器而言,采用的所谓事件驱动每每局限在TCP链接创建,关闭事件上,一个链接创建之后,在其关闭以前的全部操做都再也不是事件驱动,这时会退化成按序执行每一个操做的批处理模式,这样每一个请求在链接创建之后都始终占用着系统资源,知道链接关闭才会释放资源,整个事件消费进程只是在等待某个事件而已,形成了服务器资源的极大浪费,影响了系统能够处理的并发链接数,这种传统的web服务器每每会把一个进程或者线程做为事件消费者,当一个请求的事件被该进程处理时,直到这个请求处理结束时进程资源都将被这一个请求所占用,nginx不会使用进程或者线程做为事件消费者,事件消费者只能是某个模块,只有事件收集、分发器才有资格占用进程资源,他们会在分发某个事件时调用事件消费模块使用当前占用的进程资源。
传统web服务器与nginx间的重要区别:前者是每一个事件消费者独占一个进程资源,后者的事件消费者只是被事件分发者进程短时间调用而已。这种设计使的网络性能,用户感知的请求时延都获得了提高,每一个用户的请求所产生的事件会及时响应,整个服务器的网络吞吐量都会因为事件的及时响应而增大。但这也会带来一个重要的弊端,即每一个事件消费者都不能由阻塞行为,不然将会因为长时间占用事件分发者进程而致使其余事件得不到及时响应。尤为是每一个事件消费者不可让进程转变为休眠状态或等待状态
请求的多阶段异步处理:
请求的多阶段异步处理只能基于事件驱动架构实现,把一个请求的处理过程按照事件的触发方式划分为多个阶段,每一个事件均可以由事件收集、分发器来触发
异步处理和多阶段是相辅相成的,只有把请求分为多个阶段,才有所谓的异步处理。也就是说,当一个事件被分发到事件消费者中处理时,事件消费者处理完这个事件只至关于处理完1个请求的某个阶段,等待内核的通知才能够处理下一个阶段,即当下一次事件出现时,epoll等事件分发器将会获取到通知,在继续地调用事件消费者处理请求,这样每一个阶段中的事件消费者都不清楚本次完整的操做究竟何时才能完成,只能异步被动的等待下一个事件的通知
请求的多阶段异步处理配合事件驱动架构,将会极大的提升网络性能,同时使得每一个进程都能全力运转,不会或者尽可能少的出现进程休眠状态。
管理进程,多工做进程设计:
nginx采用一个master管理进程,多个worker工做进程的设计方式:
(1)利用多核系统的并发处理能力:nginx中的全部worker工做进程都是彻底平等的,这提升了网络性能,下降了请求的时延
(2)负载均衡:一个请求到来时更容易被分配到负载较轻的worker工做进程中处理,这下降了请求的时延,并在必定程度上提升网络性能
(3)管理进程会负责监控工做进程的状态,并负责管理其行为:管理进程不会占用多少系统资源,他只是用来启动,中止,监控或者使用其余行为来监控工做进程。首先,这提升了系统的可靠性,当工做进程出现问题时,管理进程能够启动新的工做进程来避免系统性能的降低,其次,管理进程支持nginx服务运行中的程序升级、配置项的修改等操做,这种设计使得动态可扩展性、动态定制性、动态可进化性较容易实现
热部署:master管理进程与worker工做进程的分离设计,使nginx可以提供在7*24小时不间断服务的前提下,升级nginx的可执行文件,也支持不中止服务就更新配置项,更换日志文件等功能
如何解决惊群问题:
只有打开了accept_mutex锁,才能够解决惊群问题
惊群问题:master进程开始监听web端口,fork出多个worker子进程,这些子进程开始同时监听同一个web端口。通常状况下,有多少cpu核心,就会配置多少个worker子进程,这样全部的worker子进程都在承担着web服务器的角色,在这种状况下,就能够利用每个cpu核心能够并发工做的特性,充分发挥多核的做用。假设这样一个情景:没有用户连入服务器,某一时刻刚好全部的worker子进程都休眠且等待新链接的系统调用(如epoll_wait),这时有一个用户向服务器发起了链接,内核在收到TCP的SYN包时,会激活全部的休眠worker子进程,固然,此时只有最早开始执行accpet的子进程能够成功创建新链接,而其余worker子进程都会accept失败,这些accept失败的子进程被内核唤醒是没必要要的,他们唤醒后的执行极可能是多余的,那么这一时刻他们占用的本不须要占用的系统资源,引起了没必要要的进程上下文切换,增长了系统开销
“惊群”是多个子进程同时监听同一个端口引发的,若是同一时刻只能由惟一一个worker子进程监听web端口,就不会发生惊群了,此时新链接事件只能唤醒惟一正在监听端口的worker进程
如何实现负载均衡:
只有打开了accept_mutex锁,才能够解决worker子进程间的负载均衡
支持mmap内存映射:
传统的web服务器,都是先将磁盘的内容县复制到内核缓存中,而后从内核缓存中复制一份到web服务器上,mmap就是让内核缓存与磁盘进行映射,web服务器直接复制就能够,不用将磁盘上的内容复制到内核缓存中
###apache
apache的三种工做模式:
(1)prefork:prefork模式算是很古老可是很是稳定的apache模式。apache在启动之初,就先fork一些子进程,而后等待请求进来。之因此这样作,是为了减小频繁建立和销毁进程的开销。每一个子进程只有一个线程,在一个时间点内,只能处理一个请求
优势:成熟稳定,兼容全部新老模块。同时,不须要担忧线程安全问题
缺点:一个进程相对占用更多的系统资源,消耗更多的内存。并且,他并不擅长处理高并发请求,在这种场景下,它会将请求放进队列里,一直等到有可用进程,请求才会被处理
(2)worker:和prefork模式相比,worker使用了多线程和多进程的混合模式,worker模式也一样会先预派生一些子进程,而后每一个子进程建立一些线程,同时包括一个监控线程,每一个请求过来会被分配到一个线程来服务。线程比进程更轻量,由于线程是经过共享父进程的内存空间,所以,内存的占用会减小一些,在高并发的场景下会比prefork有更多可用的线程,表现更优秀些
优势:占用更少的内存,高并发下表现优秀
缺点:必须考虑线程安全的问题,由于多个子线程是共享父进程的内存地址的。若是使用keep-alive长链接的方式,某个线程会一直被占据,也许中间几乎没有请求,须要一直等待到超时才会被释放。若是太多的线程,被这样占据,也会致使在高并发场景下的无服务线程可用
(3)event:它和worker模式很像,不一样的是它解决了keep-alive长链接的时候占用线程资源被浪费的问题,在event模式中,会有一些专门的线程来管理这些keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务器的线程,执行完毕后,又容许它释放,加强了在高并发场景下的请求处理
###epoll与select、poll的比较
假设有100万用户同时与一个进程保持着TCP链接,而每个时刻只有几十个或者几百个TCP链接是活跃的,也就是说,在每一时刻,进程只须要处理这100万链接中的一小部分链接。select和poll在每次收集事件时,都把这100万链接的套接字传给操做系统(这首先时用户态内存到内核态内存的大量复制),而由操做系统内核寻找这些链接上有没有未处理的事件,将是巨大的资源浪费,所以他们最多只能处理几千个并发链接。而epoll没有这样作,它在linux内核系统内申请了一个简易的文件系统,把原先的一个select或者poll调用分红了三个部分:调用epoll_create创建一个epoll对象、调用epoll_ctl向epoll对象添加这100万链接的套接字、调集epoll_wait收集发生事件的链接。这样,只须要在进程启动时创建一个epoll对象,并在须要的时候向他添加或者删除链接就能够了,所以,在实际收集事件时,epoll_wait的效率就会很是高,由于调用epoll_wait时并无向它传递这100万个链接,内核也不须要去遍历所有的链接
###cgi与fastcgi
cgi为每个请求产生一个惟一的进程,从一个请求到另外一个请求,内存和其余的信息将所有丢失
fastcgi使用了可以处理多个请求的持续过程,而不是针对每一个请求都产生新的进程
java