zoukankan      html  css  js  c++  java
  • nginx代码分析启动流程

     nginx代码分析--启动流程

    一、  nginx的编译安装

    1.     configure时干的事

    根据configure后面跟的参数,解析auto文件夹下的文件生成Makefile文件。

    2.     编译时干的事

    ngx_modules.c文件是在编译过程中生成的,里面定义了ngx_modules[]模块数组,包含了哪些模块。

    (安装及配置可以参考)http://www.cnblogs.com/geekma/archive/2012/07/28/2612951.html

    二、  nginx启动流程

    1.    模块相关

    ngx_conf_s::module_type有四种类型:

    NGX_CORE_MODULE,

    NGX_EVENT_MODULE,

    NGX_HTTP_MODULE,

    NGX_MAIL_MODULE。

    ngx_conf_s::cmd_type有十一种类型:

    NGX_MAIN_CONF,

    NGX_EVENT_CONF,

    NGX_HTTP_MAIN_CONF,

    NGX_HTTP_SRV_CONF,

    NGX_HTTP_LOC_CONF,

    NGX_HTTP_LMT_CONF,

    NGX_HTTP_SIF_CONF,

    NGX_HTTP_LIF_CONF,

    NGX_HTTP_UPS_CONF,

    NGX_MAIL_MAIN_CONF,

    NGX_MAIL_SRV_CONF。

    2.    一些数据结构

    在介绍启动流程之前,先对几个很重要的数据结构进行下介绍。

    typedef struct {
         /*daemon:是否为守护进程,默认为on,调试时会用off*/
         ngx_flag_t               daemon;
         /*master:是否启动master进程,默认为on,调试时会用off*/
         ngx_flag_t               master;
         /*timer_resolution:调用gettimeofday的间隔,可以减少调用次数*/
         ngx_msec_t               timer_resolution;
         /*worker_processes:工作进程数目*/
         ngx_int_t                worker_processes;
         /*debug_points:在调试器内设置断点等*/
         ngx_int_t                debug_points;
         /*rlimit_nofile:该进程内能够打开的文件描述符最大值*/
         ngx_int_t                rlimit_nofile;
         /*rlimit_sigpending:调用进程中真实用户队列的信号数量限制*/
         ngx_int_t                rlimit_sigpending;
         /*rlimit_core:允许每个进程核心文件的最大值*/
         off_t                    rlimit_core;
         /*priority:工作进程的优先级*/
         int                      priority;
         /*cpu_affinity_n:cpu绑定的个数*/
         ngx_uint_t               cpu_affinity_n;
         /*cpu_affinity:绑定的cpu*/
         uint64_t                *cpu_affinity;
         /*username:用户名*/
         char                    *username;
         /*user:用户ID*/
         ngx_uid_t                user;
         /*group:用户组ID*/
         ngx_gid_t                group;
         /*working_directory:工作的目录*/
         ngx_str_t                working_directory;
         /*lock_file:锁文件路径名*/
         ngx_str_t                lock_file;
         /*pid:进程号文件路径名*/
         ngx_str_t                pid;
         /*oldpid:老的进程号文件路径名*/
         ngx_str_t                oldpid;
         /*env:运行上下文*/
         ngx_array_t              env;
         /*environment:环境变量*/
         char                   **environment;
    
    #if (NGX_THREADS)
         ngx_int_t                worker_threads;
         size_t                   thread_stack_size;
    #endif
    } ngx_core_conf_t;

    一个实际进程打印出的ngx_cofe_conf_t结构体对象:

     

    图:ngx_core_conf_t的实际值

    struct ngx_cycle_s {
         /*conf_ctx: 配置上下文数组*/
        void                  ****conf_ctx;
         /*pool:资源池*/
        ngx_pool_t               *pool;
        /*log:日志相关的结构,包含了level,文件,handler等*/
        ngx_log_t                *log;
        ngx_log_t                 new_log;
        /*files:所有的连接*/
        ngx_connection_t        **files;
        /*free_connetions:空闲的连接*/
        ngx_connection_t         *free_connections;
        /*free_connection_n:空闲的连接数*/
        ngx_uint_t                free_connection_n;
        /*reusable_connections_queue:复用连接队列,keepalive*/
        ngx_queue_t               reusable_connections_queue;
        /*listening:监听数组*/
        ngx_array_t               listening;
        /*pathes:路径数组,与cache操作相关*/
        ngx_array_t               pathes;
        /*open_files:打开的文件链表*/
        ngx_list_t                open_files;
        /*shared_memory:共享内存*/
        ngx_list_t                shared_memory;
        /*connection_n:连接个数,对应配置文件中的worker_connections*/
        ngx_uint_t                connection_n;
        /*files_n:打开文件个数*/
        ngx_uint_t                files_n;
        /*connections:连接事件的双向链表*/
        ngx_connection_t         *connections;
        /*read_events:读事件双向链表*/
        ngx_event_t              *read_events;
        /*write_events:写事件双向链表*/
        ngx_event_t              *write_events;
        /*old_cycle:老的cycle变量*/
        ngx_cycle_t              *old_cycle;
        /*conf_file:配置文件*/
        ngx_str_t                 conf_file;
        /*conf_param:配置参数*/
        ngx_str_t                 conf_param;
        /*conf_prefix:配置前缀,配置文件路径*/
        ngx_str_t                 conf_prefix;
        /*prefix:前缀,默认为安装路径*/
        ngx_str_t                 prefix;
        /*lock_file:锁文件*/
        ngx_str_t                 lock_file;
        /*hostname:主机名*/
        ngx_str_t                 hostname;
    };

     

    图:ngx_cycle_s实际值

    3.    进程启动

    看任何C/C++代码,基本都从main函数入手,nginx的main函数在nginx.c文件中。下面,结合图3-1简单介绍下nginx的启动流程。

     

    图3-1:启动流程图

    main函数中,先初始化debug和error参数,然后才开始处理nginx启动时的参数选项(ngx_get_option),后面是其它各种初始化,其中有一段代码:

    ngx_max_module = 0;
    for (i = 0; ngx_modules[i]; i++) {
        ngx_modules[i]->index = ngx_max_module++;
    }

    这里面的ngx_modules数组在搜索代码时没有发现其相应的初始化部分,刚开始很奇怪,后来发现在编译完的代码中,有一个名为ngx_modules.c的文件,该文件中有这个数组的初始化操作,它是根据configure中的配置项来决定使用哪些模块的。这里,只是对调用的模块标示一下序号。

    ngx_init_cycle函数是根据之前的ngx_cycle_t对象生成一个新的对象,这个结构体在整个进程中是一个很重要的结构。

    在一系列初始化操作之后,会根据ngx_process的值来判断是单进程处理还是主进程处理(多进程)。

    如果ngx_process == NGX_PROCESS_SINGLE,即单进程处理,则进入ngx_single_process_cycle函数。先初始化每个模块,然后进入一个无限循环for(;;),一方面可以对事件和计时器进行操作ngx_process_events_and_timers,同时也可以接收执行用户的操作命令ngx_terminate|ngx_quit|ngx_reconfigure|ngx_reopen。

    如果ngx_process != NGX_PROCESS_SINGLE,即主进程处理,则进入ngx_master_process_cycle函数。同样也是先进行进程的初始化操作,然后调用ngx_start_worker_processes函数启动工作进程,调用ngx_start_cache_manager_processes函数启动cache管理进程,最后同样进入了无限循环for(;;),主进程的主要工作是接收用户命令并发送给各工作进程,同时也对各工作进程进行监视,在子进程(工作进程)退出时会发送SIGCHLD信号,致使ngx_reap为1,就会有如下处理:

    if (ngx_reap) {
        ngx_reap = 0;
        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
        live = ngx_reap_children(cycle);
    }

    代码3-1:ngx_reap为1的处理

    ngx_start_worker_processes工作进程的个数在conf文件中已经指定, for循环内ngx_spawn_process创建进程并执行ngx_worker_process_cycle函数,发现ngx_worker_process_cycle函数和ngx_single_process_cycle函数很相像,其实他们的工作原理基本是一样的,一方面处理事件和定时器ngx_process_events_and_timers,一方面接收执行用户命令,这个用户命令并非用户直接发送的,而是通过了master进程进行了中转。

    启动流程到此为止,其它的事就交给了各进程的无限循环for(;;)来处理了。

  • 相关阅读:
    投简历——个人记录
    光电经纬仪——查资料
    Spring Boot(十三):spring boot小技巧
    Spring Boot(十二):spring boot如何测试打包部署
    Python3 hasattr()、getattr()、setattr()函数简介
    Python3 格式化字符串
    Python3 join函数和os.path.join用法
    Python3 根据m3u8下载视频,批量下载ts文件并且合并
    it commit提示Your branch is up-to-date with 'origin/master'.
    git下,输入git log 进入log 怎么退出
  • 原文地址:https://www.cnblogs.com/geekma/p/2839781.html
Copyright © 2011-2022 走看看