本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名原文链接~~~

Nginx(11)之负载均衡健康监测

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:


nginx_upstream_check_module 模块可以用来监测被负载均衡的主机的健康状态,该模块并不是 Nginx 提供,而是一个第三方模块,其 GitHub 地址为 https://github.com/yaoweibin/nginx_upstream_check_module

可以看到,该模块仅支持如下版本的 Nginx:

image.png

在开始之前先约定一下环境,我这里使用的是 CentOS 7,由于我本地已经使用 yum 安装了 Nginx-1.16.1,所以我这里就需要先下载对应版本的 Nginx 源码包,编译出二进制程序后替换现有的 $(which nginx) 即可,而如果你没有安装过 Nginx,那么你就可以编译完毕后直接 make install 了。

那下面我们就开始吧~

安装

1、下载 Nginx 源码包,点击这里可直接点下载 nginx-1.16.1 源码包。
2、点击下载 nginx_upstream_check_module 源码包

也可关注文章首部微信公众号发送 #nginx1.16.1 一次性获取上面俩源码包。

3、安装相关依赖包:

$ yum install -y pcre pcre-devel openssl openssl-devel libxml2 libxml2-dev libxslt-devel gd gd-devel perl-devel perl-ExtUtils-Embed gperftools

4、解压 Nginx 和模块源码包:

$ tar xf nginx-1.16.1.tar.gz
$ unzip nginx_upstream_check_module-master.zip

5、进入 Nginx 源码包解压目录,选择模块解压目录中对应版本 .patch 文件打个补丁:

$ patch -p1 < ../nginx_upstream_check_module-master/check_1.16.1+.patch

6、查看已安装的 Nginx 的编译参数:

$ nginx -V
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E'

7、设定编译参数,在原编译参数的基础上加上 nginx_upstream_check_module 模块,使用 --add-module 指定模块解压目录即可:

$ ./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E' --add-module=../nginx_upstream_check_module-master

8、开始编译:

$ make

如果没安装过 Nginx,此步可直接 make && make install,后续步骤也可省略。

9、备份原有的 Nginx 二进制程序,然后用编译后的 Nginx 二进制程序替换之:

$ cp `which nginx`{,.bak}
$ mv nginx `which nginx`
mv: overwrite ‘/usr/sbin/nginx’? y

10、检查编译参数:

$ nginx -V
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E' --add-module=../nginx_upstream_check_module-master

看到编译参数中包含 nginx_upstream_check_module 了,即安装成功。

使用

环境准备

我这里准备三台主机如下:

主机功用IP
代理主机10.0.1.200
后端主机10.0.1.201
后端主机10.0.1.202

代理主机 10.0.1.200 配置如下:

upstream testpool{
    server 10.0.1.201:80;
    server 10.0.1.202:80;
}

server {
    listen 80;

    location / {
        proxy_pass http://testpool;
    }
}

后端主机 10.0.1.201 配置如下:

server {
    listen 80;
    default_type text/html;

    location / {
        return 200 'Host 201';
    }
}

后端主机 10.0.1.202 配置如下:

server {
    listen 80;
    default_type text/html;

    location / {
        return 200 'Host 202';
    }
}

此时访问 10.0.1.200 的效果是轮询访问两台后端主机。

测试

1、修改代理主机配置如下以使用 nginx_upstream_check_module 模块的健康检查功能:

upstream testpool{
    server 10.0.1.201:80;
    server 10.0.1.202:80;
    check interval=3000 rise=2 fall=3 timeout=1000 type=http default_down=true port=80;
}

server {
    listen 80;

    location / {
        proxy_pass http://testpool;
    }

    location /check_status {
        check_status;
    }
}

可以看到我在 upstream 节下添加了一条 check 指令,其中各项参数描述如下:

  • interval=n:设定检查请求发送间隔,单位为毫秒;
  • rise=n:当检查请求成功 n 次则认为目标主机是正常状态;
  • fall=n:当检查请求失败 n 次则认为目标主机是宕机状态;
  • timeout=n:设定检查请求的超时时间,单位为毫秒;
  • type={tcp|ssl_hello|http|mysql|ajp|fastcgi}:检指定检查请求的协议;
  • default_down={true|fasle}:设定被代理主机的初始状态,默认为 false,即只有连续 rise 次请求成功后被代理主机才会被认为是正常状态;
  • port=n:指定请求的目标端口;

2、重启代理主机的 Nginx 服务,浏览器访问 http://10.0.1.200/check_status,响应监控页面如下:

image.png

除此之外,我们还可以通过 URL 参数 ?format={html|csv|json} 的方式让 check_status 返回指定格式的数据,默认是 html
下面让其返回 json 格式的数据:

image.png

即在 location 节下使用一个 check_status 指令就可让这个 location 返回一个指定格式的页面,是不是很简单。

3、现在让 10.0.1.202 这台主机返回错误的状态码试试,修改 10.0.1.202location 节配置如下并重载服务:

location / {
    return 200 'Host 202';
}

4、刷新浏览器监控页:
image.png

可以看到,当失败请求 3 次后就将 10.0.1.202 这台主机设定为了宕机状态,此时代理主机 10.0.1.200 将不会分配请求给 10.0.1.202 这台主机。

5、如果说,我们希望在被代理主机返回 500+ 的状态码时,依旧视其为正常状态,则可通过 check_http_expect_alive 指令指定,修改代理主机的 upstream 节如下:

upstream testpool{
    server 10.0.1.201:80;
    server 10.0.1.202:80;
    check interval=3000 rise=2 fall=3 timeout=1000 type=http default_down=true port=80;
    check_http_expect_alive http_2xx http_3xx http_5xx;
}

默认情况下,后端主机返回 2xx3xx 状态码时代理主机就认为它是正常状态。

6、再次刷新浏览器监控页面,如下:

image.png

可以看到,后端主机 10.0.1.202 已经恢复正常了,因为我们已经设定让代理主机认为后端主机返回 5xx 状态码时是正常状态了。

7、代理主机到底是如何检测后端主机是否正常呢?换句话说,代理主机发送的请求内容到底是怎样呢?对于响应 HTTP 协议请求的后端主机,我们可以通过 check_http_send 指令指定检查请求的包内容,其默认值为 GET / HTTP/1.0\r\n\r\n,我们可以查看一下后端主机的访问日志:

$ tailf /var/log/nginx/access.log 
10.0.1.200 - - [10/Mar/2020:21:53:23 +0800] "GET / HTTP/1.0" 200 8 "-" "-" "-"
...

8、访问日志里可以直接看到 HTTP 请求的协议版本,所以我们这里修改一下检测请求的协议版本验证一下 check_http_send 指令是否生效,继续修改代理主机的 upstream 节,然后重载代理主机 Nginx 服务:

upstream testpool{
    server 10.0.1.201:80;
    server 10.0.1.202:80;
    check interval=3000 rise=2 fall=3 timeout=1000 type=http default_down=true port=80;
    check_http_expect_alive http_2xx http_3xx http_5xx;
    check_http_send 'HEAD / HTTP/1.1\r\nHost: 0 \r\n\r\n';
}

9、再次查看一下后端主机的返回日志:

10.0.1.200 - - [10/Mar/2020:22:30:01 +0800] "GET / HTTP/1.1" 200 8 "-" "-" "-"

可以看到,修改成功~~~
10、既然可以修改 HTTP 协议的版本为 1.1,那么我们能不能使用它的长连接功能呢?既然提到了,那当然是可以的,默认状态下,代理主机每一次连接后端主机发送一次请求后就立即断开,我们可以通过 check_keepalive_requests 指令来指定每一次连接后可发送的请求数,修改代理主机 upstream 节如下:

upstream testpool{
    server 10.0.1.201:80;
    server 10.0.1.202:80;
    check interval=3000 rise=2 fall=3 timeout=1000 type=http default_down=true port=80;
    check_http_expect_alive http_2xx http_3xx http_5xx;
    check_http_send "HEAD / HTTP/1.1\r\nHost: 0\r\nConnection: keep-alive\r\n\r\n";
    check_keepalive_requests 2;
}

修改之后查看后端主机的访问日志会发现连接的频率变低了:

10.0.1.200 - - [10/Mar/2020:22:33:26 +0800] "GET / HTTP/1.1" 200 8 "-" "-" "-"
10.0.1.200 - - [10/Mar/2020:22:34:32 +0800] "GET / HTTP/1.1" 200 8 "-" "-" "-"
10.0.1.200 - - [10/Mar/2020:22:35:38 +0800] "GET / HTTP/1.1" 200 8 "-" "-" "-"
10.0.1.200 - - [10/Mar/2020:22:36:44 +0800] "GET / HTTP/1.1" 200 8 "-" "-" "-"

长连接实现了,但好像并不是每 2 次一个新连接,,,不知道啥情况,后面再看。。
更多更全的功能可直接参考 GitHub 的 README,也可参考淘宝文档

# Nginx  

如果这篇文章对您有帮助,可点击下方链接分享给你的朋友们😋,如果遇到问题欢迎评论、留言~~~😇

评论

公众号:zze_coding

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×