zoukankan      html  css  js  c++  java
  • Nginx源码研究二:NGINX的事件处理概论

      NGINX作为服务端的应用程序,在客户端发出数据后,服务端在做着这样一些处理,数据先会经过网卡,网卡会和操作系统做交互,经过操作系统的协议栈处理,再和不同的应用程序交互。

      在这里面涉及两个概念,一个是用户态,一个是内核态。应用程序通过系统调用函数进入内核空间,内核运行进行数据准备和数据拷贝等工作。对于NGINX来说,他是作为应用程序和操作系统交互,即是用户态和内核态的之间的交互,NGINX和内核交互方式有很多,例如open(),read() 等都是在和内核交互,而对于网络IO来说,我们知道linux下的网络IO主要有五种:

    一是阻塞IO,应用程序调用内核函数,阻塞到内核完成数据准备和数据拷贝的全过程。

    二是非阻塞IO,应用程序调用内核函数,不断的查问内核数据是否准备好,直到内核数据准备好,再阻塞到内核完成数据拷贝。

    第三种是I/O复用,应用程序调用内核参数,告知内核关心的事件,内核在收到该事件准备好的数据后,通知应用程序,应用程序再阻塞到内核的数据拷贝完成,一般web服务器都采用这样的IO模型,例如Apache采用的select/poll,当然nginx也支持select/poll,但是在linux2.6后,NGINX一般选择epoll。

    第四种是信号,应用程序安置一个信号处理函数,运行过程不阻塞,操作系统在将数据准备好后,会发送一个信号给应用程序,应用程序的信号处理函数可以做IO处理。

    第五种的异步,应用程序在调用操作系统提供的异步IO函数,例如aio_read。

    告知操作系统发出的请求无需立即返回,待操作系统做完数据准备和数据拷贝后,再通知应用程序通过系统调用函数指定的信号。

    实际上网络I/O模型中,前四种都是同步模型,第五种是异步模型。

    我们先看一下NGINX的module里面支持的IO模型。

    |-- event
    |   |-- modules
    |   |   |-- ngx_aio_module.c
    |   |   |-- ngx_devpoll_module.c
    |   |   |-- ngx_epoll_module.c
    |   |   |-- ngx_eventport_module.c
    |   |   |-- ngx_kqueue_module.c
    |   |   |-- ngx_poll_module.c
    |   |   |-- ngx_rtsig_module.c
    |   |   |-- ngx_select_module.c
    |   |   `-- ngx_win32_select_module.c

    在本章,将重点研究NGINX使用epoll做网络IO。

    NGINX做网络IO,涉及到三个module:

    module名称

    类型

    所在文件

    ngx_events_module

    NGX_CORE_MODULE

    ngx_event.c

    ngx_event_core_module

    NGX_EVENT_MODULE

    ngx_event.c

    ngx_epoll_module

    NGX_EVENT_MODULE

    module/ngx_epoll_module.c

      在上一章,提到了module的启动过程,在init_cycle函数,对ngx_events_module的配置信息做了生成,通过分析配置文件,调用ngx_events_commands去对NGX_EVENT_MODULE做了配置信息的生成,分析,初始化。

    一、master-work工作模式的处理过程

    在解决配置信息的处理后,我们来看看进程的处理过程

    1、  我们选择master-work工作模式

    ngx_master_process_cycle(ngx_cycle_t *cycle)
    {
            ......
        
        ngx_start_worker_processes(cycle, ccf->worker_processes,
                                   NGX_PROCESS_RESPAWN);
        ngx_start_cache_manager_processes(cycle, 0);
        
        ......
    }

    2、

    static void
    ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
    {
        ngx_int_t      i;
        ngx_channel_t  ch;
    
        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
    
        ch.command = NGX_CMD_OPEN_CHANNEL;
    
        for (i = 0; i < n; i++) {
    
            ngx_spawn_process(cycle, ngx_worker_process_cycle,
                              (void *) (intptr_t) i, "worker process", type);
    
            ch.pid = ngx_processes[ngx_process_slot].pid; //主进程的情况
            ch.slot = ngx_process_slot;
            ch.fd = ngx_processes[ngx_process_slot].channel[0];
    
            ngx_pass_open_channel(cycle, &ch);
        }
    }

    3、

    //进程生成
    ngx_pid_t
    ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
        char *name, ngx_int_t respawn)
    {
       ……
    
        pid = fork();
    
        switch (pid) {
    
        case -1:
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "fork() failed while spawning "%s"", name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
    
        case 0: //子进程进入到proc
            ngx_pid = ngx_getpid();
            proc(cycle, data);
            break;
    
        default: //父进程继续
            break;
        }
         
        ……
    
        return pid;
    }

    4、

    static void
    ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
    {
    ……
    
        ngx_worker_process_init(cycle, worker);
    
        ngx_setproctitle("worker process");
    
    ……
    
        for ( ;; ) {
    ……
            ngx_process_events_and_timers(cycle);
            ……
        }
    }

    5、

    static void
    ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
    {
        ……
    
        for (i = 0; ngx_modules[i]; i++) {
            if (ngx_modules[i]->init_process) {
                if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
                    /* fatal */
                    exit(2);
                }
            }
        }
    
     ……
    
        if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
                                  ngx_channel_handler)
            == NGX_ERROR)
        {
            /* fatal */
            exit(2);
        }
    }

    6、

    static ngx_int_t
    ngx_event_process_init(ngx_cycle_t *cycle)
    {
        ......
    
        //初始化module的action
    
    
        ......
        cycle->connections =
            ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
        if (cycle->connections == NULL) {
            return NGX_ERROR;
        }
    
        c = cycle->connections;
    
        cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
                                       cycle->log);
        if (cycle->read_events == NULL) {
            return NGX_ERROR;
        }
    
        rev = cycle->read_events;
        for (i = 0; i < cycle->connection_n; i++) {
            rev[i].closed = 1;
            rev[i].instance = 1;
    #if (NGX_THREADS)
            rev[i].lock = &c[i].lock;
            rev[i].own_lock = &c[i].lock;
    #endif
        }
    
        cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
                                        cycle->log);
        if (cycle->write_events == NULL) {
            return NGX_ERROR;
        }
    
        wev = cycle->write_events;
        for (i = 0; i < cycle->connection_n; i++) {
            wev[i].closed = 1;
    #if (NGX_THREADS)
            wev[i].lock = &c[i].lock;
            wev[i].own_lock = &c[i].lock;
    #endif
        }
    
        i = cycle->connection_n;
        next = NULL;
    
        do {
            i--;
    
            c[i].data = next;
            c[i].read = &cycle->read_events[i];
            c[i].write = &cycle->write_events[i];
            c[i].fd = (ngx_socket_t) -1;
    
            next = &c[i];
    
    #if (NGX_THREADS)
            c[i].lock = 0;
    #endif
        } while (i);
    
        cycle->free_connections = next;
        cycle->free_connection_n = cycle->connection_n;
    
        /* for each listening socket */
    
        ls = cycle->listening.elts;
        for (i = 0; i < cycle->listening.nelts; i++) {
    
            ......
    
            rev->handler = ngx_event_accept;
    
            if (ngx_use_accept_mutex) {
                continue;
            }
    
            if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
                if (ngx_add_conn(c) == NGX_ERROR) {
                    return NGX_ERROR;
                }
    
            } else {
                if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
                    return NGX_ERROR;
                }
            }
    
    #endif
    
        }
    
        return NGX_OK;
    }
  • 相关阅读:
    iOS 证书、真机调试、发布 App Store
    iOS 9 适配
    交叉编译tslib1.4
    nau8822 codec driver 录音时mic bias 无法自动打开问题
    nuc900 nand flash mtd 驱动
    在ubuntu14.04上安装oracle java6 java7的方法
    N3292x IBR介绍
    N3292系列资料之RTC介绍
    支持mdev的init脚本片断
    Nginx
  • 原文地址:https://www.cnblogs.com/yimuren/p/4088887.html
Copyright © 2011-2022 走看看