Nginx + Keepalived 构建高可用的负载层方法,nginxkeepalived


本文基于如下的拓扑图:

                   +-------------+
                   |    uplink   |
                   +-------------+
                          |
                          +
    MASTER            keep|alived         BACKUP
 192.168.1.11         192.168.1.10      192.168.1.12
+-------------+    +-------------+    +-------------+
|  Nginx VM1  |----|  virtualIP  |----|  Nginx VM2  |
+-------------+    +-------------+    +-------------+
                          |
       +------------------+------------------+
       |                  |                  |
+-------------+    +-------------+    +-------------+
|    web01    |    |    web02    |    |    web03    |
+-------------+    +-------------+    +-------------+

一共配置两台服务器:

第一台服务器:Nginx vm1 和 keepalived MASTER; 第二台服务器:Nginx vm2 和 keepalived BACKUP;

一、准备工作

1、准备两台独立工作的 Nginx 系统

在我这里,安装两台 Nginx 的虚拟机IP地址分别是:

Nginx VM1:192.168.61.11:80 Nginx VM2:192.168.61.12:80

nginx没有什么可配置的,因为它与keepalived并没有联系。但记住,2台nginx服务器上的配置应该是完全一样的(rsync同步),这样才能做到对用户透明,nginx.conf 里面的 server_name 尽量使用域名来代替,然后dns解析这个域名到虚拟IP 192.168.1.10。

还有一点需要特别需要注意的是:Nginx一定要监听到所访问的地址。

附:Nginx服务器的安装配置请参考:

Nginx 服务器安装与配置
Nginx 虚拟主机配置的三种方式(一)(基于IP)
Nginx 虚拟主机配置的三种方式(二)(基于端口)
Nginx 虚拟主机配置的三种方式(三)(基于域名)

2、在已安装好 Nginx 的两个虚拟机上分别安装 Keepalived

我的环境是CentOS 7.0 X86_64,直接通过yum方式安装最简单:

[root@bogon /]# yum install -y keepalived
[root@bogon /]# keepalived -v
[root@bogon /]# Keepalived v1.2.13 (08/03,2017)

附:源码安装:Keepalived服务器的安装配置请参考:Keepalived 服务器安装与配置

3、编写 nginx 监控脚本

该脚本检测 ngnix 的运行状态,并在 nginx 进程不存在时尝试重新启动 ngnix,如果启动失败则停止 keepalived,准备让其它机器接管。

[root@bogon /]# vim /etc/keepalived/check_nginx.sh
#!/bin/sh
if [ $(ps -C nginx --no-header | wc -l) -eq 0 ]; then
    /usr/local/nginx/sbin/nginx
fi

sleep 2
if [ $(ps -C nginx --no-header | wc -l) -eq 0 ]; then
    service keepalived stop
fi

二、Nginx + Keepalived 最简配置

1、请再次确认前提

(首先,为了保证不会出现额外的问题,请首先关闭防火墙,当然正式环境里面,防火墙不能关闭)

外网进行 Nginx 访问的浮动IP:192.168.1.10; 我们将192.168.1.11这台服务器上运行的 Nginx 作为主要的 Nginx,其上的keepalived 服务我们设置成 Master 方式; 我们将192.168.1.12这台服务器上运行的Nginx作为备用的Nginx服务,其上的keepalived 服务我们设置为 Backup 方式。
2、设置192.168.1.11上的MASTER

我们先来看看192.168.1.11上的原始IP信息:

[root@localhost ~]# ifconfig
ens33: flags=4163  mtu 1500
        inet 192.168.1.11  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::2a8d:be6:a4a8:ea0  prefixlen 64  scopeid 0x20
        ether 00:0c:29:1a:76:7e  txqueuelen 1000  (Ethernet)
        RX packets 70  bytes 11009 (10.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 73  bytes 11927 (11.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1  (Local Loopback)
        RX packets 72  bytes 6252 (6.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 72  bytes 6252 (6.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

注意,这个11机器上的网卡设备号是ens33,而不是eth0,这个参数我们将在配置keepalived 的时候使用到。

下面是11上 keepalived 的最简配置:

! Configuration File for keepalived
# global setting , notify email setting
global_defs {
    #存在于同一个网段中,一组keepalived的各个节点都有不同的名字
    #在全局设置中,我们还可以设置管理员的email信息等。
    router_id LVS_V1
}

#这个是我们在上一小结讲到的nginx检查脚本,我们保存在这个文件中(注意文件权限)
vrrp_script chknginx {
    script "/etc/keepalived/check_nginx.sh"
    #每10秒钟,检查一次
    interval 10
}

#keepalived实例设置,是最重要的设置信息
vrrp_instance VI_1 {
    #state状态MASTER表示是主要工作节点。
    #一个keepalived组中,最多只有一个MASTER节点,当然也可以没有
    state MASTER
    #实例所绑定的网卡设备,我的网卡设备是ens33。您按照您自己的来
    interface ens33
    #同一个keepalived组,节点的设置必须一样,这样才会被识别
    virtual_router_id 52
    #节点优先级,BACKUP的优先级一定要比MASTER的优先级低
    priority 100
    #组播信息发送间隔,两个节点设置必须一样
    advert_int 1
    #实际的ens33上的固定ip地址
    mcast_src_ip 192.168.1.11
    #验证信息,只有验证信息相同,才能被加入到一个组中。
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    #虚拟地址和绑定的端口,如果有多个,就绑定多个
    #dev 是指定浮动IP要绑定的网卡设备号
    virtual_ipaddress {
        192.168.1.10 dev ens33
    }

    #设置的检查脚本
    #关联上方的“vrrp_script chknginx”
    track_script {
        chknginx
    }
}
3、设置192.168.1.12上的BACKUP

再来看看192.168.1.12这个备用节点上 keepalived 的设置:

! Configuration File for keepalived
# global setting , notify email setting
global_defs {
    #这里和master节点不同
    router_id LVS_V2
}

#check nginx
vrrp_script chknginx {
    script "/etc/keepalived/check_nginx.sh"
    interval 10
}

# instance setting
vrrp_instance VI_1 {
    # 这里和Master节点不一样
    state BACKUP
    interface ens33
    # 这里一定是一样的
    virtual_router_id 52
    # 这里的优先级比Master节点低
    priority 99
    advert_int 1
    # 这里和Master节点不一样
    mcast_src_ip=192.168.1.12
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.10 dev ens33
    }

    track_script {
        chknginx
    }
}
4、启动主节点和备用节点

以上配置中请注意几个关键点:

注意nginx状态检查的脚本的位置,根据自己创建文件的位置不一样,脚本检查的指定位置也不一样; 注意优先级,MASTER节点的优先级一定要高于所有的BACKUP节点; 注意局域网的组播地址,一定要可用。局域网内所有keepalived节点都是利用组播方式寻找对方; 谁说BACKUP节点只能有一个!? 最后,keepalived一定要注册成服务形式,您可以想象上面所有脚本、配置、命令如果重启后再来一次,会是什么情况。

接下来,我们要开始启动 Master 节点和 Backup 节点了,为了准确的查看日志状态,您需要观察系统日志。系统日志所在的位置:

tail -f /var/log/messages

先启动Master节点:

[root@localhost ~]# service keepalived start

再启动Backup节点:

[root@localhost ~]# service keepalived start

如果设置和启动都是成功的,您不会在日志信息中收到任何的keepalived报错信息。接下来您就可以使用192.168.1.10这个IP访问Nginx了:

这里写图片描述

另外,这个绑定在192.168.1.11上的浮动ip:192.168.1.10,您通过ipconfig命令一般是看不到的,要使用ip addr命令进行查看:

# 使用ip命令配置的地址,ifconfig查看不了
[root@bogon system]# ip a|grep ens33
2: ens33:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.1.11/24 brd 192.168.1.255 scope global dynamic ens33
    inet 192.168.1.12/32 scope global ens33

为了试验,我们主动停止 Master 节点上的 keepalived 服务(注意,杀 Nginx 进程不起作用,因为我们的检查脚本会试图重新启动 Nginx 进程),接下来我们可以看到浮动IP漂移到了12备机上:

这里写图片描述

三、Nginx + Keepalived非抢占模式

通过上面的详细介绍,相信您对Nginx + Keepalived的安装方式有了一个明确的理解。keepalived的切换可以是自动的,但是却做不到毫秒级别,他怎么都需要几秒钟的时间进行切换。

这就有一个问题,虽然在主节点出现问题我们转向备份节点时,这个延时无可避免,但是在我们修复主节点后,实际上并没有必要再马上做一次切换,所以 Keepalived 提供了一种非抢占模式,来满足这个要求。

下面我们就来介绍一下Keepalived的非抢占模式的配置(无MASTER节点,全部依据优先级确定哪个节点进行工作):

1、原来主节点的配置改动
! Configuration File for keepalived
# global setting , notify email setting
global_defs {
    router_id LVS_V1
}

vrrp_script chknginx {
    script "/etc/keepalived/check_nginx.sh"
    interval 10
    # 一旦节点失效,节点的优先级就减少2
    # 有多少个keepalived节点,就填写多少数量。
    # 这样保证这个节点的优先级比其他节点都低
    weight -2
    # fall 表示多少次检查失败,就算节点失效。默认1
    #fall 1
}

vrrp_instance VI_1 {
    #state状态都是BACKUP表示是主要工作节点。
    state BACKUP
    interface ens33
    virtual_router_id 52
    # 这个关键配置项,设置为“非抢占”模式
    nopreempt
    # 每个节点的优先级一定要不一样
    priority 100
    advert_int 1
    mcast_src_ip=192.168.1.11
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    #虚拟地址和绑定的端口,如果有多个,就绑定多个
    #dev 是指定浮动IP要绑定的网卡设备号
    virtual_ipaddress {
        192.168.1.10 dev ens33
    }

    #设置的检查脚本
    #关联上方的“vrrp_script chknginx”
    track_script {
        chknginx
    }
}

原来的主节点设置更改完成。

2、原来备份节点的配置改动

加入“非抢占”模式的关键字、更改一个确定的优先级,设置检查失败后优先级的递减量,就行了。


附、配置过程中的问题

1、Nginx为什么会停止响应呢?在我的工作经验中,无非有以下几种情况

Nginx的所有进程被强行终止(或管理进程);
这种情况,是我们需要检查和切换的。无论什么情况下进程被终止了,如果它不能重启,我们就要切换到备机。

Nginx日志盘的挂载点崩溃或者磁盘写满;
这个也是我们需要检查和切换的。

Nginx已经达到设置的最大连接数,暂时停止响应;
这种情况下,我们不能进行备机切换,因为通过VIP:192.168.61.100连接过来的用户请求比较多(在我们优化参数后,可以达到65535 / 4的数量),一旦我们进行备机切换,这些用户请求将全部异常。这个问题的解决需要靠增加负载机器,而不是主备切换。

Nginx物理机异常关机。
这个肯定是需要进行检查和切换的。

2、nginx监控脚本
#!/bin/sh
if [ $(ps -C nginx --no-header | wc -l) -eq 0 ]; then
    /usr/local/nginx/sbin/nginx
fi

sleep 2
if [ $(ps -C nginx --no-header | wc -l) -eq 0 ]; then
    service keepalived stop
fi

整个脚本的解释:

第一个判断说明的是,如果当前nginx的进程数量 == 0,那么执行nginx的启动命令,试图重新启动nginx;接下来等待2秒(这是为了给nginx一定的启动时间),然后再次查看Nginx的进程数量,如果仍然 == 0,那么停止这台机器的keepalived服务,以便备用的Keepalived节点检查到Keepalived已经停止这个事件,并将浮动IP切换到备用服务器上。

注意,这段脚本是和我机器上的Nginx安装路径、Keepalived服务的状态有关的,您如果要用的话,请进行相应的更改。

然后具体讲解一下每个命令的含义:

我们大致讲解一下“ps -C nginx –no-header | wc -l”这个命令:

ps 这个命令用来进行linux中进程相关的查询,-C 意思是按照进程名称进行查询。查询出来后的结果如下:
[root@bogon /]# ps -C nginx
   PID TTY          TIME CMD
  3178 ?        00:00:00 nginx
  3180 ?        00:00:00 nginx
  3181 ?        00:00:00 nginx
  3182 ?        00:00:00 nginx
  3183 ?        00:00:00 nginx
如果要去掉统计出来的结果表的头部,那么要使用 –no-header 参数,加上参数后,查询结果如下:
[root@bogon /]# ps -C nginx --no-header
  3178 ?        00:00:00 nginx
  3180 ?        00:00:00 nginx
  3181 ?        00:00:00 nginx
  3182 ?        00:00:00 nginx
  3183 ?        00:00:00 nginx
“|”,这是Linux中的管道流命令,将上一个命令的输出结果作为下一个命令的输入。 wc 统计命令,-l 参数,代表按行数进行统计。所以整个命令的输出结果为:
[root@bogon /]# ps -C nginx --no-header | wc -l
5
3、配置选项说明

global_defs

notification_email : keepalived在发生诸如切换操作时需要发送email通知地址,后面的 smtp_server 相比也都知道是邮件服务器地址。也可以通过其它方式报警,毕竟邮件不是实时通知的; router_id : 机器标识,通常可设为hostname。故障发生时,邮件通知会用到。

vrrp_instance

state : 指定instance(Initial)的初始状态,就是说在配置好后,这台服务器的初始状态就是这里指定的,但这里指定的不算,还是得要通过竞选通过优先级来确定。如果这里设置为MASTER,但如若他的优先级不及另外一台,那么这台在发送通告时,会发送自己的优先级,另外一台发现优先级不如自己的高,那么他会就回抢占为MASTER; interface : 实例绑定的网卡,因为在配置虚拟IP的时候必须是在已有的网卡上添加的; mcast_src_ip : 发送多播数据包时的源IP地址,这里注意了,这里实际上就是在那个地址上发送VRRP通告,这个非常重要,一定要选择稳定的网卡端口来发送,这里相当于heartbeat的心跳端口,如果没有设置那么就用默认的绑定的网卡的IP,也就是interface指定的IP地址; virtual_router_id : 这里设置VRID,这里非常重要,相同的VRID为一个组,他将决定多播的MAC地址; priority : 设置本节点的优先级,优先级高的为master; advert_int : 检查间隔,默认为1秒。这就是VRRP的定时器,MASTER每隔这样一个时间间隔,就会发送一个advertisement报文以通知组内其他路由器自己工作正常; authentication : 定义认证方式和密码,主从必须一样; virtual_ipaddress : 这里设置的就是VIP,也就是虚拟IP地址,他随着state的变化而增加删除,当state为master的时候就添加,当state为backup的时候删除,这里主要是有优先级来决定的,和state设置的值没有多大关系,这里可以设置多个IP地址; track_script : 引用VRRP脚本,即在 vrrp_script 部分指定的名字。定期运行它们来改变优先级,并最终引发主备切换。

vrrp_script
告诉 keepalived 在什么情况下切换,所以尤为重要。可以有多个 vrrp_script

script : 自己写的检测脚本。也可以是一行命令如killall -0 nginx; interval 2 : 每2s检测一次; weight -5 : 检测失败(脚本返回非0)则优先级 -5; fall 2 : 检测连续 2 次失败才算确定是真失败。会用weight减少优先级(1-255之间); rise 1 : 检测 1 次成功就算成功。但不修改优先级。

这里要提示一下script一般有2种写法:

通过脚本执行的返回结果,改变优先级,keepalived继续发送通告消息,backup比较优先级再决定; 脚本里面检测到异常,直接关闭keepalived进程,backup机器接收不到advertisement会抢占IP。

上文 vrrp_script 配置部分,killall -0 nginx属于第1种情况,/etc/keepalived/check_nginx.sh属于第2种情况(脚本中关闭keepalived)。个人更倾向于通过shell脚本判断,但有异常时exit 1,正常退出exit 0,然后keepalived根据动态调整的 vrrp_instance 优先级选举决定是否抢占VIP:

如果脚本执行结果为0,并且weight配置的值大于0,则优先级相应的增加; 如果脚本执行结果非0,并且weight配置的值小于0,则优先级相应的减少。

其他情况,原本配置的优先级不变,即配置文件中priority对应的值。

提示:

优先级不会不断的提高或者降低; 可以编写多个检测脚本并为每个检测脚本设置不同的weight(在配置中列出就行); 不管提高优先级还是降低优先级,最终优先级的范围是在[1,254],不会出现优先级小于等于0或者优先级大于等于255的情况; 在MASTER节点的 vrrp_instance 中 配置 nopreempt ,当它异常恢复后,即使它 prio 更高也不会抢占,这样可以避免正常情况下做无谓的切换。

以上可以做到利用脚本检测业务进程的状态,并动态调整优先级从而实现主备切换。

配置结束

在默认的keepalive.conf里面还有 virtual_server,real_server 这样的配置,我们这用不到,它是为lvs准备的。 notify 可以定义在切换成MASTER或BACKUP时执行的脚本,如有需求请自行google。

相关内容