apache和nginx的性能分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了apache和nginx的性能分析相关的知识,希望对你有一定的参考价值。

****简单分析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使用了能够处理多个请求的持续过程,而不是针对每个请求都产生新的进程
 


以上是关于apache和nginx的性能分析的主要内容,如果未能解决你的问题,请参考以下文章

python分析apache和nginx日志文件输出访客ip列表的代码

PHP服务器Apache与Nginx的对比分析

nginx+php与apache+php性能对比

面试常问之——Nginx和Apache有什么区别?

Nginx/Apache日志分析脚本

apache和nginx的区别