10.9. Keepalived实现基于HTTPD的高可用系统

10.9.1. Keepalived高可用集群环境部署说明

主机名

主机IP地址

集群角色

集群服务

MySQL VIP

keepalived-master

192.168.0.128

Master(主节点)

HTTPD

192.168.0.130

keepalived-backup

192.168.0.129

Backup(备用节点)

HTTP

192.168.0.130

10.9.2. 环境准备

keepalived-masterkeepalived-backup上安装httpd服务。

yum -y install httpd
echo "<h1> hello hujianli web1<h1>" > /var/www/html/index.html
systemctl start httpd

systemctl disable firewalld.service
systemctl stop firewalld.service

检查http安装后的状态。

[root@keepalived-master ~]# curl 127.0.0.1
<h1> hello hujianli web1<h1>
[root@keepalived-backup ~]# curl 127.0.0.1
<h1> hello hujianli web1<h1>

10.9.3. keepalived_master

/etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
    notification_email {
        root@localhost
    }
    notification_email_from keepalived@localhost
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    script_user root
    enable_script_security
    route_id httpd_keep
}
vrrp_script chk_httpd
{
    script  "/usr/bin/killall -0 httpd"
    interval 5
}

vrrp_instance VI_1 {
    state MASTER
    interface ens32
    virtual_router_id 151
    priority 100
    nopreempt
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    notify_master "/etc/keepalived/master.sh "
    notify_backup "/etc/keepalived/backup.sh"
    notify_fault "/etc/keepalived/fault.sh"
    track_script {
        chk_httpd
    }
    virtual_ipaddress {
        192.168.0.130/24
    }

}

/etc/keepalived/master.sh

#!/bin/bash
LOGFILE=/var/log/keepalived-mysql-state.log
echo  "[Master]"  >>  $LOGFILE
date  >>  $LOGFILE

/etc/keepalived/backup.sh

#!/bin/bash
LOGFILE=/var/log/keepalived-mysql-state.log
echo  "[Backup]"  >>  $LOGFILE
date  >>  $LOGFILE

/etc/keepalived/fault.sh

#!/bin/bash
LOGFILE=/var/log/keepalived-mysql-state.log
echo  "[FAULT]"  >>  $LOGFILE
date  >>  $LOGFILE

10.9.4. keepalived_backup

keepalived-backup节点上的keepalived.conf配置文件内容与keepalived-master节点上的基本相同, 需要修改的地方有两个。

将“state MASTER”更改为“state BACKUP”。
将priority 100更改为一个较小的值,这里改为“priority 80”。

将配置好的 keepalived.conf文件及master.shbackup.shfault.sh三个文件一起复制到keepalived-backup 备用节点对应的路径下,

Keepalived启动过程分析

主机

[root@keepalived-master keepalived]# ip a
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:6e:3d:f6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.128/24 brd 192.168.0.255 scope global noprefixroute dynamic ens32
       valid_lft 84056sec preferred_lft 84056sec
    inet 192.168.0.130/24 scope global secondary ens32
       valid_lft forever preferred_lft forever
    inet6 fe80::14d7:407e:aeb6:6a42/64 scope link tentative noprefixroute dadfailed
       valid_lft forever preferred_lft forever
    inet6 fe80::44c2:32ba:d50e:44c3/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@keepalived-master keepalived]# cat /var/log/keepalived-mysql-state.log
[Master]
2020 03 28 星期六 13:42:07 CST

备机

[root@keepalived-backup keepalived]# cat /var/log/keepalived-mysql-state.log
[Backup]
2020 03 28 星期六 13:42:11 CST

在主机上停止httpd

[root@keepalived-master keepalived]# cat /var/log/keepalived-mysql-state.log
[Master]
2020 03 28 星期六 14:36:03 CST
[root@keepalived-master keepalived]# systemctl stop httpd


#### 主机进入fault的状态
[root@keepalived-master keepalived]# cat /var/log/keepalived-mysql-state.log
[Master]
2020 03 28 星期六 14:36:03 CST
[Fault]
2020 03 28 星期六 14:36:34 CST

备机切换成主机

[root@keepalived-backup keepalived]# ip a
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:f6:8a:13 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.129/24 brd 192.168.0.255 scope global noprefixroute dynamic ens32
       valid_lft 81044sec preferred_lft 81044sec
    inet 192.168.0.130/24 scope global secondary ens32
       valid_lft forever preferred_lft forever
    inet6 fe80::14d7:407e:aeb6:6a42/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@keepalived-backup keepalived]# cat /var/log/keepalived-mysql-state.log
[Backup]
2020 03 28 星期六 14:36:08 CST
[Master]
2020 03 28 星期六 14:36:35 CST

主机上启动httpd服务后,状态立马变成backup状态

[root@keepalived-master keepalived]# systemctl start httpd

日志信息

Mar 28 14:38:54 keepalived-master systemd: Starting The Apache HTTP Server...
Mar 28 14:38:58 keepalived-master Keepalived_vrrp[11022]: VRRP_Script(chk_httpd) succeeded
Mar 28 14:38:59 keepalived-master Keepalived_vrrp[11022]: VRRP_Instance(VI_1) Entering BACKUP STATE
Mar 28 14:39:01 keepalived-master httpd: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::44c2:32ba:d50e:44c3.
Set the 'ServerName' directive globally to suppress this messageMar 28 14:39:03 keepalived-master systemd: Started The Apache HTTP Server.
Mar 28 14:40:01 keepalived-master systemd: Started Session 23 of user root.

Keepalived配置中的一个通知机制,也是Keepalived包含的4种状态。下面介绍每个选项的含义。

notify_master:指定当Keepalived进入Master状态时要执行的脚本,这个脚本可以是一个状态报警脚本,也可以是一个服务管理脚本。Keepalived允许脚本传入参数,因此灵活性很强。

notify_backup:指定当Keepalived进入Backup状态时要执行的脚本,同理,这个脚本可以是一个状态报警脚本,也可以是一个服务管理脚本。

notify_fault:指定当Keepalived进入Fault状态时要执行的脚本,脚本功能与前两个类似。

notify_stop:指定当Keepalived程序终止时需要执行的脚本。

10.9.5. 通过vrrp_script实现对集群资源的监控

1.通过killall命令监控服务运行状态

这里要用到的信号为0,代号为0的信号并不表示要关闭某个程序,而表示对程序(进程)的运行状态进行监控, 如果发现进程关闭或其他异常,将返回状态码1,反之,如果发现进程运行正常,将返回状态码0。vrrp_script模块正是利用了killall命令的这个特性,变相地实现了对服务运行状态的监控。下面看一个实例。

vrrp_script check_mysqld {
      script  "killall  -0  mysqld"
      interval  2
      }
  track_script {
      check_mysqld
      }

rrp_script模块其实并不关注监控脚本或监控命令是如何实现的,它仅仅通过监控脚本的返回状态码来识别集群服务是否正常,如果返回的状态码为 0,那么就认为服务正常,如果返回的状态码为 1,则认为服务故障。

2.检测端口运行状态

检测端口的运行状态,也是最常见的服务监控方式。在Keepalived的vrrp_script模块中可以通过如下方式对本机的端口进行检测。

    vrrp_script check_httpd {
        script "</dev/tcp/127.0.0.1/80"
        interval  2

    vrrp_script check_mysqld {
        script  "killall  -0  mysqld"
        interval  2
        }
    track_script {
        check_mysqld
        }
在这个例子中,定义了一个服务监控模块check_mysqld,其采用的监控方式是通过“killall-0 mysqld”,其中“interval”选项用于设置检查的时间间隔,即2秒钟执行一次检测。

在mysql服务运行正常的情况下,通过killall命令检测的结果如下。


    [root@keepalived-master ~]# killall -0 mysqld
    [root@keepalived-master ~]# echo $?
    0
这里通过“echo $?”方式显示了上个命令返回的状态码,mysql服务运行正常,因此返回的状态码为0,此时check_mysqld模块将返回服务检测正常的提示。接着将mysql服务关闭,再次执行检测,结果如下。


    [root@keepalived-master ~]#   killall -0 mysqld
    mysqld:  no  process  killed
    [root@keepalived-master ~]# echo $?
    1
由于mysql服务被关闭,因此返回的状态码为1,此时check_mysqld模块将返回服务检测失败的提示。然后根据vrrp_script模块中设定的“weight”值重新设置Keepalived主、备节点的优先级,进而引发主、备节点发生切换。

从这个过程可以看到,vrrp_script模块其实并不关注监控脚本或监控命令是如何实现的,它仅仅通过监控脚本的返回状态码来识别集群服务是否正常,如果返回的状态码为 0,那么就认为服务正常,如果返回的状态码为 1,则认为服务故障。明白了这个原理之后,在进行自定义监控脚本的时候,只需按照这个原则来编写即可。

2.检测端口运行状态

检测端口的运行状态,也是最常见的服务监控方式。在Keepalived的vrrp_script模块中可以通过如下方式对本机的端口进行检测。


    vrrp_script check_httpd {
        script "</dev/tcp/127.0.0.1/80"
        interval  2
        fall    2
        rise    1
        }
    track_script {
        check_httpd
        }

其中,“fall”选项表示检测到失败的最大次数。也就是说,如果请求失败两次,就认为此节点资源发生故障,将进行切换操作;“rise”表示如果请求一次成功,就认为此节点资源恢复正常。

3.通过shell语句进行状态监控

在Keepalived的vrrp_script模块中甚至可以直接引用shell语句进行状态监控。

vrrp_script chk_httpd {
    script "if [ -f /var/run/httpd/httpd.pid ]; then exit 0; else exit 1; fi"
    interval  2
    fall    1
    rise    1
    }
track_script {
    chk_httpd
    }

4.通过脚本进行服务状态监控

这是最常见的监控方式,其监控过程类似于Nagios的执行方式。不同的是,这里只有0、1两种返回状态。

vrrp_script chk_mysqld {
    script "/etc/keepalived/check_mysqld.sh"
    interval  2
    }
    track_script {
    chk_mysqld
    }

check_mysqld.sh的内容如下:

#!/bin/bash
MYSQL=/usr/bin/mysql
MYSQL_HOST=localhost
MYSQL_USER=root
MYSQL_PASSWORD='xxxxxx'
$MYSQL -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASSWORD -e "show status;" > /dev/null 2>&1
if  [  $?  =  0  ]  ;then
    MYSQL_STATUS=0
else
    MYSQL_STATUS=1
fi
    exit $MYSQL_STATUS

10.9.6. Keepalived集群中Master和Backup角色选举策略

在Keepalived集群中,其实并没有严格意义上的主、备节点,虽然可以在Keepalived配置文件中设置state选项为MASTER状态,但是这并不意味着此节点一直就是MASTER角色。控制节点角色的是Keepalived配置文件中的priority值,但它并不控制所有节点的角色,另一个能改变节点角色的是在vrrp_script模块中设置的weight值,这两个选项对应的都是一个整数值,其中weight值可以是个负整数,一个节点在集群中的角色就是通过这两个值的大小决定的。

在一个一主多备的Keepalived集群中,priority值最大的将成为集群中的MASTER节点,而其他都是BACKUP节点。在MASTER节点发生故障后,BACKUP节点之间将进行“民主选举”,通过对节点优先级值priority和weight的计算,选出新的MASTER节点接管集群服务。

在vrrp_script模块中,如果不设置weight选项值,那么集群优先级的选择将由Keepalived配置文件中的priority值决定,而在需要对集群中优先级进行灵活控制时,可以通过在vrrp_script模块中设置weight值来实现。下面列举一个实例来具体说明。

假定由A和B两个节点组成的Keepalived集群,在A节点keepalived.conf文件中,设置priority值为100,而在B节点keepalived.conf文件中,设置priority值为80,并且A、B两个节点都使用了vrrp_script模块来监控MySQL服务,同时都设置weight值为10,那么将会发生如下情况。

在两节点都启动Keepalived服务后,正常情况是A节点将成为集群中的MASTER节点,而B自动成为BACKUP节点,此时将A节点的MySQL服务关闭,通过查看日志发现,并没有出现B节点接管A节点的日志,B节点仍然处于BACKUP状态,而A节点依旧处于MASTER状态,在这种情况下整个HA集群将失去意义。

下面分析产生这种情况的原因。这也就是Keepalived集群中主、备角色选举策略的问题。下面总结在Keepalived中使用vrrp_script模块时整个集群角色的选举算法,由于weight值可以是正数也可以是负数,因此,要分两种情况进行说明。

1.weight值为正数时

在vrrp_script中指定的脚本如果检测成功,那么MASTER节点的权值将是weight值与priority值之和;如果脚本检测失败,那么MASTER节点的权值保持为priority值,因此切换策略为:

·MASTER节点vrrp_script脚本检测失败时,如果MASTER节点priority值小于BACKUP节点weight值与priority值之和,将发生主、备切换。

·MASTER节点vrrp_script脚本检测成功时,如果MASTER节点weight值与priority值之和大于BACKUP节点weight值与priority值之和,主节点依然为主节点,不发生切换。

2.weight值为负数时

在vrrp_script中指定的脚本如果检测成功,那么MASTER节点的权值仍为priority值,当脚本检测失败时,MASTER节点的权值将是priority值与weight值之差,因此切换策略为:

·MASTER节点vrrp_script脚本检测失败时,如果MASTER节点priority值与weight值之差小于BACKUP节点priority值,将发生主、备切换。

·MASTER节点vrrp_script脚本检测成功时,如果MASTER节点priority值大于BACKUP节点priority值时,主节点依然为主节点,不发生切换。

在熟悉了Keepalived主、备角色的选举策略后,再来分析一下前面的那个实例。由于A、B两个节点设置的weight值都为10,因此符合选举策略的第一种,在A节点停止MySQL服务后,A节点的脚本检测将失败,此时A节点的权值将保持为A节点上设置的priority值,即为100,而B节点的权值将变为weight值与priority值之和,也就是90(10+80),这样就出现了A节点权值仍然大于B节点权值的情况,因此不会发生主、备切换。

对于weight值的设置,有一个简单的标准,即weight值的绝对值要大于MASTER和BACKUP节点priority值之差。对于上面A、B两个节点的例子,只要设置weight值大于20即可保证集群正常运行和切换。由此可见,对于weight值的设置要非常谨慎,如果设置不好,主节点发生故障时将导致集群角色选举失败,使集群陷于瘫痪状态。