文章目录- 平滑重启难点
- 平滑重启流程
- 源码探秘
平滑重启难点
重启意味着新旧接替,在交接任务的过程中势必会存在新旧server并存的情形,因此,最主要的问题在于如何保证新旧server可以并存,如果重启前后的server端口一致,如何保证两者可以监听同一端口。
平滑重启流程
代码语言:javascript复制nginx reload流程
(1)向 master 进程发送 HUP 信号(reload命令)
(2)master 进程校验配置文件语法是否正确
(3)master 进程打开新的监听端口
(4)master 进程用新配置启动新的 worker 子进程
(5)master 进程向老 worker 子进程发送 QUIT 信号
(6)老 worker 进程关闭监听句柄,处理完当前连接后结束进程
reload 可以实现平滑重启、
原先我也不得其法,翻来翻去,后来想明白了一点: 拿重启和正常启动做比较不就好了吗?
源码探秘
先定位 “reload” 所在位置:
代码语言:javascript复制static ngx_int_t
ngx_get_options(int argc, char *const *argv)
{
u_char *p;
ngx_int_t i;
for (i = 1; i < argc; i ) {
p = (u_char *) argv[i];
if (*p != '-') {
ngx_log_stderr(0, "invalid option: "%s"", argv[i]);
return NGX_ERROR;
}
while (*p) {
switch (*p ) {
...
case 's':
if (*p) {
ngx_signal = (char *) p;
} else if (argv[ i]) {
ngx_signal = argv[i];
} else {
ngx_log_stderr(0, "option "-s" requires parameter");
return NGX_ERROR;
}
if (ngx_strcmp(ngx_signal, "stop") == 0
|| ngx_strcmp(ngx_signal, "quit") == 0
|| ngx_strcmp(ngx_signal, "reopen") == 0
|| ngx_strcmp(ngx_signal, "reload") == 0)
{
ngx_process = NGX_PROCESS_SIGNALLER;
goto next;
}
...
}
}
next:
continue;
}
return NGX_OK;
}
这里有正常启动的和重启的,区别在于重启的话ngx_process = NGX_PROCESS_SIGNALLER;
下一步追踪这个函数被调用的地方,运气很好,就被调用了一次:
在main里面:
代码语言:javascript复制if (ngx_get_options(argc, argv) != NGX_OK) {
return 1;
}
没有什么价值。
再追踪 ngx_process 的位置,是一个全局变量,不过被调用的地方太多了。
这个就好找多了,除了刚那个地方和声明的地方,只有一个地方被用到了:
具体流程就是: 如果有旧循环的话,先从旧的循环中将必需数据拷贝到新循环中,出现一个判断 ngx_process == NGX_PROCESS_SIGNALLER ,如果是,则直接返回新循环。不然就继续初始化下去。
就写在这里吧,代码太长了。
又追踪了 ngx_init_cycle
的被调用的地方,运气不错,也只有一个地方调用了,赋值给 ngx_cycle,拿去初始化 master 了。
在那个函数里面会处理一些后续信号。
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
void *rv;
char **senv;
ngx_uint_t i, n;
ngx_log_t *log;
ngx_time_t *tp;
ngx_conf_t conf;
ngx_pool_t *pool;
ngx_cycle_t *cycle, **old;
ngx_shm_zone_t *shm_zone, *oshm_zone;
ngx_list_part_t *part, *opart;
ngx_open_file_t *file;
ngx_listening_t *ls, *nls;
ngx_core_conf_t *ccf, *old_ccf;
ngx_core_module_t *module;
char hostname[NGX_MAXHOSTNAMELEN];
ngx_timezone_update();
/* force localtime update with a new timezone */
tp = ngx_timeofday();
tp->sec = 0;
ngx_time_update();
log = old_cycle->log;
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
if (pool == NULL) {
return NULL;
}
pool->log = log;
cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
if (cycle == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->pool = pool;
cycle->log = log;
cycle->old_cycle = old_cycle;
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
if (cycle->conf_prefix.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->prefix.len = old_cycle->prefix.len;
cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
if (cycle->prefix.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_file.len = old_cycle->conf_file.len;
cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len 1);
if (cycle->conf_file.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
old_cycle->conf_file.len 1);
cycle->conf_param.len = old_cycle->conf_param.len;
cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
if (cycle->conf_param.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));
if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,
ngx_str_rbtree_insert_value);
if (old_cycle->open_files.part.nelts) {
n = old_cycle->open_files.part.nelts;
for (part = old_cycle->open_files.part.next; part; part = part->next) {
n = part->nelts;
}
} else {
n = 20;
}
if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
if (old_cycle->shared_memory.part.nelts) {
n = old_cycle->shared_memory.part.nelts;
for (part = old_cycle->shared_memory.part.next; part; part = part->next)
{
n = part->nelts;
}
} else {
n = 1;
}
if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
ngx_queue_init(&cycle->reusable_connections_queue);
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
ngx_destroy_pool(pool);
return NULL;
}
/* on Linux gethostname() silently truncates name that does not fit */
hostname[NGX_MAXHOSTNAMELEN - 1] = '