组件热升级


一. master/work模型

  多进程监听同一个端口来实现服务不中断;热升级时先关闭监听(从epoll监听列表中剔除,但不影响已经连接的请求返回),不让新请求进来,再等待现有连接处理完成或超时,就可以进行进程包替换了。

    数据库需要做到新老代码兼容,不能有删除,修改字段

二.lvs  vip健康检查实现组件热升级

业务代码通过curl http://realserverip:/status.html 返回状态是否正在升级中来告诉lvs 本台rs 不可用,记录请求数,如果没有请求了就停止业务进程,进行升级

1.  status.html 文件:

       一般是web 服务器常用的方式,apache/nginx  web 服务 配置健康检测文件status.html[自己设置即可]这样 VIP/LVS  会每秒(或者一个时间粒度) 去他们下面的realserver 上面:curl http://realserverip:/status.html如果能取到这文件,则说明这个realserver 是好的,就会根据负载均衡算法把流量引到这台realserver。

(1).  realserver  touch了 status.html 但是没有启动web服务;

        因为没有启动web服务,则 curl http://realserverip:/status.html 时 根本连不上此台机器 80,所以机器的web服务如果没有启动,即使已经touch了  status.html 文件,LVS 也认为这台机器是不健康的,不会引流量进来;所以,我们上线时;如果不摘流量(rm -f .../status.html);也只是在一瞬间丢掉了流量;LVS 下次健康检测就会失败的.

(2).  配置好监控检测文件后,我们需要在realserver上面touch statu.html文件;

        因为监控检测是通过web服务来检测的;所以,要在 web服务器的  根目录里面touch 监控检测文件;但是这个根目录要找对:

  •  /home/a/conf/apache/httpd.conf    是apache 默认的配置文件:DocumentRoot "/home/a/share/htdocs"  

                 如果在 /home/a/conf/apache/include/*.conf 里面没有新的设置,web服务的跟目录就是上面这个。

  •  如果在  /home/a/conf/apache/include/.*.conf 里面重新设置了<VirtualHost *>  则优先使用include 里面的配置。

[html]  view plain copy
  1. <VirtualHost *>  
  2.       ServerName              www.baidu.com         # 如果访问域名:www.baidu.com  或者直接访问web机器的IP地址则  
  3.       DocumentRoot            /home/a/share/htdocs/test   #跟目录在这个目录下面  
  4.       ........  
  5.       ........  
  • Nginx 服务器:conf里面的那个root 对应的就是 跟目录。               
[html]  view plain copy
  1. http {  
  2.          include                 mime.types;  
  3.          server_tokens           off;  
  4.          root                    /home/a/share/htdocs;   #web 服务器的根目录  
  5.          ......  
  6.          ......  

    2 . 端口(port) 的健康检测方式:

如果realserver 上面不提供web 服务器,则上面的status.html 检测方式是不适合的;我们可以采用port方式;LVS/VIP 会每秒检测下面的 realserver 上面的 固定端口 [ 比如3000]  如果这个realserver的端口可以通信;则认为这台realserver 是健康,会把数据与这台realserver 进行通信;

(1). 判断realserver 的端口是否是通的: 

[html]  view plain copy
  1. telnet realserverIP  port(3000)  
  2. Trying realserverIP   ...  
  3. Connected to realserverIP    
  4. Escape character is '^]'.   ------>表明 端口是通的  
  5.   
  6. Trying  realserverIP...  
  7. telnet: connect to address : realserverIP Connection refused  
  8. telnet: Unable to connect to remote host: Connection refused      ------>表明  端口是不通的   


    3.   status.html + port 监控检测的方式

上面说使用status.html 健康检测的方式必须是web 服务,其实不不一定;只要这个机器提供HTTP的服务,比如curl http://ip:port/status.html  返回是200  就是健康的。
wget http://IP:4050/status.html  可以作为realserver 健康检测的;还是用status.html 来做健康检测,不过需要指定特定的端口:4050   只要应用中可以使用curl 发送消息
也就是可以进行HTTP服务。


     4.  健康检测的方式

     健康检测的方式其实有两种啊,四层健康检测【TCP】、七层健康检测【HTTP】

四层健康检测方式:其实就是上面的端口检测方式,只要这个server 的端口是通的,就认为这台realserver是alive的;就会把流量分发过来,

这样的health  check 一般是用在http服务,但是不是真正的apache/nginx 这样传统的webserver上面;

七层健康检测方式:其实就是上面的status.html 的方式,在OSI的第七层,应用层进行检测,判断curl  http://ip/status.html  这个配置文件是否存在


  •     四层health check :如果你摘流量,必须停止服务,把对应的port 关闭
  •     七层health check :如果你摘流量,只要删除指定的健康检测文件即可

三. nginx 热升级

可以使用Nginx提供的信号机制来对其进行维护,比较常用的是kill -HUP <master pid>命令,它能通知Nginx使用新的配置文件启动工作进程,并逐个关闭旧进程,完成平滑切换。当需要对Nginx进行版本升级或增减模块时,为了不丢失请求,可以结合使用USR2WINCH等信号进行平滑过度,达到热升级的目的。如果中途遇到问题,也能立刻回退至原版本。

操作步骤

1、备份原Nginx二进制文件;

2、编译新Nginx源码,安装路径需与旧版一致;

3、向主进程发送USR2信号,Nginx会启动一个新版本的master进程和工作进程,和旧版一起处理请求:

prey:~ root# ps -ef|grep nginx
 127     1   nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
 129   127   nginx: worker process
prey:~ root# kill -USR2 127
prey:~ root# ps -ef|grep nginx
 127     1   nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
 129   127   nginx: worker process
5180   127   nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
5182  5180   nginx: worker process

4、向原Nginx主进程发送WINCH信号,它会逐步关闭旗下的工作进程(主进程不退出),这时所有请求都会由新版Nginx处理:

prey:~ root# kill -WINCH 127
prey:~ root# ps -ef|grep nginx
 127     1   nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
5180   127   nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
5182  5180   nginx: worker process

5、如果这时需要回退,可向原Nginx主进程发送HUP信号,它会重新启动工作进程, 仍使用旧版配置文件 。尔后可以将新版Nginx进程杀死(使用QUITTERM、或者KILL):

6、如果不需要回滚,可以将原Nginx主进程杀死,至此完成热升级。

prey:~ root# kill 127
prey:~ root# ps -ef|grep nginx
5180     1   nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
5182  5180   nginx: worker process

切换过程中,Nginx会将旧的.pid文件重命名为.pid.oldbin文件,并在旧进程退出后删除。

原理简介

多进程模式下的请求分配方式

Nginx默认工作在多进程模式下,即主进程(master process)启动后完成配置加载和端口绑定等动作,fork出指定数量的工作进程(worker process),这些子进程会持有监听端口的文件描述符(fd),并通过在该描述符上添加监听事件来接受连接(accept)。

信号的接收和处理

Nginx主进程在启动完成后会进入等待状态,负责响应各类系统消息,如SIGCHLD、SIGHUP、SIGUSR2等。

// src/os/unix/ngx_process_cycle.c
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    sigset_t           set;

    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }

    for ( ;; ) {

        sigsuspend(&set); // 等待信号

        // 信号回调函数定义在 src/os/unix/ngx_process.c 中,
        // 它只负责设置全局变量,实际处理逻辑在这里。
        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);
        }

    }
}

上述代码中的ngx_exec_new_binary函数会调用execve系统函数运行一个新的Nginx主进程,并将当前监听端口的文件描述符通过环境变量的方式传递给新的主进程,这样新的主进程fork出的子进程就同样能够对监听端口添加事件回调,接受连接,从而使得新老Nginx共同处理用户请求。

其它方式

除了使用上述方式进行Nginx热升级,还可以选择以下两种方式:

Keepalived主备切换

Nginx用作LB时一般会用Keepalived做热备,即DNS解析指向一个虚拟IP(VIP),主备服务器上分别启动Keepalived进程,当Master健康检查失败,Slave会自动抢夺VIP,完成切换。

在进行热升级时就可以使用这种方式,在Slave上进行Nginx升级,然后关闭Master的Keepalived进程,完成VIP的漂移。测试完成后可以对继续对Master进行升级操作,或选择回滚。

Tengine动态模块

当需要增加Nginx模块时,必须对Nginx源码进行重新编译,然后采用上面提到的方式进行热升级。Nginx官网上说未来并无打算增加动态模块加载的功能,至少1.x中不会。

如果你愿意使用Tengine,淘宝开发的一个Nginx分支,它提供了动态模块加载(DSO)功能。这里简单介绍一下使用方法:

动态添加内部模块

http_sub_module为例,到Nginx源码目录执行以下命令:

$ ./configure --with-http_sub_module=shared
$ make
$ sudo make dso_install

它会将编译好的ngx_http_sub_filter_module.so文件复制到/usr/local/nginx/modules目录下。随后在Nginx配置文件中的最外层添加以下内容:

dso {
    load ngx_http_sub_filter_module.so;
}

执行sbin/nginx -s reload,就能完成模块的加载。

第三方模块

对于第三方模块,Tengine提供了dso_tool命令,能够一步安装:

sbin/dso_tool --add-module=/home/dso/lua-nginx-module

Nginx信号汇总

以下内容译自:http://wiki.nginx.org/CommandLine

主进程支持的信号

  • TERMINT: 立刻退出
  • QUIT: 等待工作进程结束后再退出
  • KILL: 强制终止进程
  • HUP: 重新加载配置文件,使用新的配置启动工作进程,并逐步关闭旧进程。
  • USR1: 重新打开日志文件
  • USR2: 启动新的主进程,实现热升级
  • WINCH: 逐步关闭工作进程

工作进程支持的信号

  • TERMINT: 立刻退出
  • QUIT: 等待请求处理结束后再退出
  • USR1: 重新打开日志文件

nginx -s signal 支持的信号

  • stop: 等价于TERMINT
  • quitQUIT
  • reopenUSR1
  • reloadHUP

使用方法

$ sbin/nginx -s reload
$ kill -HUP $(cat logs/nginx.pid)
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值