Keepalived
关于 Keepalived 的详细介绍可以参考:Keepalived Introduction
Keepalived 是一个用于负载均衡和高可用的路由软件。
其负载均衡(Load balancing)的特性依赖于 Linux 虚拟服务器(LVS)的 IPVS 内核模块,提供了 Layer 4 负载均衡器(TCP 层级,Layer 7 是 HTTP 层级,即计算机网络中的OSI 七层网络模型与 TCP/IP 四层网络模型)。
Keepalived 实现了虚拟冗余路由协议(VRRP, Virtual Redundancy Routing Protoco),VRRP 是路由故障切换(failover)的基础。
简单来说,Keepalived 主要提供两种功能:
- 依赖 IPVS 实现服务器的健康检查;
- 实现 VRRPv2 协议来处理路由的故障切换。
我们接下来会用个简单的配置来描述后者的工作原理:
在 haproxy-master 机器上:
vrrp_script chk_haproxy {
script "killall -0 haproxy" # verify haproxy's pid existance
interval 2 # check every 2 seconds
weight -2 # if check failed, priority will minus 2
}
vrrp_instance VI_1 {
state MASTER # Start-up default state
interface ens18 # Binding interface
virtual_router_id 51 # VRRP VRID(0-255), for distinguish vrrp's multicast
priority 105 # VRRP PRIO
virtual_ipaddress { # VIP, virtual ip
192.168.0.146
}
track_script { # Scripts state we monitor
chk_haproxy
}
}
在 haproxy-backup 机器上:
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 2
weight -2
}
vrrp_instance VI_1 {
state BACKUP
interface ens18
virtual_router_id 51
priority 100
virtual_ipaddress {
192.168.0.146
}
track_script {
chk_haproxy
}
}
我们为两台机器(master、backup)安装了 Keepalived 服务并设定了上述配置。
可以发现,我们绑定了一个虚拟 IP (VIP, virtual ip): 192.168.0.146,在 haproxy-master + haproxy-backup 上用 Keepalived 组成了一个集群。在集群初始化的时候,haproxy-master 机器的 <state>
被初始化为 MASTER。
间隔 2 seconds(<interval>
) 会定时执行 <script>
脚本 ,每个<vrrp_instance>
会记录脚本的 exit code。
关于<weight>
参数的使用:
- 检测失败,并且 weight 为正值:无操作
- 检测失败,并且 weight 为负值:priority = priority - abs(weight)
- 检测成功,并且 weight 为正值:priority = priority + weight
- 检测成功,并且 weight 为负值:无操作
weight 默认值为 0,对此如果感到迷惑可以参考:HAProxy github code
故障切换工作流程:
- 当前的 MASTER 节点
<script>
脚本检测失败后,如果“当前 MASTER 节点的 priority” < “当前 BACKUP 节点的 priority” 时,会发生路由故障切换。 - 当前的 MASTER 节点脚本检测成功,无论 priority 是大是小,不会做故障切换。
其中有几处地方需要注意:
- 一个 Keepalived 服务中可以有个 0 个或者多个 vrrp_instance
- 可以有多个绑定同一个 VIP 的 Keepalived 服务(一主多备),本小节中只是写了两个
- 注意
<virtual_router_id>
,同一组 VIP 绑定的多个 Keepalived 服务的<virtual_router_id>
必须相同;多组 VIP 各自绑定的 Keepalived 服务一定与另外组不相同。否则前者会出现丢失节点,后者在初始化的时候会出错。
vi keepalived.conf
2 ! Configuration File for keepalived
3
4 global_defs {
5 notification_email {
6 acassen@firewall.loc
7 failover@firewall.loc
8 sysadmin@firewall.loc
9 }
10 notification_email_from Alexandre.Cassen@firewall.loc
11 smtp_connect_timeout 30
12 router_id LVS_DEVEL
13 }
14 vrrp_script chk_tomcat
15 {
16 script "/etc/keepalived/check_haproxy.sh"
17 ## script "/etc/keepalived/mysql.sh"
18 script "/etc/keepalived/tomcat_check.sh"
19 script "/etc/keepalived/check_port.sh 8066"
20 interval 5
21 weight -5
22 }
23 vrrp_instance VI_1 {
24 state BACKUP
25 interface ens33
26 virtual_router_id 56
27 priority 99
28 unicast_src_ip 173.16.80.76 ##source ip
29 unicast_peer {
30 173.16.80.70 ##dest ip
31 }
32 advert_int 1
33 authentication {
34 auth_type PASS
35 auth_pass 1111
36 }
37 virtual_ipaddress {
38 173.16.80.200
39 }
40 track_script {
41 chk_tomcat
42 }
43
44 }
vi check_haproxy.sh
1 #!/bin/bash
2 A=`ps -C haproxy --no-header |wc -l`
3 if [ $A -eq 0 ];then
4 /etc/init.d/haproxyd restart
5 echo "Start haproxy" &> /dev/null
6 sleep 3
7 if [ `ps -C haproxy --no-header |wc -l` -eq 0 ];then
8 /etc/init.d/keepalived stop
9 echo "Stop keepalived" &> /dev/null
10 fi
11 fi
12
vi check_port.sh
CHK_PORT=$1
echo $CHK_PORT
if [ "$CHK_PORT" != "" ];then
PORT_PROCESS=`lsof -i:$CHK_PORT|wc -l`
if [ $PORT_PROCESS -eq 0 ];then
echo "Port $CHK_PORT Is Not Used,End."
sleep 2
PORT_PROCESS=`lsof -i:$CHK_PORT|wc -l`
if [ $PORT_PROCESS -eq 0 ];then
systemctl stop keepalived
fi
fi
else
echo "Check Port Cant Be Empty!"
fi
vi tomcat_check.sh
1 #!/bin/bash
2 netstat -ant|grep 8090
3 ALIVE=$?
4 LOGFILE="/etc/keepalived/keepalived-check.log"
5 echo "[CHECK]" >> $LOGFILE
6 date >> $LOGFILE
7 if [ $ALIVE -eq 0 ]; then :
8 echo "8090 is ok" >> $LOGFILE 2>&1
9 exit 0
10 else
11 echo "8090 is down" >> $LOGFILE 2>&1
12 exit 1
13 fi
脚本编写完 chmod 777 check_port.sh 赋予权限