nginx 模块初始化

2015-08-11 17:26:07   最后更新: 2015-08-11 17:26:07   访问数量:839




监听连接数组、复用连接队列、模块配置上下文初始化

上篇日志中,我们对 nginx 各模块初始化有了大致的了解,可是在循环中究竟做了什么呢?我们需要仔细观察

 

ngx_init_cycle 是 nginx 初始化进程中最重要的一个环节,其中对模块配置文件的创建和初始化以及对模块的初始化就是这个初始化函数中最重要的环节了

在调用 ngx_init_cycle 前,首先对所有模块进行了编号:

// objs/ngx_modules.c // ngx_module_t *ngx_modules[] {{{ // &ngx_core_module, // NGX_CORE_MODULE // &ngx_errlog_module, // NGX_CORE_MODULE // &ngx_conf_module, // NGX_CONF_MODULE // &ngx_events_module, // NGX_CORE_MODULE // &ngx_event_core_module, // NGX_EVENT_MODULE // &ngx_epoll_module, // NGX_EVENT_MODULE // &ngx_regex_module, // NGX_CORE_MODULE // &ngx_http_module, // NGX_CORE_MODULE // &ngx_http_core_module, // NGX_HTTP_MODULE // &ngx_http_log_module, // NGX_HTTP_MODULE // &ngx_http_upstream_module, // NGX_HTTP_MODULE // &ngx_http_static_module, // NGX_HTTP_MODULE // &ngx_http_autoindex_module, // NGX_HTTP_MODULE // &ngx_http_index_module, // NGX_HTTP_MODULE // &ngx_http_auth_basic_module, // NGX_HTTP_MODULE // &ngx_http_access_module, // NGX_HTTP_MODULE // &ngx_http_limit_conn_module, // NGX_HTTP_MODULE // &ngx_http_limit_req_module, // NGX_HTTP_MODULE // &ngx_http_geo_module, // NGX_HTTP_MODULE // &ngx_http_map_module, // NGX_HTTP_MODULE // &ngx_http_split_clients_module, // NGX_HTTP_MODULE // &ngx_http_referer_module, // NGX_HTTP_MODULE // &ngx_http_rewrite_module, // NGX_HTTP_MODULE // &ngx_http_proxy_module, // NGX_HTTP_MODULE // &ngx_http_fastcgi_module, // NGX_HTTP_MODULE // &ngx_http_uwsgi_module, // NGX_HTTP_MODULE // &ngx_http_scgi_module, // NGX_HTTP_MODULE // &ngx_http_memcached_module, // NGX_HTTP_MODULE // &ngx_http_empty_gif_module, // NGX_HTTP_MODULE // &ngx_http_browser_module, // NGX_HTTP_MODULE // &ngx_http_upstream_hash_module, // NGX_HTTP_MODULE // &ngx_http_upstream_ip_hash_module, // NGX_HTTP_MODULE // &ngx_http_upstream_least_conn_module, // NGX_HTTP_MODULE // &ngx_http_upstream_keepalive_module, // NGX_HTTP_MODULE // &ngx_http_write_filter_module, // NGX_HTTP_MODULE // &ngx_http_header_filter_module, // NGX_HTTP_MODULE // &ngx_http_chunked_filter_module, // NGX_HTTP_MODULE // &ngx_http_range_header_filter_module, // NGX_HTTP_MODULE // &ngx_http_gzip_filter_module, // NGX_HTTP_MODULE // &ngx_http_postpone_filter_module, // NGX_HTTP_MODULE // &ngx_http_ssi_filter_module, // NGX_HTTP_MODULE // &ngx_http_charset_filter_module, // NGX_HTTP_MODULE // &ngx_http_userid_filter_module, // NGX_HTTP_MODULE // &ngx_http_headers_filter_module, // NGX_HTTP_MODULE // &ngx_http_copy_filter_module, // NGX_HTTP_MODULE // &ngx_http_range_body_filter_module, // NGX_HTTP_MODULE // &ngx_http_not_modified_filter_module, // NGX_HTTP_MODULE // NULL // }; }}} // 对模块进行编号,初始化模块 index 域 for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; }

 

注释中加入了每个模块的类型便于后续操作的理解

 

在 ngx_init_cycle 函数中,首先创建了所有 CORE 模块的配置文件:

// 创建 CORE 模块的配置 // NGX_CORE_MODULE 包括:ngx_core_module、ngx_errlog_module // ngx_events_module、ngx_regex_module、ngx_http_module 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) { // ngx_core_module ngx_core_module_create_conf // ngx_regex_module ngx_regex_create_conf // // ngx_errlog_module NULL // ngx_events_module NULL // ngx_http_module NULL rv = module->create_conf(cycle); if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[ngx_modules[i]->index] = rv; } }

 

这里顺次对所有模块中的 NGX_CORE_MODULE 类型模块调用了他们的 create_conf 方法

NGX_CORE_MODULE 模块只有 5 个:

  1. ngx_core_module
  2. ngx_regex_module
  3. ngx_errlog_module
  4. ngx_events_module
  5. ngx_http_module

而在这五个模块中,只有 ngx_core_module 和 ngx_regex_module 实现了 create_conf 方法:

  1. ngx_core_module -- ngx_core_module_create_conf
  2. ngx_regex_module -- ngx_regex_create_conf

 

nginx 核心配置信息结构创建

// static void * ngx_core_module_create_conf(ngx_cycle_t *cycle) // 核心配置信息创建 {{{ static void * ngx_core_module_create_conf(ngx_cycle_t *cycle) { ngx_core_conf_t *ccf; ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)); if (ccf == NULL) { return NULL; } /* * set by ngx_pcalloc() * * ccf->pid = NULL; * ccf->oldpid = NULL; * ccf->priority = 0; * ccf->cpu_affinity_n = 0; * ccf->cpu_affinity = NULL; */ ccf->daemon = NGX_CONF_UNSET; ccf->master = NGX_CONF_UNSET; ccf->timer_resolution = NGX_CONF_UNSET_MSEC; ccf->worker_processes = NGX_CONF_UNSET; ccf->debug_points = NGX_CONF_UNSET; ccf->rlimit_nofile = NGX_CONF_UNSET; ccf->rlimit_core = NGX_CONF_UNSET; ccf->rlimit_sigpending = NGX_CONF_UNSET; ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT; ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT; #if (NGX_THREADS) ccf->worker_threads = NGX_CONF_UNSET; ccf->thread_stack_size = NGX_CONF_UNSET_SIZE; #endif if (ngx_array_init(&ccf->env, cycle->pool, 1, sizeof(ngx_str_t)) != NGX_OK) { return NULL; } return ccf; } // }}}

 

 

他创建了一个 ngx_core_conf_t 结构体变量,用于保存整个 nginx 启动环境的配置信息,包括配置文件中的配置与系统的配置参数

并将它全部域都初始化为 -1 (NGX_CONF_UNSET)

// struct ngx_core_conf_t // nginx 核心配置结构体 {{{ typedef struct { ngx_flag_t daemon; // 为 0 则不以 deamon 方式运行 ngx_flag_t master; // 为 0 则不创建 worker ngx_msec_t timer_resolution; // 最大超时时间 ngx_int_t worker_processes; // worker 进程数 ngx_int_t debug_points; ngx_int_t rlimit_nofile; // 系统最大文件描述符数 ngx_int_t rlimit_sigpending; // 系统最大挂起信号数 off_t rlimit_core; // 内核转存文件的最大长度 int priority; // 进程优先级 ngx_uint_t cpu_affinity_n; // CPU 数 uint64_t *cpu_affinity; char *username; // 用户名 ngx_uid_t user; // 用户ID ngx_gid_t group; // 组ID ngx_str_t working_directory; // 当前工作路径 ngx_str_t lock_file; // 锁文件 ngx_str_t pid; // pid 文件 ngx_str_t oldpid; // 老的 pid 文件,用于平滑启动 ngx_array_t env; // 环境变量 char **environment; // 环境变量 #if (NGX_THREADS) ngx_int_t worker_threads; // worker 线程数 size_t thread_stack_size; // 线程栈大小 #endif } ngx_core_conf_t; // }}}

 

 

正则配置结构创建

// static void * ngx_regex_create_conf(ngx_cycle_t *cycle) // 正则配置结构创建 {{{ static void * ngx_regex_create_conf(ngx_cycle_t *cycle) { ngx_regex_conf_t *rcf; rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); if (rcf == NULL) { return NULL; } rcf->pcre_jit = NGX_CONF_UNSET; ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); if (ngx_pcre_studies == NULL) { return NULL; } return rcf; } // }}}

 

 

pcre 是一个流行的正则库,nginx 使用了这个正则库,在相关配置结构体中,保存了指向这个正则库编译器的指针 pcre_jit

// struct ngx_regex_conf_t // PCRE 正则库配置 {{{ typedef struct { // 指向正则库编译器指针 ngx_flag_t pcre_jit; } ngx_regex_conf_t; // }}}

 

 

在配置结构体创建以后,nginx 并没有立即初始化他们,这是为什么呢?

在创建配置结构体后,nginx 接下来进行了配置文件的解析,紧接着,nginx 调用各个模块的 init_conf 初始化了相应的结构体

为什么这么做?因为 ngx_core_module 的配置结构依赖于配置文件的解析,需要使用配置文件中的配置进行相应的初始化

 

ngx_core_module 配置结构初始化 -- ngx_core_module_init_conf

ngx_core_module 配置的一部分已经在配置文件解析的过程中进行过初始化了

// static char * ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf) // 内核模块配置结构初始化 {{{ static char * ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf) { ngx_core_conf_t *ccf = conf; ngx_conf_init_value(ccf->daemon, 1); ngx_conf_init_value(ccf->master, 1); ngx_conf_init_msec_value(ccf->timer_resolution, 0); ngx_conf_init_value(ccf->worker_processes, 1); ngx_conf_init_value(ccf->debug_points, 0); #if (NGX_HAVE_CPU_AFFINITY) if (ccf->cpu_affinity_n && ccf->cpu_affinity_n != 1 && ccf->cpu_affinity_n != (ngx_uint_t) ccf->worker_processes) { ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "the number of \"worker_processes\" is not equal to " "the number of \"worker_cpu_affinity\" masks, " "using last mask for remaining worker processes"); } #endif #if (NGX_THREADS) ngx_conf_init_value(ccf->worker_threads, 0); ngx_threads_n = ccf->worker_threads; ngx_conf_init_size_value(ccf->thread_stack_size, 2 * 1024 * 1024); #endif if (ccf->pid.len == 0) { ngx_str_set(&ccf->pid, NGX_PID_PATH); } // 保存 pid 配置文件路径 if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { return NGX_CONF_ERROR; } ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); if (ccf->oldpid.data == NULL) { return NGX_CONF_ERROR; } ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); #if !(NGX_WIN32) if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) { struct group *grp; struct passwd *pwd; ngx_set_errno(0); // 获取用户 (nobody) 相关信息 pwd = getpwnam(NGX_USER); if (pwd == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "getpwnam(\"" NGX_USER "\") failed"); return NGX_CONF_ERROR; } ccf->username = NGX_USER; ccf->user = pwd->pw_uid; ngx_set_errno(0); // 获取组 (nogroup) 相关信息 grp = getgrnam(NGX_GROUP); if (grp == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "getgrnam(\"" NGX_GROUP "\") failed"); return NGX_CONF_ERROR; } ccf->group = grp->gr_gid; } // 初始化锁文件配置 if (ccf->lock_file.len == 0) { ngx_str_set(&ccf->lock_file, NGX_LOCK_PATH); } if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) != NGX_OK) { return NGX_CONF_ERROR; } { ngx_str_t lock_file; lock_file = cycle->old_cycle->lock_file; if (lock_file.len) { lock_file.len--; if (ccf->lock_file.len != lock_file.len || ngx_strncmp(ccf->lock_file.data, lock_file.data, lock_file.len) != 0) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "\"lock_file\" could not be changed, ignored"); } cycle->lock_file.len = lock_file.len + 1; lock_file.len += sizeof(".accept"); cycle->lock_file.data = ngx_pstrdup(cycle->pool, &lock_file); if (cycle->lock_file.data == NULL) { return NGX_CONF_ERROR; } } else { cycle->lock_file.len = ccf->lock_file.len + 1; cycle->lock_file.data = ngx_pnalloc(cycle->pool, ccf->lock_file.len + sizeof(".accept")); if (cycle->lock_file.data == NULL) { return NGX_CONF_ERROR; } ngx_memcpy(ngx_cpymem(cycle->lock_file.data, ccf->lock_file.data, ccf->lock_file.len), ".accept", sizeof(".accept")); } } #endif return NGX_CONF_OK; } // }}}

 

 

事件模块配置初始化 -- ngx_event_init_conf

事件模块配置的初始化过程非常简单,他只保证 ngx_events_module 的上下文已经被加载到 nginx 的全局变量 cycle 中

// static char * ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) // 事件模块配置初始化 {{{ static char * ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) { if (ngx_get_conf(cycle->conf_ctx, ngx_events_module) == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no \"events\" section in configuration"); return NGX_CONF_ERROR; } return NGX_CONF_OK; } // }}}

 

 

正则库配置初始化 -- ngx_regex_init_conf

这里将 PCRE 配置中的编译器指针初始化为 0

// static char * ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf) // 正则库 PCRE 配置初始化 {{{ static char * ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf) { ngx_regex_conf_t *rcf = conf; ngx_conf_init_value(rcf->pcre_jit, 0); return NGX_CONF_OK; } // }}}

 

 

  • 事实上,事件模块和正则库模块的真正初始化过程是 init_module

 

只有两个模块实现了 init_module 方法

  1. ngx_event_core_module -- ngx_event_module_init
  2. ngx_regex_module -- ngx_regex_module_init

 

事件模块初始化 -- ngx_event_module_init

在这个函数中最重要的一件事就是实现了互斥锁 ngx_accept_mutex_ptr,nginx 为了兼容性自己实现了锁,而没有依赖系统实现

// static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle) // 事件模块初始化 {{{ static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle) { void ***cf; u_char *shared; size_t size, cl; ngx_shm_t shm; ngx_time_t *tp; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; // 获取 ngx_events_module 配置 cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); // 获取 ngx_event_core_module 配置 ecf = (*cf)[ngx_event_core_module.ctx_index]; // ecf = { // connections = 1024, // use = 1, // multi_accept = 0, // accept_mutex = 1, // accept_mutex_delay = 500, // name = 0x80bdb09 "epoll" // } if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "using the \"%s\" event method", ecf->name); } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // ccf = { // daemon = 1, // master = 1, // timer_resolution = 0, // worker_processes = 2, // debug_points = 0, // rlimit_nofile = -1, // rlimit_sigpending = -1, // rlimit_core = -1, // priority = 0, // cpu_affinity_n = 0, // cpu_affinity = 0x0, // username = 0x80ba02f "nobody", // user = 65534, // group = 65534, // working_directory = { // len = 0, // data = 0x0 // }, // lock_file = { // len = 49, // data = 0x810f358 "/home/zeyu/Documents/nginx-1.7.7//logs/nginx.lock" // }, // pid = { // len = 24, // data = 0x80ba016 "/var/run/nginx/nginx.pid" // }, // oldpid = { // len = 32, // data = 0x810f338 "/var/run/nginx/nginx.pid.oldbin" // }, // env = { // elts = 0x80fff34, // nelts = 0, // size = 8, // nalloc = 1, // pool = 0x80ff5b0 // }, // environment = 0x0 // } ngx_timer_resolution = ccf->timer_resolution; #if !(NGX_WIN32) { ngx_int_t limit; struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed, ignored"); } else { if (ecf->connections > (ngx_uint_t) rlmt.rlim_cur && (ccf->rlimit_nofile == NGX_CONF_UNSET || ecf->connections > (ngx_uint_t) ccf->rlimit_nofile)) { limit = (ccf->rlimit_nofile == NGX_CONF_UNSET) ? (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile; ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "%ui worker_connections exceed " "open file resource limit: %i", ecf->connections, limit); } } } #endif /* !(NGX_WIN32) */ // 无 worker 模式,则不需要后续流程 if (ccf->master == 0) { return NGX_OK; } if (ngx_accept_mutex_ptr) { return NGX_OK; } // 实现互斥锁 ngx_accept_mutex_ptr /* cl should be equal to or greater than cache line size */ cl = 128; size = cl /* ngx_accept_mutex */ + cl /* ngx_connection_counter */ + cl; /* ngx_temp_number */ #if (NGX_STAT_STUB) size += cl /* ngx_stat_accepted */ + cl /* ngx_stat_handled */ + cl /* ngx_stat_requests */ + cl /* ngx_stat_active */ + cl /* ngx_stat_reading */ + cl /* ngx_stat_writing */ + cl; /* ngx_stat_waiting */ #endif shm.size = size; shm.name.len = sizeof("nginx_shared_zone"); shm.name.data = (u_char *) "nginx_shared_zone"; shm.log = cycle->log; if (ngx_shm_alloc(&shm) != NGX_OK) { return NGX_ERROR; } shared = shm.addr; ngx_accept_mutex_ptr = (ngx_atomic_t *) shared; ngx_accept_mutex.spin = (ngx_uint_t) -1; if (ngx_shmtx_create(&ngx_accept_mutex, (ngx_shmtx_sh_t *) shared, cycle->lock_file.data) != NGX_OK) { return NGX_ERROR; } ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl); (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "counter: %p, %d", ngx_connection_counter, *ngx_connection_counter); ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl); tp = ngx_timeofday(); ngx_random_number = (tp->msec << 16) + ngx_pid; #if (NGX_STAT_STUB) ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); ngx_stat_waiting = (ngx_atomic_t *) (shared + 9 * cl); #endif return NGX_OK; } // }}}

 

 






技术帖      龙潭书斋      nginx      源码      opensource      sourcecode      webserver      模块      开源      module      自旋锁      互斥锁     


京ICP备15018585号