`

为什么Nginx的性能要比Apache高很多?

阅读更多

为什么Nginx的性能要比Apache高很多? 这得益于Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。

目前Linux下能够承受高并发访问的Squid、Memcached都采用的是epoll网络I/O模型。

处理大量的连接的读写,Apache所采用的select网络I/O模型非常低效。

下面用一个比喻来解析Apache采用的select模型和Nginx采用的epoll模型进行之间的区别:

假设你在大学读书,住的宿舍楼有很多间房间,你的朋友要来找你。

select版宿管大妈就会带着你的朋友挨个房间去找,直到找到你为止。

而epoll版宿管大妈会先记下每位同学的房间号,

你的朋友来时,只需告诉你的朋友你住在哪个房间即可,不用亲自带着你的朋友满大楼找人。

如果来了10000个人,都要找自己住这栋楼的同学时,select版和epoll版宿管大妈,谁的效率更高,不言自明。

同理,在高并发服务器中,轮询I/O是最耗时间的操作之一,select和epoll的性能谁的性能更高,同样十分明了。

epoll - I/O event notification facility

在linux的网络编程中,很长的时间都在使用select来做事件触发。

在linux新的内核中,有了一种替换它的机制,就是epoll。

相比于select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。

因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。

并且,在linux/posix_types.h头文件有这样的声明:

  • #define __FD_SETSIZE    1024

表示select最多同时监听1024个fd,当然,可以通过修改头文件再重编译内核来扩大这个数目,但这似乎并不治本。

epoll的接口非常简单,一共就三个函数:

1. int epoll_create(int size);

创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。

这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。

需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,

是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,

而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值,

第二个参数表示动作,用三个宏来表示:

EPOLL_CTL_ADD:注册新的fd到epfd中;

EPOLL_CTL_MOD:修改已经注册的fd的监听事件;

EPOLL_CTL_DEL:从epfd中删除一个fd;

第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:

  • typedef union epoll_data {
  • void *ptr;
  • int fd;
  • __uint32_t u32;
  • __uint64_t u64;
  • } epoll_data_t;
  • struct epoll_event {
  • __uint32_t events; /* Epoll events */
  • epoll_data_t data; /* User data variable */
  • };

events可以是以下几个宏的集合:

EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);

EPOLLOUT:表示对应的文件描述符可以写;

EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);

EPOLLERR:表示对应的文件描述符发生错误;

EPOLLHUP:表示对应的文件描述符被挂断;

EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,

如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

等待事件的产生,类似于select()调用。

参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。

该函数返回需要处理的事件数目,如返回0表示已超时。

4、关于ET、LT两种工作模式:

可以得出这样的结论:

ET模式仅当状态发生变化的时候才获得通知,这里所谓的状态的变化并不包括缓冲区中还有未处理的数据,也就是说,如果要采用ET模式,需要一直read/write直到出错为止,很多人反映为什么采用ET模式只接收了一部分数据就再也得不到通知了,大多因为这样;而LT模式是只要有数据没有处理就会一直通知下去的。

那么究竟如何来使用epoll呢?其实非常简单。

通过在包含一个头文件#include <sys/epoll.h> 以及几个简单的API将可以大大的提高你的网络服务器的支持人数。

首先通过create_epoll(int maxfds)来创建一个epoll的句柄,其中maxfds为你epoll所支持的最大句柄数。

这个函数会返回一个新的epoll句柄,之后的所有操作将通过这个句柄来进行操作。

在用完之后,记得用close()来关闭这个创建出来的epoll句柄。

<iframe id="iframe1104309_0" style="display: block; border-width: 0px; border-style: initial; vertical-align: bottom; margin: 0px;" src="http://pos.baidu.com/qchm?sz=200x200&amp;rtbid=1971540&amp;rdid=9223372032564593756&amp;dc=2&amp;di=1104309&amp;dri=0&amp;dis=0&amp;dai=6&amp;ps=0x0&amp;dcb=BAIDU_SSP_define&amp;dtm=BAIDU_DUP_SETJSONADSLOT&amp;dvi=0.0&amp;dci=-1&amp;dpt=none&amp;tsr=0&amp;tpr=1460164447593&amp;ti=%E4%B8%BA%E4%BB%80%E4%B9%88Nginx%E7%9A%84%E6%80%A7%E8%83%BD%E8%A6%81%E6%AF%94Apache%E9%AB%98%E5%BE%88%E5%A4%9A%EF%BC%9F%20-%20%E7%AB%99%E9%95%BF%E4%B9%8B%E5%AE%B6&amp;ari=1&amp;dbv=2&amp;drs=3&amp;pcs=1903x978&amp;pss=1903x7582&amp;cfv=0&amp;cpl=4&amp;chi=5&amp;cce=true&amp;cec=UTF-8&amp;tlm=1460164447&amp;ltu=http%3A%2F%2Fwww.chinaz.com%2Fprogram%2F2015%2F0424%2F401376.shtml&amp;ltr=http%3A%2F%2Fwww.chinaz.com%2Fprogram%2F2015%2F0506%2F403868.shtml&amp;ecd=1&amp;psr=1920x1080&amp;par=1920x1040&amp;pis=-1x-1&amp;ccd=24&amp;cja=false&amp;cmi=6&amp;col=zh-CN&amp;cdo=-1&amp;tcn=1460164448&amp;qn=667380d971960ac0&amp;dpv=da38a5e8f76e0602&amp;tt=1460164447529.319.387.390" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" align="center,center" width="200" height="200"></iframe>

之后在你的网络主循环里面,每一帧的调用epoll_wait(int epfd, epoll_event events, int max events, int timeout)来查询所有的网络接口,看哪一个可以读,哪一个可以写了。基本的语法为:

  • nfds = epoll_wait(kdpfd, events, maxevents, -1);

其中kdpfd为用epoll_create创建之后的句柄,events是一个epoll_event*的指针,当epoll_wait这个函数操作成功之后,epoll_events里面将储存所有的读写事件。

max_events是当前需要监听的所有socket句柄数。最后一个timeout是 epoll_wait的超时,为0的时候表示马上返回,为-1的时候表示一直等下去,直到有事件范围,为任意正整数的时候表示等这么长的时间,如果一直没有事件,则范围。一般如果网络主循环是单独的线程的话,可以用-1来等,这样可以保证一些效率,如果是和主逻辑在同一个线程的话,则可以用0来保证主循环的效率。

epoll_wait范围之后应该是一个循环,遍利所有的事件。

几乎所有的epoll程序都使用下面的框架:

 
  • for( ; ; )
        {
            nfds = epoll_wait(epfd,events,20,500);
            for(i=0;i<nfds;++i)
            {
                if(events[i].data.fd==listenfd) //有新的连接
                {
                    connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); //accept这个连接
                    ev.data.fd=connfd;
                    ev.events=EPOLLIN|EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); //将新的fd添加到epoll的监听队列中
                }
                else if( events[i].events&EPOLLIN ) //接收到数据,读socket
                {
                    n = read(sockfd, line, MAXLINE)) < 0    //读
                    ev.data.ptr = md;     //md为自定义类型,添加数据
                    ev.events=EPOLLOUT|EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);//修改标识符,等待下一个循环时发送数据,异步处理的精髓
                }
                else if(events[i].events&EPOLLOUT) //有数据待发送,写socket
                {
                    struct myepoll_data* md = (myepoll_data*)events[i].data.ptr;    //取数据
                    sockfd = md->fd;
                    send( sockfd, md->ptr, strlen((char*)md->ptr), 0 );        //发送数据
                    ev.data.fd=sockfd;
                    ev.events=EPOLLIN|EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); //修改标识符,等待下一个循环时接收数据
                }
                else
                {
                    //其他的处理
                }
            }
  •     }
分享到:
评论

相关推荐

    为什么Nginx的性能要比Apache高很多

    为什么Nginx的性能要比Apache高很多? 这得益于Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。 目前Linux下能够承受高并发访问的Squid、Memcached...

    实战Nginx:取代Apache的高性能Web服务器 PDF

    2. 轻量级:Nginx的资源占用很小,包括内存和CPU的占用都远低于Apache,这让Nginx可以在硬件资源有限的情况下提供更高的性能。 3. 高并发连接处理能力:Nginx可以处理数以万计的并发连接,这对于需要高吞吐量的网站...

    nginx-1.5.2 比apache快十倍

    刚看到nginx这个词,我很好奇它的读法(engine x),我的直译是“引擎x”,一般引“擎代”表了性能,而“x”大多出现是表示“xtras(额外的效果)”,那么整个词的意思就是类似“极致效果”,“额外性能”。...

    实战Nginx取代Apache的高性能Web服务器_文字版

    在很多场景下,Nginx被用作替代Apache服务器的选择,尤其是在高流量网站和需要负载均衡的环境中。本实战指南旨在探讨如何通过Nginx实现高性能的Web服务,以提升网站的响应速度和稳定性。 一、Nginx与Apache的性能...

    实战Nginx_取代Apache的高性能Web服务器

    ### 实战Nginx:取代Apache的高性能Web服务器 #### Nginx简介 Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,由俄罗斯的程序设计师Igor Sysoev所开发。自2004年公开发布以来,...

    实战Nginx取代Apache的高性能Web服务器

    在详细介绍Nginx取代Apache作为高性能Web服务器之前,先来阐述一下这两个Web服务器软件的基础知识以及它们之间的主要区别。Apache是目前使用最广泛的Web服务器软件之一,它是一个开源项目,从1995年就开始活跃在Web...

    [实战Nginx_取代Apache的高性能Web服务器].张宴.扫描版-new2

    2. **优化Nginx性能**:讲解了如何通过调整配置参数来提升Nginx的性能,如调整worker_processes数量、设置合适的keepalive_timeout值等。 3. **使用Nginx处理静态文件**:介绍如何让Nginx高效地处理静态文件请求,并...

    实战Nginx_取代Apache的高性能Web服务器_代码

    Nginx是一款高性能的Web服务器和反向代理服务器,它以其高效的并发处理能力、轻量级的进程模型以及丰富的模块支持而备受青睐。本实战教程将深入探讨如何使用Nginx取代Apache,以提升Web服务的性能。 1. **Nginx与...

    实战Nginx:取代Apache的高性能Web服务器 第一章

    ### 实战Nginx:取代Apache的高性能Web服务器 第一章 #### 1.1 常用的Web服务器简介 在Web服务器领域,有多种不同的服务器被广泛使用,包括但不限于Apache、Nginx和Lighttpd等。这些服务器各有特点,适用于不同...

    实战Nginx:取代Apache的高性能Web服务器

    总结,Nginx凭借其高性能、低资源消耗和强大的反向代理能力,成为了很多企业和开发者首选的Web服务器。通过深入了解其工作原理和配置,我们可以更好地利用Nginx提升网站的稳定性和响应速度,实现高效的服务交付。

    nginx-1.11.3+apache-tomcat-7.0.47搭建高性能负载均衡集群

    ### Nginx 1.11.3 + Apache Tomcat 7.0.47 高性能负载均衡集群搭建详解 #### 一、引言 随着互联网应用的不断发展,单一服务器已经难以满足高并发访问的需求。为了提高系统的可用性和响应速度,负载均衡技术成为了一...

    實戰Nginx-取代 Apache的高性能Web服務器

    《实戦Nginx-取代Apache的高性能Web服务器》一书主要探讨了Nginx这一高性能Web服务器在替代Apache时的优势与实践方法。Nginx以其高效的性能、优秀的并发处理能力和轻量级的特性,逐渐成为现代互联网环境中备受青睐的...

    实战Nginx 取代Apache的高性能Web服务器

    在很多场景下,Nginx被用作替代Apache的选择,尤其在高并发访问和大型网站部署中表现优秀。本资源旨在通过实战教程帮助读者理解和掌握如何使用Nginx构建高性能的Web服务。 一、Nginx的特点与优势 1. 高并发处理能力...

    实战nginx:取代Apache的高性能web服务器

    Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多. C. 作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last...

    高并发环境下 Apache 与 Nginx 的 IO 性能比较

    ### 高并发环境下 Apache 与 Nginx 的 IO 性能比较 随着互联网技术的快速发展,网络用户数量急剧增加,导致网络服务器面临高并发访问的压力。在这种情况下,提高服务器的I/O性能变得尤为重要。本文主要探讨了Linux...

    php apache/nginx

    这种架构被称为“Nginx+PHP-FPM”,它具有高性能和低内存占用的特点。 在Apache 2和多虚拟主机环境中,配置PHP旗标(php_flag)可能需要注意,因为它们在不同虚拟主机之间可能有不同的效果。对于Apache 2,如果在...

Global site tag (gtag.js) - Google Analytics