实现nginx的高可用

一、简要介绍

nginx作为一款企业级的代理服务器,在各种企业事业单位中,均有广泛的使用,尤其是在前后端分离的项目中,nginx作为路由转发的功能是非常常用的。在一些流量比较大的项目中,为了应对高并发的场景,后端服务往往采用集群部署,这时候,就需要使用到nginx的负载均衡功能,从而避免应用节点的单节点故障问题。

那么针对nginx的单节点故障问题,我们在实际生产中又应当如何避免呢?我们可以通过nginx+keepalived的高可用集群方案来避免nginx的单节点故障问题,从而大幅度提高nginx的稳定性和可靠性。

Keepalived软件主要是实现网站、数据库、业务系统高可用性、自动切换的,主要是基于类似交换机制OSI七层模型:3(网络层)、4(传输层)、7层(应用层)来实现健康检查的,当监测到其中一台服务器宕机或者异常,能够切换到另外一台。

Keepalived软件程序主要的功能有两个:

  • 健康检测
    基于类似交换机制OSI七层模型:3(网络层:IP)、4(传输层:IP+PORT)、7层(应用层:FTP、HTTP APP)来实现健康检查;
  • VRRP漂移
    基于VRRP(虚拟路由冗余协议)路由协议来实现两台主机之间高可用,其中包括:MASTER和BACKUP,当MASTER宕机,能够自动化切换至BACKUP,从而让用户持续的访问;

下面,本文将简单介绍一下nginx+keepalived高可用集群的两种常用方案,即nginx+keepalived主从和双主模式。

二、主从模式

这种方案,使用一个VIP地址,前端使用2台机器,一台做主,一台做备,但同时只有一台机器工作,另一台备机在主机器不出现故障的时候,永远处于浪费状态,对于服务器不多的网站,该方案并不经济实惠。

网络架构图如下:

keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_服务器

2.1 架构规划

根据网络架构图,服务器规划如下:

角色

ip地址

vip地址

软件

nginx端口

OS


192.168.10.101

192.168.10.108

nginx+keepalived

80

centos 7.9


192.168.10.102

192.168.10.108

nginx+keepalived

80

centos 7.9

2.2 软件安装

2.2.1 nginx

前往nginx官方网站(http://nginx.org/en/download.html)下载最新版nginx,进行编译安装。以1.23.2为例:

# 根据实际情况安装依赖
yum install -y libxml2 libxslt libxslt-devel libxml2-devel gd gd-devel geoip-devel pcre-devel openssl-devel
# 解压并安装nginx
tar -zxvf nginx-1.23.2.tar.gz
cd nginx-1.23.2
./configure \
--prefix=/usr/local/nginx \
--with-threads \
--with-file-aio \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_xslt_module \
--with-http_image_filter_module \
--with-http_geoip_module \
--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_auth_request_module \
--with-http_random_index_module \
--with-http_degradation_module \
--with-http_slice_module \
--with-http_stub_status_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module

make

make install

本文中,我们不探讨nginx的负载均衡功能,仅仅演示nginx+keepalived的高可用性,故而以nginx静态页面来进行展示:

#设置简单页面,区分两个nginx服务器
vim /usr/local/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx! 192.168.10.101</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx! 192.168.10.102</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

分别访问两个Nginx,http://192.168.10.101,http://192.168.10.102。页面如下:

keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_nginx_02


keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_网络_03

2.2.2 keepalived

在centos7.9中,自带了keepalived安装包,可以采用yum方式安装,有其他版本需求的,可以自行下载源码安装包进行安装。

yum install -y keepalived

2.3 主从配置

2.3.1 keepalived
2.3.1.1 配置主服务器
cd /etc/keepalived
true > keepalived.conf
vim keepalived.conf

在keepalived.conf中添加以下内容:

! Configuration File for keepalived
 
############################ 全局配置 #############################
  
global_defs {
 
    # 定义管理员邮件地址,表示keepalived在发生诸如切换操作时需要发送email通知,以及email发送给哪些邮件地址,可以有多个,每行一个
	notification_email {    
        #设置报警邮件地址,可以设置多个,每行一个。 需开启本机的sendmail服务	
		137708020@qq.com
	}
    #keepalived在发生诸如切换操作时需要发送email通知地址,表示发送通知的邮件源地址是谁
	notification_email_from 137708020@qq.com
	
	#指定发送email的smtp服务器
	smtp_server 127.0.0.1
	
	#设置连接smtp server的超时时间
	smtp_connect_timeout 30
	
	#运行keepalived的机器的一个标识,通常可设为hostname。故障发生时,发邮件时显示在邮件主题中的信息。
	router_id nginx-1
}
 
 
############################ VRRPD配置 #############################
 
# 定义chk_nginx脚本,脚本执行间隔10秒,权重-10,检测nginx服务是否在运行。有很多方式,比如进程,用脚本检测等等
vrrp_script chk_nginx {  
 
    #这里通过脚本监测    
    script "/data/chk_nginx.sh"   
	
	#脚本执行间隔,每2s检测一次
    interval 2    
	
    #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5	
    weight -10     
	
    #检测连续2次失败才算确定是真失败。会用weight减少优先级(1-255之间)	
    fall 2     
	
    #检测1次成功就算成功。但不修改优先级	
    rise 1                    
}
 
#定义vrrp实例,VI_1 为虚拟路由的标示符,自己定义名称,keepalived在同一virtual_router_id中priority(0-255)最大的会成为master,也就是接管VIP,当priority最大的主机发生故障后次priority将会接管
vrrp_instance VI_1 { 
 
    #指定keepalived的角色,MASTER表示此主机是主服务器,BACKUP表示此主机是备用服务器。注意这里的state指定instance(Initial)的初始状态,就是说在配置好后,这台服务器的初始状态就是这里指定的,
	#但这里指定的不算,还是得要通过竞选通过优先级来确定。如果这里设置为MASTER,但如若他的优先级不及另外一台,那么这台在发送通告时,会发送自己的优先级,另外一台发现优先级不如自己的高,
	#那么他会就回抢占为MASTER   
    state MASTER 
	
	#指定HA监测网络的接口。与本机 IP 地址所在的网络接口相同,可通过ip addr 查看
    interface ens33
    
    #当该keepalived切换为MASTER状态时,执行下面的脚本
    notify_master /data/chk_master.sh
    #当该keepalived切换为BACKUP状态时,执行下面的脚本
    notify_backup /data/chk_backup.sh
 
    # 发送多播数据包时的源IP地址,这里注意了,这里实际上就是在哪个地址上发送VRRP通告,这个非常重要,
	#一定要选择稳定的网卡端口来发送,这里相当于heartbeat的心跳端口,如果没有设置那么就用默认的绑定的网卡的IP,也就是interface指定的IP地址    
    mcast_src_ip 192.168.10.101
	
	#虚拟路由标识,这个标识是一个数字,同一个vrrp实例使用唯一的标识。即同一vrrp_instance下,MASTER和BACKUP必须是一致的
    virtual_router_id 51    
 
    #定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP的优先级	
    priority 100
 
    #设定MASTER与BACKUP负载均衡器之间同步检查的时间间隔,单位是秒	
    advert_int 1        
 
    #设置验证类型和密码。主从必须一样
    authentication {    
	
	    #设置vrrp验证类型,主要有PASS和AH两种
        auth_type PASS           
		
		#设置vrrp验证密码,在同一个vrrp_instance下,MASTER与BACKUP必须使用相同的密码才能正常通信
        auth_pass 1111           
    }
	
	#VRRP HA 虚拟地址 如果有多个VIP,继续换行填写
	#设置VIP,它随着state变化而增加删除,当state为master的时候就添加,当state为backup的时候则删除,由优先级决定
    virtual_ipaddress {          
        192.168.10.108
    }
    
	#执行nginx检测脚本。注意这个设置不能紧挨着写在vrrp_script配置块的后面(实验中碰过的坑),否则nginx监控失效!!
	track_script {   
 
       #引用VRRP脚本,即在 vrrp_script 部分指定的名字。定期运行它们来改变优先级,并最终引发主备切换。	
	   chk_nginx                    
	}
}
2.3.1.2 配置从服务器
cd /etc/keepalived
true > keepalived.conf
vim keepalived.conf

在keepalived.conf中添加以下内容,与主服务器除了priority优先级不一样外,其他保持一致:

! Configuration File for keepalived    
  
global_defs {
	notification_email {                
		137708020@qq.com
	}
	  
	notification_email_from 137708020@qq.com
	smtp_server 127.0.0.1                    
	smtp_connect_timeout 30                 
	router_id nginx-2                 
}
  
vrrp_script chk_nginx {         
	script "/data/chk_nginx.sh"   
	interval 2                      
	weight -10                       
	fall 2                   
	rise 1                  
}
  
vrrp_instance VI_1 {            
	state BACKUP           
	interface ens33
    notify_master /data/chk_master.sh
    notify_backup /data/chk_backup.sh
	mcast_src_ip 192.168.10.102
	virtual_router_id 51        
	priority 90              
	advert_int 1               
	authentication {            
		auth_type PASS         
		auth_pass 1111          
	}
	virtual_ipaddress {        
		192.168.10.108
	}
 
	track_script {                     
	   chk_nginx                 
	}
 
}
2.3.2 检测脚本设计

在主从服务器,均创建以下检测脚本。

cd /data
#创建nginx检测脚本
vim chk_nginx.sh
###############################################
#!/bin/bash  
A=`ps -C nginx --no-header |wc -l` 
if [ $A -eq 0 ];then 
    /usr/local/nginx/sbin/nginx
    sleep 3 
    if [ `ps -C nginx --no-header |wc -l` -eq 0 ] 
    then
        systemctl stop keepalived 
    fi 
fi
###############################################
chmod +x chk_nginx.sh

2.4 启动

在主从服务器上,分别启动nginx和keepalived服务:

/usr/local/nginx/sbin/nginx 
systemctl start keepalived
#检查ip绑定情况
ip addr show ens33

2.5 验证

2.5.1 验证

分别访问主、从和vip地址:

主:

keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_nginx_04


从:

keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_优先级_05


VIP:

keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_网络_06

可以看到,访问vip地址其实就是访问了主节点。

也可以通过网卡命令查询:

ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:f0:6d:88 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.101/24 brd 192.168.10.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 192.168.10.108/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::ca30:6fa0:7f41:3eec/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
2.5.2 切换
  • nginx
    关闭主节点上的nginx服务,观察主节点的nginx是否会被自动重启。如果重启则说明chk_nginx脚本执行成功,如果nginx未能重启,则应当执行脚本中的命令关闭keepalived服务。
  • keepalived
    关闭主节点的keepalived服务,观察vip是否会绑定到从服务器上。
    重启主节点的keepalived服务,观察vip是否会绑定到主服务器上。

三、互为主从

这种方案,使用两个VIP地址,前端使用2台机器,互为主备,同时有两台机器工作,当其中一台机器出现故障,两台机器的请求转移到一台机器负担,非常适合于生产架构环境。

网络架构图如下:

keepalived nginx高可用 lvs nginx和keepalived实现nginx高可用_优先级_07

3.1 架构规划

根据网络架构图,服务器规划如下:

角色

ip地址

vip地址

软件

nginx端口

OS

主从

192.168.10.101

192.168.10.108

nginx+keepalived

80

centos 7.9

从主

192.168.10.102

192.168.10.109

nginx+keepalived

80

centos 7.9

3.2 软件安装

软件安装与前面2.2章节一模一样,此处不再赘述。

3.3 互为主从配置

3.3.1 keepalived配置

在双主模式中,大致内容与主从模式一样,需要额外添加以下内容,添加一个新的VIP,需要注意的是初始的服务器角色是反的。

3.3.1.1 配置主服务器

在原有的keepalived.conf下增加以下配置

#定义vrrp实例,VI_2 为虚拟路由的标示符,自己定义名称,keepalived在同一virtual_router_id中priority(0-255)最大的会成为master,也就是接管VIP,当priority最大的主机发生故障后次priority将会接管 
vrrp_instance VI_2 {   
  
    #指定keepalived的角色,MASTER表示此主机是主服务器,BACKUP表示此主机是备用服务器。注意这里的state指定instance(Initial)的初始状态,就是说在配置好后,这台服务器的初始状态就是这里指定的,  
    #但这里指定的不算,还是得要通过竞选通过优先级来确定。如果这里设置为MASTER,但如若他的优先级不及另外一台,那么这台在发送通告时,会发送自己的优先级,另外一台发现优先级不如自己的高,  
    #那么他会就回抢占为MASTER     
    state BACKUP   
      
    #指定HA监测网络的接口。与本机 IP 地址所在的网络接口相同,可通过ip addr 查看  
    interface ens33        
    
    #当该keepalived切换为MASTER状态时,执行下面的脚本
    notify_master /data/chk_master.sh
    #当该keepalived切换为BACKUP状态时,执行下面的脚本
    notify_backup /data/chk_backup.sh
    
    # 发送多播数据包时的源IP地址,这里注意了,这里实际上就是在哪个地址上发送VRRP通告,这个非常重要,  
    #一定要选择稳定的网卡端口来发送,这里相当于heartbeat的心跳端口,如果没有设置那么就用默认的绑定的网卡的IP,也就是interface指定的IP地址      
    mcast_src_ip 192.168.10.101
      
    #虚拟路由标识,这个标识是一个数字,同一个vrrp实例使用唯一的标识。即同一vrrp_instance下,MASTER和BACKUP必须是一致的  
    virtual_router_id 52     
  
    #定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP的优先级     
    priority 90   
  
    #设定MASTER与BACKUP负载均衡器之间同步检查的时间间隔,单位是秒     
    advert_int 1          
  
    #设置验证类型和密码。主从必须一样  
    authentication {      
      
        #设置vrrp验证类型,主要有PASS和AH两种  
        auth_type PASS             
          
        #设置vrrp验证密码,在同一个vrrp_instance下,MASTER与BACKUP必须使用相同的密码才能正常通信  
        auth_pass 1111             
    }  
      
    #VRRP HA 虚拟地址 如果有多个VIP,继续换行填写  
    #设置VIP,它随着state变化而增加删除,当state为master的时候就添加,当state为backup的时候则删除,由优先级决定  
    virtual_ipaddress {            
        192.168.10.109
    }  
      
    #执行nginx检测脚本。注意这个设置不能紧挨着写在vrrp_script配置块的后面(实验中碰过的坑),否则nginx监控失效!!  
    track_script {     
  
       #引用VRRP脚本,即在 vrrp_script 部分指定的名字。定期运行它们来改变优先级,并最终引发主备切换。 
       chk_nginx                      
    }  
}
3.3.1.2 配置从服务器

在原有的keepalived.conf下增加以下配置

vrrp_instance VI_2 {
        state MASTER
        interface ens33
        notify_master /data/chk_master.sh
        notify_backup /data/chk_backup.sh
        mcast_src_ip 192.168.10.102
        virtual_router_id 52
        priority 100
        advert_int 1
        authentication {
                auth_type PASS
                auth_pass 1111
        }
        virtual_ipaddress {
                192.168.10.109
        }

        track_script {
           chk_nginx
        }
}
3.3.2 检测脚本设计

在主从服务器,均创建以下检测脚本。

cd /data
#创建nginx检测脚本
vim chk_nginx.sh
###############################################
#!/bin/bash
counter=$(ps -ef|grep nginx | grep -v 'grep'|wc -l)
if [ "${counter}" = "0" ]; then
    /usr/local/nginx/sbin/nginx || true
    sleep 2
    counter=$(ps -ef|grep nginx | grep -v 'grep'|wc -l)
    if [ "${counter}" = "0" ]; then
        systemctl stop keepalived
    fi
fi
###############################################
chmod +x chk_nginx.sh

3.4 启动

在主从服务器上,分别启动nginx和keepalived服务:

/usr/local/nginx/sbin/nginx 
systemctl start keepalived
#检查ip绑定情况
ip addr show ens33

3.5 验证

分别访问主、从和两个vip地址,以及分别停止两个节点的nginx和keepalived服务进行验证。不再赘述。

四、附加脚本

  • nginx_rsync.sh

执行方式:后台,nohup sh nginx_rsync.sh 该脚本只有一台主机在后台执行,此外执行改脚本需要提前配置ssh互信免密登录。

#!/bin/bash
ip_address="192.168.10.101"

inotify_cmd="inotifywait -mrq -e modify,create,attrib,move,delete /usr/local/nginx/"
rsync_cmd="rsync -azH --delete /usr/local/nginx/ root@${ip_address}:/usr/local/nginx/"

$inotify_cmd | while read DIRECTORY EVENT FILE
do
    if [ $(pgrep rsync | wc -l) -le 0 ];then
        $rsync_cmd
        ssh root@${ip_address} "/usr/local/nginx/sbin/nginx -t"
        if [ $? -eq 0 ];then
            ssh root@${ip_address} "/usr/local/nginx/sbin/nginx -s reload"
        fi        
    fi
done

PS:本文件同步脚本引用自

  • chk_master.sh

在keepalived配置文件中配置,当发生主从切换时被调用执行,发送的内容和发送方式根据实际需要进行调整。

#!/bin/bash
time=$(date +%Y-%m-%d-%H-%M)
echo “$time nginx-2已故障停机,VIP飘逸至nginx-1!”|mail -s nginx VIP飘逸提醒 137708020@qq.com
  • chk_backup.sh
#!/bin/bash
time=$(date +%Y-%m-%d-%H-%M)
echo “$time nginx-1已故障停机,VIP飘逸至nginx-2!”|mail -s nginx VIP飘逸提醒 137708020@qq.com
  • chk_nginx.sh

nginx健康检查,在keepalived配置文件中配置。

#!/bin/bash  
A=`ps -C nginx --no-header |wc -l` 
if [ $A -eq 0 ];then 
    /usr/local/nginx/sbin/nginx
    sleep 3 
    if [ `ps -C nginx --no-header |wc -l` -eq 0 ] 
    then
        systemctl stop keepalived 
    fi 
fi