一、Nginx平滑升级指令
Nginx的MakeFile文件:
default: build
clean:
rm -rf Makefile objs
build:
$(MAKE) -f objs/Makefile
install:
$(MAKE) -f objs/Makefile install
modules:
$(MAKE) -f objs/Makefile modules
upgrade:
/home/nginx_rtmp//sbin/nginx -t
kill -USR2 `cat /home/nginx_rtmp//logs/nginx.pid`
sleep 10
test -f /home/nginx_rtmp//logs/nginx.pid.oldbin
kill -QUIT `cat /home/nginx_rtmp//logs/nginx.pid.oldbin`
将编译好的新Nginx可执行程序,替换原有的旧Nginx程序后,执行make upgrade即可。
二、Nginx平滑升级的源码实现
1、nginx启动时,初始化信号处理函数。
static void
ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext)
{
.........
.........
case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
if (ngx_getppid() == ngx_parent || ngx_new_binary > 0) {
/*
* Ignore the signal in the new binary if its parent is
* not changed, i.e. the old binary's process is still
* running. Or ignore the signal in the old binary's
* process if the new binary's process is already running.
*/
action = ", ignoring";
ignore = 1;
break;
}
ngx_change_binary = 1;
action = ", changing binary";
break;
.........
.........
}
ngx_config.h中
#define NGX_REOPEN_SIGNAL USR1
#define NGX_CHANGEBIN_SIGNAL USR2
2、发送NGX_CHANGEBIN_SIGNAL信号
信号处理接收到信号后,将ngx_change_binary 置 1。
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
.........
.........
if (ngx_change_binary) {
ngx_change_binary = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
}
.........
.........
}
execve():会保留父进程的文件描述符。可以重用父进程的监听套接字。
execve(): By default, file descriptors remain open across an execve(). File descriptors that are marked close-on-exec are closed; see the description of FD_CLOEXEC in fcntl(2). (If a file descriptor is closed, this will cause the release of all record locks obtained on the underlying file by this process. See fcntl(2) for details.) POSIX.1-2001 says that if file descriptors 0, 1, and 2 would otherwise be closed after a successful execve(), and the process would gain privilege because the set-user_ID or set-group_ID permission bit was set on the executed file, then the system may open an unspecified file for each of these file descriptors. As a general principle, no portable program, whether privileged or not, can assume that these three file descriptors will remain closed across an execve().
3、新的可执行程序运行
static void
ngx_execute_proc(ngx_cycle_t *cycle, void *data)
{
.........
.........
if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"execve() failed while executing %s \"%s\"",
ctx->name, ctx->path);
}
.........
.........
}
int ngx_cdecl
main(int argc, char *const *argv)
{
.........
.........
if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
return 1;
}
.........
.........
}
ngx_int_t
ngx_open_listening_sockets(ngx_cycle_t *cycle)
{
.........
.........
if (ls[i].fd != (ngx_socket_t) -1) {
/*对于继承的socket,实际上是运行到这里*/
continue;
}
if (ls[i].inherited) {
/* TODO: close on exit */
/* TODO: nonblocking */
/* TODO: deferred accept */
continue;
}
.........
.........
}
4、关闭旧的nginx master
kill -QUIT `cat /home/nginx_rtmp//logs/nginx.pid.oldbin`