使用 keepalived 实现虚拟IP + IP漂移

这段时间在调研 MySQL HA 方面的东西,看到大多数实现方法都是通过虚IP + IP 漂移实现,所以打算先将此过程实现一下。

虚IP,就是一个未分配给真实主机的IP,也就是说对外提供数据库服务器的主机除了有一个真实IP外还有一个虚IP,使用这两个 IP 中的任意一个都可以连接到这台主机,所有项目中数据库链接一项配置的都是这个虚IP,当服务器发生故障无法对外提供服务时,动态将这个虚IP切换到备用主机。这个切换的过程我们称之为IP漂移

其实现原理主要是靠 TCP/IP 的 ARP 协议。因为 IP 地址只是一个逻辑 地址,在以太网中 MAC 地址才是真正用来进行数据传输的物理地址,每台主机中都有一个 ARP缓存,存储同一个网络内的IP地址与 MAC 地址的对应关系,以太网中的主机发送数据时会先从这个缓存中查询目标 IP 对应的MAC地址,会向这个 MAC 地址发送数据。操作系统会自动维护这个缓存。这就是整个实现的关键。

我们可以通过 Keepalived 来实现这个过程。 Keepalived 是一个基于 VRRP 协议(Virtual Router Redundancy Protocol,即虚拟路由冗余协议)来实现的LVS(负载均衡器)服务高可用方案,可以利用其来避免单点故障。

一个 LVS 服务会有2台服务器运行 Keepalived,一台为主服务器(MASTER),另一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备份服务器,当备份服务器收不到这个消息的时候,即主服务器宕机的时候,备份服务器就会接管虚拟IP,这时就需要根据 VRRP 的优先级来选举一个 backup 当 master,保证路由器的高可用,继续提供服务,从而保证了高可用性。

先来准备两台机器,IP地址如下:

1
2
lc1: 172.24.8.101
lc7: 172.24.8.107

我们现在要实现添加一个虚IP:172.24.8.150,当 lc1 机器正常时,172.24.8.150 指向 lc1,当 lc1 出现故障时指向 lc7

此时通过 ping 可以看到 172.24.8.150 是无法 ping 通的。

在这两台机器上分别安装 Keepalived

1
$ sudo yum install -y keepalived

配置 Keepalived

lc1 的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface enp7s0f0
virtual_router_id 51
priority 101
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.24.8.150
}
}

lc7 的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vrrp_instance VI_1 {
state MASTER
interface enp7s0f0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.24.8.150
}
}

启动 lc1 和 lc7 上的 Keepalived 服务

1
sudo systemctl restart keepalived.service

将 Keepalived 加入开机启动项

1
sudo systemctl enable keepalived.service

测试

通过 ping 172.24.8.150 发现已经可以通了。

查看 lc1 的 IP信息

1
2
3
4
5
6
7
8
9
$ ip addr show enp7s0f0
2: enp7s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 6c:92:bf:0d:09:47 brd ff:ff:ff:ff:ff:ff
inet 172.24.8.101/24 brd 172.24.8.255 scope global enp7s0f0
valid_lft forever preferred_lft forever
inet 172.24.8.150/32 scope global enp7s0f0
valid_lft forever preferred_lft forever
inet6 fe80::6e92:bfff:fe0d:947/64 scope link
valid_lft forever preferred_lft forever

其中可以看到 inet 172.24.8.150/32 scope global enp7s0f0,说明现在 lc1 是作为虚拟IP的 master 来运行的。

查看 lc7 的 IP信息

1
2
3
4
5
6
7
$ ip addr show enp7s0f0
2: enp7s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 6c:92:bf:0d:21:49 brd ff:ff:ff:ff:ff:ff
inet 172.24.8.107/24 brd 172.24.8.255 scope global enp7s0f0
valid_lft forever preferred_lft forever
inet6 fe80::6e92:bfff:fe0d:2149/64 scope link
valid_lft forever preferred_lft forever

此时 lc7 中没有虚拟IP 的信息。

验证 Failover

我们手动停止 lc1 上的 Keepalived 服务:

1
sudo systemctl stop keepalived.service

此时 lc1 的 IP信息为:

1
2
3
4
5
6
7
$ ip addr show enp7s0f0
2: enp7s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 6c:92:bf:0d:09:47 brd ff:ff:ff:ff:ff:ff
inet 172.24.8.101/24 brd 172.24.8.255 scope global enp7s0f0
valid_lft forever preferred_lft forever
inet6 fe80::6e92:bfff:fe0d:947/64 scope link
valid_lft forever preferred_lft forever

可以看到 lc1 已经不在有 虚拟IP 的信息了。

查看 lc7 的 IP信息:

1
2
3
4
5
6
7
8
9
ip addr show enp7s0f0
2: enp7s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 6c:92:bf:0d:21:49 brd ff:ff:ff:ff:ff:ff
inet 172.24.8.107/24 brd 172.24.8.255 scope global enp7s0f0
valid_lft forever preferred_lft forever
inet 172.24.8.150/32 scope global enp7s0f0
valid_lft forever preferred_lft forever
inet6 fe80::6e92:bfff:fe0d:2149/64 scope link
valid_lft forever preferred_lft forever

可以看到 lc7 的 IP信息中 已经有虚拟IP 172.24.8.150 的信息了。

此时如果再把 lc1 上的 Keepalived 启动,可以看到 虚拟IP 又重新绑定到了 lc1 上。