Nginx高性能Web服务器:Nginx HTTP负载均衡和反向代理的配置与优化(第六章)

Nginx (3.5万) 2020-08-31 14:47:11

6.5、Nginx负载均衡服务器的双机高可用

如果将Web服务器集群当作一个城池,那么负载均衡服务器则相当于城门,重要性不言而喻。如果“城门”关闭了,与外界的通道也就掐断了。如果只有一台Nginx负载均衡服务器,当该服务器发生故障时,则会导致整个网站无法访问。因此,我们需要两台以上的Nginx负载均衡服务器,实现故障转移与高可用。

双机高可用一般是通过虚拟IP(也称漂移IP)方式来实现的,基于Linux/Unix的IP别名技术。双机高可用方式目前可分为两种:第一种方式为一台主服务器加一台热备服务器,正常情况下主服务器绑定一个公网虚拟IP,提供负载均衡服务,热备服务器处于空闲状态,当主服务器发生故障时,热备服务器接管主服务器的虚拟IP,提供负载均衡服务;第二种方式为两台负载均衡服务器都处于活动状态,各自绑定一个公网虚拟IP,提供负载均衡服务,当其中一台服务器发生故障时,另一台服务器接管发生故障服务器的虚拟IP。第一种方式较为常见,但始终有一台服务器处于空闲状态,浪费了一台服务器的负载均衡处理能力。第二种方式需要多用一个公网IP,笔者已经在金山游戏官方网站——逍遥网(xoyo.com)线上环境成功使用,能够在正常情况下将两台服务器都用于实际的负载均衡处理。

第一种方式:
(1)www.yourdomain.com域名解析到虚拟ip:61.1.1.2上。
(2)正常情况下,主机61.1.1.4绑定虚拟ip61.1.1.2。

/sbin/ifconfig eth0:1 61.1.1.2 broadcast  61.1.1.255 netmask 255.255.255.0 up
/sbin/route add -host 61.1.1.2 dev eth0:1
/sbin/arping -I eth0 -c 3 -s 61.1.1.2 61.1.1.1

(3)用户访问www.yourdomain.com(虚拟IP 61.1.1.2)实际访问的是主机61.1.1.4,而备机61.1.1.5则处于空闲状态。
(4)如果主机61.1.1.4发生故障,备机61.1.1.5将在几秒钟内接管虚拟IP 61.1.1.2,与自己绑定,并发送ARPing包给IDC的公网网关刷新MAC地址。

/sbin/ifconfig eth0:1 61.1.1.2 broadcast  61.1.1.255 netmask 255.255.255.0 up
/sbin/route add -host 61.1.1.2 dev eth0:1
/sbin/arping -I eth0 -c 3 -s 61.1.1.2 61.1.1.1

(5)这时,用户访问www.yourdomain.com(虚拟IP 61.1.1.2)实际上访问的是备机61.1.1.5,从而实现故障转移与高可用,避免了单点故障。转移过程如图6-8所示。
Nginx高性能Web服务器:Nginx HTTP负载均衡和反向代理的配置与优化(第六章)_https://www.tiejiang.org_Nginx_第1张
图6-8 一台主机配一台备机的可用服务方式
另外,第一种方式还可以利用基于VRRP路由协议的Keepalived软件来实现。
第二种方式:
(1)www.yourdomain.com域名通过DNS轮询解析到虚拟IP 61.1.1.2和61.1.1.3上。
(2)正常情况下,服务器①61.1.1.4绑定虚拟IP 61.1.1.2,服务器②61.1.1.5绑定虚拟IP61.1.1.3。其联结与运行方式如图6-9所示。
Nginx高性能Web服务器:Nginx HTTP负载均衡和反向代理的配置与优化(第六章)_https://www.tiejiang.org_Nginx_第2张
图6-9 两台负载均衡服务器的高可用服务方式(正常状态)
在服务器①61.1.1.4上执行以下命令:

/sbin/ifconfig eth0:1 61.1.1.2 broadcast  61.1.1.255 netmask 255.255.255.0 up
/sbin/route add -host 61.1.1.2 dev eth0:1
/sbin/arping -I eth0 -c 3 -s 61.1.1.2 61.1.1.1

在服务器①61.1.1.5上执行以下命令:

/sbin/ifconfig eth0:1 61.1.1.3 broadcast  61.1.1.255 netmask 255.255.255.0 up
/sbin/route add -host 61.1.1.3 dev eth0:1
/sbin/arping -I eth0 -c 3 -s 61.1.1.3 61.1.1.1

(3)用户访问www.yourdomain.com(虚拟IP 61.1.1.2和61.1.1.3)实际上是根据DNS轮询访问两台负载均衡服务器,两台服务器均处于活动状态。
(4)如果服务器①发生故障,服务器②将在几秒钟内接管服务器①的虚拟IP 61.1.1.2,与自己绑定,并发送ARPing包给IDC的公网网关刷新MAC地址。这时,服务器②同时绑定61.1.1.2和61.1.1.3两个虚拟IP,其联结与运行方式如图6-10所示。

Nginx高性能Web服务器:Nginx HTTP负载均衡和反向代理的配置与优化(第六章)_https://www.tiejiang.org_Nginx_第3张
图6-10 其中一台负载均衡服务器发生故障的运行方式
在服务器②61.1.1.5上执行以下命令:

/sbin/ifconfig eth0:1 61.1.1.2 broadcast  61.1.1.255 netmask 255.255.255.0 up
/sbin/route add -host 61.1.1.2 dev eth0:1
/sbin/arping -I eth0 -c 3 -s 61.1.1.2 61.1.1.1

我们可以写两个shell脚本,来实现第二种方式的自动故障转移。
以下代码6-7为脚本1(nginx_ha1.sh),部署在Nginx负载均衡服务器①:
代码6-7

#!/bin/sh
LANG=C
date=$(date -d "today" +"%Y-%m-%d %H:%M:%S")
function_bind_vip1()
{
    /sbin/ifconfig eth0:ha1 61.1.1.2 broadcast 219.232.254.255 netmask
    255.255.255.192 up
    /sbin/route add -host 61.1.1.2 dev eth0:ha1
}
function_bind_vip2()
{
    /sbin/ifconfig eth0:ha2 61.1.1.3 broadcast 219.232.254.255 netmask
    255.255.255.192 up
    /sbin/route add -host 61.1.1.3 dev eth0:ha2
}
function_restart_nginx()
{
    kill -USR1 `cat /usr/local/webserver/nginx/nginx.pid`
}
function_remove_vip1()
{
    /sbin/ifconfig eth0:ha1 61.1.1.2 broadcast 219.232.254.255 netmask
    255.255.255.192 down
}
function_remove_vip2()
{
    /sbin/ifconfig eth0:ha2 61.1.1.3 broadcast 219.232.254.255 netmask
    255.255.255.192 down
}
function_vip_arping1()
{
    /sbin/arping -I eth0 -c 3 -s 61.1.1.2 61.1.1.1 > /dev/null 2>&1
}
function_vip_arping2()
{
    /sbin/arping -I eth0 -c 3 -s 61.1.1.3 61.1.1.1 > /dev/null 2>&1
}
bind_time_vip1="N";
bind_time_vip2="N";
while true
do
    httpcode_rip1=`/usr/bin/curl -o /dev/null -s -w %{http_code} http://61.1.1.4`
    httpcode_rip2=`/usr/bin/curl -o /dev/null -s -w %{http_code} http://61.1.1.5`
    if [ x$httpcode_rip1 == "x200" ];
    then
      if [ $bind_time_vip1 == "N" ];
      then
          function_bind_vip1
          function_vip_arping1
          function_restart_nginx
          bind_time_vip1="Y"
      fi
      function_vip_arping1
    else
      if [ $bind_time_vip1 == "Y" ];
      then
          function_remove_vip1
          bind_time_vip1="N"
      fi
    fi
    if [ x$httpcode_rip2 == "x200" ];
    then
        if [ $bind_time_vip2 == "Y" ];
        then
          function_remove_vip2
          bind_time_vip2="N"
        fi
    else
        if [ $bind_time_vip2 == "N" ];
        then
          function_bind_vip2
          function_vip_arping2
          function_restart_nginx
          bind_time_vip2="Y"
        fi
        function_vip_arping2
    fi
    sleep 5
done

在Nginx负载均衡服务器①将脚本驻留后台运行:

nohup /bin/sh ./nginx_ha1.sh 2>&1 > /dev/null &

以下代码6-8为脚本2(server2.sh),部署在Nginx负载均衡服务器②:
代码6-8

#!/bin/sh
LANG=C
date=$(date -d "today" +"%Y-%m-%d %H:%M:%S")
function_bind_vip1()
{
    /sbin/ifconfig eth0:ha1 61.1.1.3 broadcast 219.232.254.255 netmask
    255.255.255.192 up
    /sbin/route add -host 61.1.1.3 dev eth0:ha1
}
function_bind_vip2()
{
    /sbin/ifconfig eth0:ha2 61.1.1.2 broadcast 219.232.254.255 netmask
    255.255.255.192 up
    /sbin/route add -host 61.1.1.2 dev eth0:ha2
}
function_restart_nginx()
{
    kill -USR1 `cat /usr/local/webserver/nginx/nginx.pid`
}
function_remove_vip1()
{
    /sbin/ifconfig eth0:ha1 61.1.1.3 broadcast 219.232.254.255 netmask
    255.255.255.192 down
}
function_remove_vip2()
{
    /sbin/ifconfig eth0:ha2 61.1.1.2 broadcast 219.232.254.255 netmask
    255.255.255.192 down
}
function_vip_arping1()
{
    /sbin/arping -I eth0 -c 3 -s 61.1.1.3 61.1.1.1 > /dev/null 2>&1
}
function_vip_arping2()
{
    /sbin/arping -I eth0 -c 3 -s 61.1.1.2 61.1.1.1 > /dev/null 2>&1
}
bind_time_vip1="N";
bind_time_vip2="N";
while true
do
    httpcode_rip1=`/usr/bin/curl -o /dev/null -s -w %{http_code} http://61.1.1.5`
    httpcode_rip2=`/usr/bin/curl -o /dev/null -s -w %{http_code} http://61.1.1.4`
    if [ x$httpcode_rip1 == "x200" ];
    then
      if [ $bind_time_vip1 == "N" ];
      then
          function_bind_vip1
          function_vip_arping1
          function_restart_nginx
          bind_time_vip1="Y"
      fi
      function_vip_arping1
    else
      if [ $bind_time_vip1 == "Y" ];
      then
          function_remove_vip1
          bind_time_vip1="N"
      fi
    fi
    if [ x$httpcode_rip2 == "x200" ];
    then
      if [ $bind_time_vip2 == "Y" ];
      then
          function_remove_vip2
          bind_time_vip2="N"
      fi
    else
      if [ $bind_time_vip2 == "N" ];
      then
          function_bind_vip2
          function_vip_arping2
          function_restart_nginx
          bind_time_vip2="Y"
      fi
      function_vip_arping2
    fi
    sleep 5
done

在Nginx负载均衡服务器②将脚本驻留后台运行:

nohup /bin/sh ./nginx_ha2.sh 2>&1 > /dev/null &
THE END

Leave a Reply