nginx平滑重启(windownginx重启命令)

nginx平滑重启(windownginx重启命令)

浏览次数:
信息来源: 用户投稿
更新日期: 2026-04-06
文章简介

一、背景在服务器开发过程中,难免需要重启服务加载新的代码或配置,如果能够保证server重启的过程中服务不间断,那重启对于业务的影响可以降为0。二、重启流程重启意味着新旧接替,在交接任务的过程中

2025阿里云双十一服务器活动

一、背景

在服务器开发过程中,难免需要重启服务加载新的代码或配置,如果能够保证server重启的过程中服务不间断,那重启对于业务的影响可以降为0。

二、重启流程

  • 重启意味着新旧接替,在交接任务的过程中势必会存在新旧server并存的情形,因此,重启的流程大致为:

  • 新旧server并存,两者共同处理请求,提供服务

  • 旧的server处理完所有的请求之后优雅退出

  • 这里,最主要的问题在于如何保证新旧server可以并存,如果重启前后的server端口一致,如何保证两者可以监听同一端口。

  • 三、nginx实现

    为了验证nginx平滑重启,笔者首先尝试nginx启动的情形下再次开启一个新的server实例,结果

    很明显,重新开启server实例是行不通的,原因在于新旧server使用了同一个端口80,在未开始socketreuseport选项复用端口时,bind系统调用会出错。nginx默认bind重试5次,失败后直接退出。而nginx需要监听ipv4地址0.0.0.0和ipv6地址[::],故图中打印出10条emerg日志。

    接下来就开始尝试平滑重启命令了,一共两条命令:

    kill-usr2`cat/var/run/nginx.pid`

    kill-quit`cat/var/run/nginx.pid.oldbin`

    第一条命令是发送信号usr2给旧的master进程,进程的pid存放在/var/run/nginx.pid文件中,其中nginx.pid文件路径由nginx.conf配置。

    第二条命令是发送信号quit给旧的master进程,进程的pid存放在/var/run/nginx.pid.oldbin文件中,随后旧的master进程退出。

    那么问题来了,为什么旧的master进程的pid存在于两个pid文件之中?事实上,在发送信号usr2给旧的master进程之后,旧的master进程将pid重命名,原先的nginx.pid文件rename成nginx.pid.oldbin。这样新的master进行就可以使用nginx.pid这个文件名了。

    不错,新旧master和worker进程并存了。再来第二条命令,结果如图:

    如你所见,旧的master进程8527和其worker进程全部退出,只剩下新的master进程12740。

    不由得产生困惑,为什么手动开启一个新的实例行不通,使用信号重启就可以达到。先看下nginxlog文件:

    除了之前的错误日志,还多了一条notice,意思就是继承了sockets,fd值为6,7。随着日志翻看nginx源码,定位到nginx.c/ngx_exec_new_binary函数之中,

    ngx_exec_new_binary(ngx_cycle_t*cycle,char*const*argv)

    ctx.name="newbinaryprocess";

    env=ngx_set_environment(cycle,&n);

    var=ngx_alloc(sizeof(nginx_var)

    nginx平滑重启,windownginx重启命令

    p=ngx_cpymem(var,nginx_var"=",sizeof(nginx_var));

    ls=cycle->listening.elts;

    for(i=0;i<cycle->listening.nelts;i++){

    p=ngx_sprintf(p,"%ud;",ls[i].fd);

    ngx_add_inherited_sockets(ngx_cycle_t*cycle)

    inherited=(u_char*)getenv(nginx_var);

    if(ngx_array_init(&cycle->listening,cycle->pool,10,

    for(p=inherited,v=p;*p;p++){

    ls=ngx_array_push(&cycle->listening);

    ngx_memzero(ls,sizeof(ngx_listening_t));

    ls->fd=(ngx_socket_t)s;

    returnngx_set_inherited_sockets(cycle);

    ctx.envp=(char*const*)env;

    ccf=(ngx_core_conf_t*)ngx_get_conf(cycle->conf_ctx,ngx_core_module);

    if(ngx_rename_file(ccf->pid.data,ccf->oldpid.data)==ngx_file_error){

    pid=ngx_execute(cycle,&ctx);

    if(pid==ngx_invalid_pid){

    if(ngx_rename_file(ccf->oldpid.data,ccf->pid.data)==ngx_file_error)

    1. 将旧的master进程监听的所有fd,拷贝至新master进程的env环境变量nginx_var。

    2. ngx_execute函数fork子进程,execve执行命令行启动新的server。

    3. 在server启动流程之中,涉及到环境变量nginx_var的解析,ngx_connection.c/ngx_add_inherited_sockets具体代码为:

    解析环境变量nginx_var的值,获取fd存入数组

    fd对应的socket设为ngx_inherited,保存这些socket的信息。

    也就是说,新的server压根就没重新bind端口listen,这些fd状态和值都是新的master进程fork时带过来的,新的master进程监听处理继承来的文件描述符即可,这里比较关键的一点在于listensocket文件描述符通过env传递。

    以上就是nginx怎么实现平滑重启的详细内容,更多请关注主机测评网其它相关文章!

    标签:
    什么是自动化和编排的关系(自动一体化是什么意思)
    « 上一篇
    返回列表
    下一篇 »

    如本文对您有帮助,就请抽根烟吧!