Nginx学习——启动框架

Nginx启动时框架处理流程

下图包含了Nginx框架在启动阶段执行的所有基本流程:

下面的简要源码是对上面步骤的说明:

第1步:

在src\core\nginx.c的main函数中实现:

主要语句:

/*第1步:调用ngx_process_options方法设置配置文件路径等参数*/
    if (ngx_process_options(&init_cycle) != NGX_OK) {
        return 1;
}

第2步:

在src\core\nginx.c的main函数中实现:

主要语句:

/*
	第2步Nginx不重启master进程而启动新版本的Nginx程序,也就是平滑升级。
	通过环境变量NGINX完成socket的继承,继承来的socket将会放到init_cycle的listening数组中。
	在NGINX的环境变量中,每个socke中间用冒号或分号隔开。完成继承同时设置全局变量ngx_inherited为1.
	*/
    if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
        return 1;
}

第3-8步都在:src\core\ngx_cycle.c中ngx_init_cycle实现,在main函数调用ngx_init_cycle源码如下:

/*
调用ngx_init_cycle()函数,这里会初始化很多东西到变量cycle,是nginx启动初始化的核心之处
*/
cycle = ngx_init_cycle(&init_cycle);

第3步:

/*
	流程图第3步:在for循环中,调用NGX_CORE_MODULE类型模块的ceate_conf回调,创建相应的配置结构存储空间,
	然后将这个配置结构存储空间的地址保存到conf_ctx数组的对应单元处。
	*/
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            cycle->conf_ctx[ngx_modules[i]->index] = rv;
        }
}

第4步:

/*
	第4步:这里将完成对配置文件的解析工作,做过Nginx模块开发的都清楚——解析配置文件的时候,将会完成每个指令的set回调,
	这个set回调函数一般都是用于将配置数据填写到配置结构中。
	*/
    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }

    if (ngx_test_config && !ngx_quiet_mode) {
        ngx_log_stderr(0, "the configuration file %s syntax is ok",
                       cycle->conf_file.data);
}

第5步:

/*
	第五步:
	这里调用所有NGX_CORE_MODULE类型模块的init_conf回调函数,完成配置结构的初始化工作。
	*/
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->init_conf) {
            if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                == NGX_CONF_ERROR)
            {
                environ = senv;
                ngx_destroy_cycle_pools(&conf);
                return NULL;
            }
        }
}

第6步:

/*
	第6步:
	此处for循环是在遍历链表open_files
	遍历open_files链表,打开所有文件(调用open)。起初,我们看到了对open_files链表的创建、初始化,
	却没有看到写需要打开的文件名数据到链表中;其实,填写文件名数据就是在解析配置文件的时候完成的。
	除此之外,很多很多的数据初始化都是在解析配置文件的时候完成。执行了打开文件操作后,open_files链表就不光保存了文件名了,
	还保存了文件描述符等信息,足够以后读写文件之用了。
	*/
    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }

        if (file[i].name.len == 0) {
            continue;
        }
		/*根据链表中存储的文件名来打开对应的文件*/
        file[i].fd = ngx_open_file(file[i].name.data,
                                   NGX_FILE_APPEND,
                                   NGX_FILE_CREATE_OR_OPEN,
                                   NGX_FILE_DEFAULT_ACCESS);

        ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
                       "log: %p %d \"%s\"",
                       &file[i], file[i].fd, file[i].name.data);

        if (file[i].fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          ngx_open_file_n " \"%s\" failed",
                          file[i].name.data);
            goto failed;
        }

#if !(NGX_WIN32)
        if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          "fcntl(FD_CLOEXEC) \"%s\" failed",
                          file[i].name.data);
            goto failed;
        }
#endif
}
/*
	第6步:
	同上面的open_files,此处遍历链表shared_memory,初始化各个共享内存段
	*/
    for (i = 0; /* void */ ; i++) {
ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK
        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            shm_zone = part->elts;
            i = 0;
        }

        if (shm_zone[i].shm.size == 0) {
            ngx_log_error(NGX_LOG_EMERG, log, 0,
                          "zero size shared memory zone \"%V\"",
                          &shm_zone[i].shm.name);
            goto failed;
        }

        shm_zone[i].shm.log = cycle->log;

        opart = &old_cycle->shared_memory.part;
        oshm_zone = opart->elts;

        for (n = 0; /* void */ ; n++) {

            if (n >= opart->nelts) {
                if (opart->next == NULL) {
                    break;
                }
                opart = opart->next;
                oshm_zone = opart->elts;
                n = 0;
            }

            if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
                continue;
            }

            if (ngx_strncmp(shm_zone[i].shm.name.data,
                            oshm_zone[n].shm.name.data,
                            shm_zone[i].shm.name.len)
                != 0)
            {
                continue;
            }

            if (shm_zone[i].tag == oshm_zone[n].tag
                && shm_zone[i].shm.size == oshm_zone[n].shm.size)
            {
                shm_zone[i].shm.addr = oshm_zone[n].shm.addr;

                if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
                    != NGX_OK)
                {
                    goto failed;
                }

                goto shm_zone_found;
            }

            ngx_shm_free(&oshm_zone[n].shm);

            break;
        }
		/*
		第6步:
		下面三步就完成共享内存的创建和初始化
		*/
        if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
            goto failed;
        }

        if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
            goto failed;
        }

        if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
            goto failed;
        }

    shm_zone_found:

        continue;
    }

第7步:

/*
	第七步:
	遍历listening数组,打开所有的监听套接口(依次进行socket、bind、listen),
	同时设置一些socket选项及文件描述符属性,如非阻塞等。
	*/
    if (ngx_open_listening_sockets(cycle) != NGX_OK) {
        goto failed;
    }

    if (!ngx_test_config) {
        ngx_configure_listening_sockets(cycle);
    }

第8步:

/*
	第8步:
	执行所有模块的init_module操作,看名字为对模块进行初始化。
	*/
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->init_module) {
            if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
                /* fatal */
                exit(1);
            }
        }
    }

第9步-16步又回到main函数中执行:

/*
	到此就基本完成了Nginx的启动初始化过程了,即将开始进程相关的工作,这里做最重要的
	是ngx_master_process_cycle这个过程,在这个过程里实现了master-worker模式的进程模型,
	也是生成环境下nginx的常用模型。
	*/
    if (ngx_process == NGX_PROCESS_SINGLE) {
	/*
	第9、10步
	*/
        ngx_single_process_cycle(cycle);

    } else {
	/*
	第11-16步
	*/
        ngx_master_process_cycle(cycle);
    }

参考

深入理解Nginx

http://www.alidata.org/archives/1092

转载请注明出处~~

时间: 2024-10-12 17:19:38

Nginx学习——启动框架的相关文章

Nginx学习之十一-Nginx启动框架处理流程

Nginx启动过程流程图 下面首先给出Nginx启动过程的流程图: ngx_cycle_t结构体 Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个Nginx的入口,除了完成启动初始化任务以外,也必定是所有功能模块的入口之处.Nginx的初始化工作主要围绕一个类型为ngx_cycle_t类型的全局变量(cycle)展开. ngx_cycle_t结构体类型: typedef struct ngx_cycle_s ngx_cycle_t; struc

nginx学习十一 nginx启动流程

今天用了一天的时间看nginx的启动流程,流程还是很复杂,主要的函数调用有十几个之多,通过看源码和上网查资料,弄懂了一些函数,有些函数还在学习中,有些函数还待日后学习,这里记录一下今天所学.加油! http://blog.csdn.net/xiaoliangsky/article/details/39856803 1nginx.c 启动的程序主要在src/core/nginx.c中,和普通函数一样,main函数是其入口函数:下面我们看看main函数的源代码: int ngx_cdecl main

【nginx】【转】Nginx启动框架处理流程

Nginx启动过程流程图: ngx_cycle_t结构体: Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个Nginx的入口,除了完成启动初始化任务以外,也必定是所有功能模块的入口之处.Nginx的初始化工作主要围绕一个类型为ngx_cycle_t类型的全局变量(cycle)展开. ngx_cycle_t结构体类型: typedef struct ngx_cycle_s ngx_cycle_t; struct ngx_cycle_s { voi

nginx学习与配置-安装与启动关闭管理

nginx服务器的安装 安装准备: nginx依赖于pcre库,要先安装pcre yum install pcre pcre-devel cd /usr/local/src/ wget wget http://nginx.org/download/nginx-1.6.3.tar.gz tar zxvf nginx-1.6.3.tar.gz cd nginx-1.6.3 ./configure --prefix=/data/local/nginx make && make install 这

nginx学习笔记七(nginx HTTP框架的执行流程)

之前已经介绍过nginx的事件框架.那么,对于client发出的一个http的请求,nginx的http框架是如何一步步解析这个http请求?http框架又是如何和之前介绍过得epoll事件模块结合起来的,下面来简要介绍下. 注:我手头上的nginx工程是nginx-1.9.14的,与<深入理解nginx>的版本不一致,在http框架这块的代码上也有着较大的区别. 一.ngx_http_init_connection 在http框架初始化的时候(参见<深入理解nginx>第10章)

TOMCAT源码分析(启动框架)

建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的. 所以得实践.实践.再实践. 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动过程. 如果有不明白的地方, 再来查阅本文, 看是否能得到帮助. 我相信这样效果以及学习速度都会好很多! 1. Tomcat的整体框架结构 Tomcat的基本框架, 分为4个层次. Top Level Elements: Server Service Connector HTTP AJP Conta

Nginx学习指南之模块的应用

一.自述 Nginx模块功能也是相当的丰富,但对于Apache Web来说,两者之间还是有区别的,大家都知道Nginx模块是直接被编译进了nginx.conf配置文件,而Apache则是被编译成为.SO文件,有些是需要在httpd.conf配置文件中指定是否加载,这样才能激活模块功能.Nginx模块有三个角色,Handlers(处理一个HTTP请求,并产生输出):Filters(处理由一个handler生成的输出):load-balancers(负载均衡器,当后端服务器符合一个以上后,依据算法选

Nginx学习总结(1):Nginx简介

(最近,部门组织了好几个技术兴趣小组,对当前的热门技术进行研究.我加入了Nginx学习小组,与几个同事一道围绕Nginx来进行研究和学习.从今天起,我会陆陆续续发一系列有关Nginx的学习总结.本文是系列之一:Nginx简介.) 一.Nginx概况 1.Nginx是Igor Sysoev为俄罗斯访问量第二的Rambler.ru站点开发的,第一个公开版本0.1.0发布于2004年10月4日.目前最新的版本是nginx-1.9.0(2015年4月28日发布). 2.Nginx是一款高性能的HTTP和

跟着刚哥学习Spring框架--Spring容器(二)

Spring容器 启动Spring容器(实例化容器) -- IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化(加载启动),这样才可以从容器中获取Bean的实例并使用.  Bean是Spring管理的基本单位,任何的Java对象和组件都被当成Bean处理,容器还负责管理Bean与Bean之间的依赖关系.  两种类型的启动实现   1.BeanFactory:IOC容器的基本实现,是Spring框架的基础设施,面向Spring本身: -- Spring容器最基本的接口就是BeanF