1. 工作场景
Keepalived提供了Loadbalancing和High-Availability的功能, 本文说的是其为2个Mycat节点提供HA功能的场景.
2. 关键配置如下, 为主备非抢占模式.
! mycat01, 192.168.4.196
global_defs {
# 一个keepalived.conf, 对应一个router_id
router_id mycat01
}
vrrp_instance VI_1 {
state BACKUP
nopreempt
interface eth0
# 一个组播内, 各节点该值相同
virtual_router_id 196
priority 200
advert_int 1
authentication {
auth_type PASS
auth_pass Zf4aqy
}
virtual_ipaddress {
192.168.4.200
}
}
! mycat02, 192.168.4.195
global_defs {
router_id mycat02
}
vrrp_instance VI_1 {
state BACKUP
nopreempt
interface eth0
virtual_router_id 196
priority 200
advert_int 1
authentication {
auth_type PASS
auth_pass Zf4aqy
}
virtual_ipaddress {
192.168.4.200
}
}
3. Keepalived提供HA的工作原理
Keepalived的HA功能, 是通过VRRP(Virtual Router Redundancy Protocol, 虚拟路由冗余协议)来实现的. 其用IP组播的方式(默认组播地址: 224.0.0.18), 实现服务节点间的通信, 通过一种竞选机制来将路由任务交给某台VRRP路由器. 工作时主节点发送VRRP协议报文, 备节点接收报文, 若一段时间(默认3个报文发送时间)备节点接收不到主节点发送的报文, 就会启动接管程序接管主节点的资源. 备节点可以有多个, 通过优先级竞选.
4. Keepalived发生脑裂的情况
4.1 根据上述工作原理知道, 备节点接收不到报文时, 如两者间的网络不通了, 备节点就会启动接管程序接管主节点的资源, 对外提供服务, 表现形式就是备节点上出现了虚拟IP, 此时主节点也是持有虚拟IP的.
问题重现如下, 此时mycat01为主节点, mycat02为备节点, 在mycat02上drop掉组播数据包.
# iptables -A INPUT -m pkttype --pkt-type multicast -j DROP
然后观察message日志, 可见其也变成了主节点.
# tail -f /var/log/messages
Mar 17 00:13:58 mycat02 kernel: ip_tables: (C) 2000- Netfilter Core Team
Mar 17 00:14:00 mycat02 Keepalived_vrrp: VRRP_Instance(VI_1) Transition to MASTER STATE
Mar 17 00:14:01 mycat02 Keepalived_vrrp: VRRP_Instance(VI_1) Entering MASTER STATE
Mar 17 00:14:01 mycat02 Keepalived_vrrp: VRRP_Instance(VI_1) setting protocol VIPs.
Mar 17 00:14:01 mycat02 Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.4.200
Mar 17 00:14:01 mycat02 Keepalived_healthcheckers: Netlink reflector reports IP 192.168.4.200 added
Mar 17 00:14:06 mycat02 Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.4.200
在mycat01上抓包, 看到mycat02也在向组播地址发送数据包.
# tcpdump -nnei eth0 | grep -i 'vrid 196'
00:13:58.735738 fa:16:3e:f4:18:40 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 54: 192.168.4.196 > 224.0.0.18: VRRPv2, Advertisement, vrid 196, prio 202, authtype simple, intvl 1s, length 20
00:13:59.736268 fa:16:3e:f4:18:40 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 54: 192.168.4.196 > 224.0.0.18: VRRPv2, Advertisement, vrid 196, prio 202, authtype simple, intvl 1s, length 20
00:14:00.736800 fa:16:3e:f4:18:40 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 54: 192.168.4.196 > 224.0.0.18: VRRPv2, Advertisement, vrid 196, prio 202, authtype simple, intvl 1s, length 20
00:14:00.955581 fa:16:3e:5d:23:10 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 54: 192.168.4.195 > 224.0.0.18: VRRPv2, Advertisement, vrid 196, prio 202, authtype simple, intvl 1s, length 20
00:14:01.956340 fa:16:3e:f4:18:40 > 01:00:5e:00:00:12, ethertype IPv4 (0x0800), length 54: 192.168.4.196 > 224.0.0.18: VRRPv2, Advertisement, vrid 196, prio 202, authtype simple, intvl 1s, length 20
当把iptables停掉后, mycat01和mycat02扔分别持有虚拟IP 192.168.4.200, 这也说明了主备非抢占模式的一个弊端, 主备抢占模式是不会这样的, 下面是其主要配置.
! mycat01, 192.168.4.196
global_defs {
router_id mycat01
}
vrrp_instance VI_1 {
state MASTER
virtual_router_id 196
priority 200
}
! mycat02, 192.168.4.195
global_defs {
router_id mycat02
}
vrrp_instance VI_1 {
state BACKUP
virtual_router_id 196
priority 150
}
4.2 同一个组播内, virtual_router_id配置不相同, 也会发生脑裂现象, 这里就不在赘述了.
说到最后, 如何避免脑裂现象呢, 其实可以看到, 只要有虚拟IP存在, 就不可能完全规避这个问题. 也就是没有虚拟IP了, 就没有脑裂了, 那么节点又如何向外提供服务呢? 引入Zookeeper或Consul的服务发现机制, 这些又是另外的事情了...
若感兴趣可关注订阅号”数据库最佳实践”(DBBestPractice).