万字多图,搞懂Nginx高性能网络工

北京主治白癜风医院 https://wapyyk.39.net/bj/zhuanke/89ac7.html

来源丨经授权转自开发内功修炼(ID:kfngxl)

作者丨张彦飞allen

大家好,我是飞哥!

在单进程的网络编程模型中。所有的网络相关的动作都是在一个进程里完成的,如监听socket的创建,bind、listen。再比如epoll的创建、要监听事件的添加,以及epoll_wait等待时间发生。这些统统都是在一个进程里搞定。

一个客户端和使用了epoll的服务端的交互过程如下图所示。

以下是其大概的代码示例(没耐心看的同学可以先)。

intmain(){//监听lfd=socket(AF_INET,SOCK_STREAM,0);bind(lfd,...)listen(lfd,...);//创建epoll对象,并把listensocket的事件管理起来efd=epoll_create(...);epoll_ctl(efd,EPOLL_CTL_ADD,lfd,...);//事件循环for(;;){size_tnready=epoll_wait(efd,ep,...);for(inti=0;inready;++i){if(ep[i].data.fd==lfd){//lfd上发生事件表示都连接到达,accept接收它fd=accept(listenfd,...);epoll_ctl(efd,EPOLL_CTL_ADD,fd,...);}else{//其它socket发生的事件都是读写请求、或者关闭连接...}}}}

在单进程模型中,不管有多少的连接,是几万还是几十万,服务器都是通过epoll来监控这些连接socket上的可读和可写事件。当某个socket上有数据发生的时候,再以非阻塞的方式对socket进行读写操作。

事实上,Redis5.0及以前的版本中,它的网络部分去掉对handler的封装,去掉时间事件以后,代码基本和上述demo非常接近。而且因为Redis的业务特点只需要内存IO,且CPU计算少,所以可以达到数万的QPS。

但是单进程的问题也是显而易见的,没有办法充分发挥多核的优势。所以目前业界绝大部分的后端服务还都是需要基于多进程的方式来进行开发的。到了多进程的时候,更复杂的问题多进程之间的配合和协作问题就产生了。比如

哪个进程执行监听listen,以及accept接收新连接?哪个进程负责发现用户连接上的读写事件?当有用户请求到达的时候,如何均匀地将请求分散到不同的进程中?需不需要单独搞一部分进程执行计算工作...

事实上,以上这些问题并没有标准答案。各大应用或者网络框架都有自己不同的实现方式。为此业界还专门总结出了两类网络设计模式-Reactor和Proactor。不过今天我不想讨论这种抽象模式,而是想带大家看一个具体的Case-Nginx是如何在多进程下使用epoll的。

一、NginxMaster进程初始化

在Nginx中,将进程分成了两类。一类是Master进程,一类是Worker进程。

在Master进程中,主要的任务是负责启动整个程序、读取配置文件、监听和处理各种信号,并对Worker进程进行统筹管理。

不过今天我们要查看的重点问题是看网络。在Master进程中,和网络相关的操作非常简单就是创建了socket并对其进行bind和监听。

具体细节我们来看Main函数。

//file:src/core/nginx.cintngx_cdeclmain(intargc,char*const*argv){ngx_cycle_t*cycle,init_cycle;//1.1ngx_init_cycle中开启监听cycle=ngx_init_cycle(init_cycle);//1.2启动主进程循环ngx_master_process_cycle(cycle);}

在Nginx中,ngx_cycle_t是非常核心的一个结构体。这个结构体存储了很多东西,也贯穿了好多的函数。其中对端口的bind和listen就是在它执行时完成的。

ngx_master_process_cycle是Master进程的主事件循环。它先是根据配置启动指定数量的Worker进程,然后就开始


转载请注明:http://www.jiaju1314.com/zyyd/zyyd/16056.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了