nginx_upstream_check_module
模块可以用来监测被负载均衡的主机的健康状态,该模块并不是 Nginx 提供,而是一个第三方模块,其 GitHub 地址为 https://github.com/yaoweibin/nginx_upstream_check_module。
可以看到,该模块仅支持如下版本的 Nginx:
在开始之前先约定一下环境,我这里使用的是 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
,响应监控页面如下:
除此之外,我们还可以通过 URL 参数 ?format={html|csv|json}
的方式让 check_status
返回指定格式的数据,默认是 html
。
下面让其返回 json 格式的数据:
即在 location
节下使用一个 check_status
指令就可让这个 location
返回一个指定格式的页面,是不是很简单。
3、现在让 10.0.1.202
这台主机返回错误的状态码试试,修改 10.0.1.202
的 location
节配置如下并重载服务:
location / {
return 200 'Host 202';
}
4、刷新浏览器监控页:
可以看到,当失败请求 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;
}
默认情况下,后端主机返回 2xx
或 3xx
状态码时代理主机就认为它是正常状态。
6、再次刷新浏览器监控页面,如下:
可以看到,后端主机 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,也可参考淘宝文档。
评论区