构建机房运维基础架构(十): 如何实现Nginx和程序的100%无损发布

我们的负载均衡架构是这样的:

请求 —> 网络 —> LVS集群 —> Nginx 集群 —> APP

这里,LVS、Nginx 和APP(后端程序) 都需要发布,LVS和 Nginx 一般是修改配置文件,APP则是程序更新。对于LVS,我们是用模板生成配置,然后reload,reload 的时候LVS会把当前请求继续处理完,而且LVS改的频率较小,所以问题不大。

主要看一下Nginx 和 APP 如何做到100%无损发布,我觉得理想的方式是发布Nginx 的时候把Nginx 从LVS上T掉,发布APP 的时候从Nginx上把 APP T掉,T掉通过「健康检查」的方式,而不是修改配置reload 。

 

Nginx发布

事实上,LVS支持 HTTP 的检查方式,我们只要在 Nginx 端 创建一个专门用于检测的文件。

LVS的 HTTP_GET 指令用于实现HTTP CHECK,解释如下:

HTTP_GET: Working at layer5. Performs a GET HTTP to a specified URL. The get result is
then summed using the MD5 algorithm. If this sum does not match with the expected value,
the test is wrong and the server is removed from the server pool. This module implements a
multi-URL get check on the same service. This functionality is useful if you are using a server
hosting more than one application server. This functionality gives you the ability to check if an
application server is working properly. The MD5 digests are generated using the genhash
utility (included in the keepalived package).

同样,LVS 支持 SSL_GET 的方式,用于 检查后端的 443 端口。

SSL_GET: Same as HTTP_GET but uses a SSL connection to the remote webservers. 

这里,我先配置Nginx,Nginx配置文件目录 是 /home/work/nginx/conf ,我把检查的配置写在了default配置里,LVS检查请求的Host 是 Nginx的内网IP,所以要保证没有其他配置文件的server_name 里面包含 Nginx内网IP。

server {
    listen 80 default_server;
    listen 443 ssl default_server;

    # Do not delete it, otherwise lvs http check will fail, it’s terrible!!!
    location /http_check/index.html {
        root /home/work/nginx/conf/;
        open_file_cache off;
    }

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 10.0.0.0/8;
        deny all;
    }
}

在这里,我们用 open_file_cache off; 把文件缓存关掉,为了不让缓存影响 LVS 的检测;另外要注意,listen 443 的时候要启用 ssl,不然可能会有严重的问题,我遭受过惨烈的 教训

在Nginx 上:
cd /home/work/nginx/conf/

$ cat http_check/index.html

Do not change this file, otherwise lvs http check will fail, it’s terrible!!!

http check ok!

$ md5sum http_check/index.html
2a94d9d1703ca63c35b24fc7a41d89e1  http_check/index.html
在LVS上用 genbash 检查(10.19.29.3是Nginx IP):
$ genhash -s 10.19.29.3 -p 80 -u /http_check/index.html
MD5SUM = b4ec1928222cfee3512e328ad5c98be4

MD5之后的值要写在LVS配置文件里,如下:

delay_loop 6

real_server 10.19.29.3 80 {
weight 100
HTTP_GET(或者 SSL_GET) {
            url {
              path /http_check/index.html
              digest 2a94d9d1703ca63c35b24fc7a41d89e1
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
}
}

解释下下面三个指令的含义:
delay_loop :specify in seconds the interval between checks
nb_get_retry :maximum number of retries
delay_before_retry :delay between two successive retries

Nginx 的http_check/index.html 删掉之后,等待15s LVS就会把Nginx T掉了;同样 http_check/index.html 恢复之后,等15s 也足够了。

 

APP发布

Nginx 的健康检查我们用 ngx_http_upstream_check_module 模块来做, 文档(我们用的是Tengine):
http://tengine.taobao.org/document_cn/http_upstream_check_cn.html

用法类似:
upstream test-nodes {
server pxe0.hy01:8888;
server pxe1.hy01:8888;

    check interval=3000 rise=3 fall=2 timeout=1000 type=http port=1023;’
    check_keepalive_requests 100;
    check_http_send “HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n”;
    check_http_expect_alive http_2xx http_3xx;
}

check_keepalive_requests 指令表示一共连接检查多少次之后关闭,默认是 1,所以改大点比较好(但是我在线上配置的时候发现没有这个指令 !! )。

我们可以在后端APP(比如pxe0.hy01 和 pxe1.hy01 ) 起一个单独的服务,端口 1023 ,专门用作健康检查,检查失败Nginx 即把后端机器 T掉。

这个服务越轻量越稳定越好,甚至可以用精简版Nginx ,虽然看起来很挫,但很work。

另外要注意的两点:

1.如果后端用 lighttpd 做检测,check_http_send 需要加 Host,因为 lighttpd 对长连接要求有 Host 头(HTTP1.1 规范,不知道 Nginx 是否也是这样),不然报 400 bad request ,check_http_send 可以这么写:

     check_http_send “HEAD / HTTP/1.1\r\nConnection: keep-alive\r\nHost:nginx.check\r\n\r\n”;

自己把 nginx.check 替换成想要的 Host 头就行了。

2.我在把这段配置正式上线的时候遇到了一个坑,导致线上所有服务都挂了一下,我在加上配置 reload 的时候 Nginx 开始启用新检查方式,而在新的检查方式成功之前,Nginx 认为后端都是不可用的,会报  502 Bad Gateway ,好惨烈的坑,所以最佳方式是 先 stop 后 start 。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注