文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
Keepalived 是集群管理中保证集群高可用的一个服务软件,用来防止单点故障。
1. VRRP
Keepalived 是以 VRRP (Virtual Router Redundancy Protocol)协议为实现基础的,即虚拟路由冗余协议。VRRP 协议是为消除在静态缺省路由环境下的缺省路由器单点故障引起的网络失效而设计的主备模式的协议,使得在发生故障而进行设备功能切换时可以不影响内外数据通信,不需要再修改内部网络的网络参数。VRRP 协议需要具有 IP 地址备份,优先路由选择,减少不必要的路由器间通信等功能。
- VRRP 实现了对路由器 IP 地址的冗余功能。
- 防止了单点故障造成的网络失效。
- VRRP 本身是热备形式的,但可以通过互相热备实现路由器的均衡处理。
- 新版的 VRRP 较老版简化了认证处理,实际不再进行数据的认证,这是因为在实际应用中经常出现认证造成多个 master 同时使用的异常情况。
1.1 VRRP 工作原理
- VRRP 协议(可以认为是实现路由器高可用的协议)将两台或多台路由器设备虚拟成一个设备(路由器组)。
- 路由器组里面有一个 master 路由器和多个 backup 路由器。
- master 上面对外提供 虚拟路由器 IP (一个或多个)。
- master 定时发送通告(VRRP 包)。
- backup 定时接收通告(VRRP 包)。
- master 实现针对虚拟路由器 IP 的各种网络功能,负责转发发送给网关地址的包和响应ARP 请求等。
- backup 只接收 master 的通告(VRRP 包),不执行对外的网络功能。
- backup 收不到通告(VRRP 包)时,认为 master 宕掉。并根据 VRRP 的优先级选举一个 backup 成为 master。
- 多台 backup 中优先级最高被抢占为 master。这种抢占是非常快速的(<1s),以保证服务的连续性。由于安全性考虑,VRRP 包使用了加密协议进行加密。
1.2 VRRP 实现
- 配置 VRRP 协议时需要配置每个路由器的 虚拟路由器 ID (VRID)和 优先权值。
- 使用 VRID 将路由器进行分组,具有相同 VRID 值的路由器为同一个组,VRID 是一个 0~255 的正整数。
- 同一组(路由器组)中的路由器通过使用优先权值来选举 master,优先级大者为 master,优先级也是一个 0~255 的正整数。
- VRRP 协议使用 IP 多播(multicast)包(多播地址 224.0.0.18)形式发送协议报文的。
- 虚拟路由器由 VRID(虚拟路由器 ID) 和一组 IP 地址组成,对外表现为一个周知的 MAC 地址,这个地址是特殊 虚拟源 MAC 地址 而不是 自身网卡的 MAC 地址。
- 在一组路由器中,不管谁是 master,对外都提供 相同的 MAC(虚拟源 MAC 地址) 和 IP(虚拟路由器 IP 地址(VIP))。客户端主机并不需要因为 master 的改变而修改自己的路由配置,对客户端而言,这种主从的切换是透明的。
1.2.1 master 选举方式
- 如果对外的 虚拟路由器 IP(VIP) 就是 路由器本身配置的 IP 地址 的话,该路由器始终都是 master,优先级为 255。
- 如果不具备虚拟 IP,进行 master 选举,各路由器宣告自己是 master,发送通告(VRRP 包)信息。
- 如果收到其他路由器发来的通告信息的优先级比自己高,将转回 backup 状态。
- 如果优先级相等的话,将比较路由器的实际 IP,IP 值较大的优先权高。
1.2.2 VRRP 协议状态
- VRRP 协议分为三种状态:初始化状态(initialize),主机状态(master),备份状态(backup)。
1)初始化状态(initialize)
- 路由器启动时,如果路由器的优先级是 255(最高优先级,虚拟路由器 IP 就是路由器本身配置的 IP 地址),发送 VRRP 通告信息。
- 发送广播 ARP 信息通告路由器 IP 地址对应的 MAC 地址为虚拟源 MAC 地址。
- 设置 发送通告信息 定时器,准备定时发送 VRRP 通告信息,转为 master 状态。
- 否则进入 backup 状态,设置 定时检查是否收到 master 的通告信息 定时器。
2) 主机状态(master)
- 设置 发送通告信息 的定时器。
- 用 虚拟源 MAC 地址 响应针对 虚拟路由器 IP 的 ARP 请求。
- 转发 目的 MAC 是 虚拟源 MAC 地址 的数据包。
- 接受 目的 IP 地址 是 虚拟路由器 IP 的数据包,否则丢弃。
- 当收到 shutdown 的事件时,删除 发送通告信息 的定时器,发送优先权级为 0 的通告信息(VRRP 包),转初始化状态。
3)备份状态(backup)
- 设置 定时检查是否收到 master 的通告信息 的定时器。
- 不能响应针对 虚拟路由器 IP 的 ARP 请求信息。
- 丢弃所有 目的 MAC 地址 是 虚拟源 MAC 地址 的数据包。
- 不接受 目的 IP 地址 是 虚拟路由器 IP 的数据包。
- 当收到 shutdown 的事件时,删除 定时检查是否收到 master 的通告信息 定时器,转初始化状态。
- 定时检查是否收到 master 的通告信息 定时器未检测到通告信息时,发送 VRRP 通告信息,广播 ARP 地址信息,进入 master 选举。
- 收到优先权级为 0 的通告信息(VRRP 包),进入 master 选举。
- 如果收到其他路由器发来的通告信息的优先级比自己高,转回 backup 状态,丢弃通告包。
- 如果优先级相等,比较路由器的实际 IP,IP 值较大的优先权高。
- 如果优先级大于其他路由器,则承认 master 有效,设置 发送通告信息 的定时器。
1.2.3 ARP 查询处理
- 当内网机器通过 ARP 查询 虚拟路由器 IP 地址 对应的 虚拟源 MAC 地址 时,master 路由器回复的 MAC 地址为 虚拟源 MAC 地址,而不是 实际网卡的 MAC 地址,这样在路由器切换时让内网机器觉察不到。
- 在路由器重新启动时,不主动发送本机网卡的 实际网卡的 MAC 地址。
- 如果虚拟路由器开启的 ARP 代理(proxy_arp)功能,代理的 ARP 也回应 虚拟源 MAC 地址。
1.3 VRRP 协议定义
1.3.1 以太头
- 源 MAC 地址必须为虚拟源 MAC 地址:00-00-5E-00-01-{VRID},VRID 为虚拟路由器 ID 值,16 进制格式,同一网段中最多有 255 个 VRRP 路由器。
- 目的 MAC 地址为多播类型的 MAC。
1.3.2 IP 头参数
- VRRP 包的源地址是本机地址,目的地址为一多播地址。
- IP 协议号为 112。
- IP 包的 TTL 值必须为 255。
1.3.3 VRRP 协议数据字段报文格式
属性 | 说明 | 宽度 | 默认值 |
---|---|---|---|
Version | 版本 | 4 位 | 在 RFC3768 中定义为 2。 |
Type | 类型 | 4 位 | 目前只定义一种类类型:通告数据,取值为 1。 |
VRID(Virtual Rtr ID) | 虚拟路由器 ID | 8 位 | |
Priority | 优先级 | 8 位 | 具备冗余 IP 地址的设备的优先级为 255。 |
Count IP Addrs | VRRP 包中的 IP 地址数量 | 8 位 | |
Auth Type | 认证类型 | 8 位 | RFC3768 中认证功能已经取消,此字段值定义 0(不认证),1 和 2 只作为对老版本的兼容。 |
Adver Int | 通告包的发送间隔时间 | 8位 | 单位是秒,缺省是 1 秒。 |
Checksum | 校验和 | 16 位 | 校验数据范围只是 VRRP 数据,即从 VRRP 的版本字段开始的数据,不包括 IP 头。 |
IP Address(es) | 和虚拟路由器相关的 IP 地址,数量由 Count IP Addrs 决定 | 8 位 | |
Authentication Data | 认证数据 | RFC3768 中定义该字段只是为了和老版本兼容,必须置 0。 |
1.3.4 接收数据时的检查
- 收到 VRRP 数据包时要进行以下验证,不满足的数据包将被丢弃。
- TTL 必须为 255。
- VRRP 版本号 必须为 2。
- 一个包中 数据字段 必须完整。
- 校验和 必须正确。
- 必须验证在接收的网卡上配置了 VRID 值,而且本地路由器不是 master。
- 必须验证 VRRP 认证类型 和配置的一致。
2. Keepalived
2.1 Keepalived 的安装
使用 yum 源在线安装
yum install keepalived
离线 tar 包方式安装
- 下载 Keepalived for Linux 解压安装。
- 以 Keepalived for Linux - Version 1.2.13 版本为例。
[root@nodeA ~]# tar -zxvf keepalived-1.2.13.tar.gz
[root@nodeA ~]# cd keepalived-1.2.13
[root@nodeA keepalived-1.2.13]# ./configure
[root@nodeA keepalived-1.2.13]# make & make install
- 配置过程中提示错误 configure: error: no acceptable C compiler found in $PATH,可安装 gcc 套件解决。
yum install mpfr-2.4.1-6.el6.x86_64.rpm
yum install cpp-4.4.7-18.el6.x86_64.rpm
yum install libgomp-4.4.7-18.el6.x86_64.rpm
yum install ppl-0.10.2-11.el6.x86_64.rpm
yum install cloog-ppl-0.15.7-1.2.el6.x86_64.rpm
yum install kernel-headers-2.6.32-696.el6.x86_64.rpm
yum install tzdata-2016j-1.el6.noarch.rpm
yum install glibc-2.12-1.209.el6.x86_64.rpm
yum install glibc-common-2.12-1.209.el6.x86_64.rpm
yum install glibc-headers-2.12-1.209.el6.x86_64.rpm
yum install glibc-devel-2.12-1.209.el6.x86_64.rpm
yum install libstdc++-4.4.7-18.el6.x86_64.rpm
yum isntall libstdc++-devel-4.4.7-18.el6.x86_64.rpm
yum install libgcc-4.4.7-18.el6.x86_64.rpm
yum install gcc-4.4.7-18.el6.x86_64.rpm
yum install gcc-c++-4.4.7-18.el6.x86_64.rpm
离线安装 rpm 包可在 https://pkgs.org 中下载。
配置安装成功
Keepalived configuration
------------------------
Keepalived version : 1.2.13
Compiler : gcc
Compiler flags : -g -O2
Extra Lib : -lssl -lcrypto -lcrypt
Use IPVS Framework : Yes
IPVS sync daemon support : Yes
IPVS use libnl : No
fwmark socket support : Yes
Use VRRP Framework : Yes
Use VRRP VMAC : Yes
SNMP support : No
SHA1 support : No
Use Debug flags : No
- 如果配置过程中提示警告 this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.,可安装 libnl3。
yum install -y libnl3.x86_64
yum install -y libnl3-devel.x86_64
yum install -y libnl3-cli.x86_64
- 如果配置过程中提示错误 configure: error: libnfnetlink headers missing,可安装 libnfnetlink。
yum install -y libnfnetlink.x86_64
yum install -y libnfnetlink-devel.x86_64
- 安装成功
......
Make complete
make[1]: Leaving directory `/root/keepalived-1.2.13/keepalived'
make -C genhash
make[1]: Entering directory `/root/keepalived-1.2.13/genhash'
gcc -g -O2 -I/usr/src/linux/include -I/usr/src/linux/include -I../lib -Wall -Wunused -Wstrict-prototypes -c -o main.o main.c
gcc -g -O2 -I/usr/src/linux/include -I/usr/src/linux/include -I../lib -Wall -Wunused -Wstrict-prototypes -c -o sock.o sock.c
gcc -g -O2 -I/usr/src/linux/include -I/usr/src/linux/include -I../lib -Wall -Wunused -Wstrict-prototypes -c -o layer4.o layer4.c
gcc -g -O2 -I/usr/src/linux/include -I/usr/src/linux/include -I../lib -Wall -Wunused -Wstrict-prototypes -c -o http.o http.c
gcc -g -O2 -I/usr/src/linux/include -I/usr/src/linux/include -I../lib -Wall -Wunused -Wstrict-prototypes -c -o ssl.o ssl.c
Building ../bin/genhash
strip ../bin/genhash
Make complete
make[1]: Leaving directory `/root/keepalived-1.2.13/genhash'
Make complete
2.2 Keepalived 模块
模块 | 说明 |
---|---|
core | keepalived 核心,复杂主进程的启动和维护,全局配置文件的加载解析等。 |
check | 负责 healthchecker(健康检查),包括了各种健康检查方式,以及对应的配置的解析包括 LVS 的配置解析。 |
vrrp | VRRP 子进程,实现 VRRP 协议。 |
libipfwc | iptables(ipchains)库,配置 LVS 时用到。 |
libipvs | 配置 LVS 用到。 |
- keepalived 启动后会有三个进程。
- 父进程:内存管理,子进程管理等等。
- 子进程:VRRP 子进程。
- 子进程:healthchecker 子进程。
2.3 Keepalived 配置
- keepalived 只有一个配置文件 keepalived.conf,其中包含了三类配置区域。
2.3.1 全局配置 Global Configuration
- 全局配置区域包含了 global_defs(全局配置标识)、static_ipaddress(静态地址)、static_routes(静态路由) 区域配置项。
global_defs 区域
- 主要是配置故障发生时的通知对象以及机器标识。
global_defs {
notification_email {
[email protected]
[email protected]
...
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
enable_traps
router_id node1
}
配置项 | 说明 |
---|---|
notification_email | 故障发生时给谁发邮件通知。 |
notification_email_from | 通知邮件从哪个地址发出。 |
smpt_server | 通知邮件的 smtp 地址。 |
smtp_connect_timeout | 连接 smtp 服务器的超时时间。 |
enable_traps | 开启 SNMP 陷阱(Simple Network Management Protocol)。 |
router_id | 标识本节点的字条串,通常为 hostname,但不一定非得是 hostname。故障发生时,邮件通知会用到。 |
static_ipaddress 和 static_routes 区域
- 配置的是本节点的 IP 和 路由 信息。如果机器上已经配置了 IP 和路由,那么这两个区域可以不用配置。
static_ipaddress {
10.210.214.163/24 brd 10.210.214.255 dev eth0
...
}
static_routes {
10.0.0.0/8 via 10.210.214.1 dev eth0
...
}
2.3.2 VRRP 配置
- VRRP 配置区域主要包含了 vrrp_instance(VRRP 实例)、vrrp_sync_group(VRRP 同步组)、vrrp_script(VRRP 脚本) 、virtual_server 区域配置项。
vrrp_instance 和 vrrp_sync_group 区域
- vrrp_instance 用来定义对外提供服务的 VIP 区域及其相关属性。
- vrrp_rsync_group 用来定义 vrrp_intance 组,使得这个组内成员动作一致。例如两个 vrrp_instance 同属于一个 vrrp_rsync_group,那么其中一个vrrp_instance 发生故障切换时,另一个 vrrp_instance 也会跟着切换(即使这个 instance 没有发生故障)。
vrrp_sync_group VG_1 {
group {
inside_network # name of vrrp_instance (below)
outside_network # One for each moveable IP.
...
}
notify_master /path/to_master.sh
notify_backup /path/to_backup.sh
notify_fault "/path/fault.sh VG_1"
notify /path/notify.sh
smtp_alert
}
vrrp_instance VI_1 {
state MASTER
interface eth0
use_vmac
dont_track_primary
track_interface {
eth0
eth1
}
mcast_src_ip
lvs_sync_daemon_interface eth1
garp_master_delay 10
virtual_router_id 1
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 12345678
}
virtual_ipaddress {
10.210.214.253/24 brd 10.210.214.255 dev eth0
192.168.1.11/24 brd 192.168.1.255 dev eth1
}
virtual_routes {
172.16.0.0/12 via 10.210.214.1
192.168.1.0/24 via 192.168.1.1 dev eth1
default via 202.102.152.1
}
track_script {
check_running
}
nopreempt
preempt_delay 300
debug
notify_master |
notify_backup |
notify_fault |
notify |
smtp_alert
}
配置项 | 说明 |
---|---|
notify_master | 分别表示切换为主时所执行的脚本。 |
notify_backup | 分别表示切换为备时所执行的脚本。 |
notify_fault | 分别表示切换出错时所执行的脚本。 |
notify | 表示任何一状态切换时都会调用该脚本,并且该脚本在以上三个脚本执行完成之后进行调用,keepalived 会自动传递三个参数(2 = name of group or instance,$3 = target state of transition(MASTER/BACKUP/FAULT))。 |
smtp_alert | 表示是否开启邮件通知(用全局区域的邮件设置来发通知)。 |
state | 可以是 MASTER 或 BACKUP,不过当其他节点 keepalived 启动时会将 Priority(优先级)比较大的节点选举为 MASTER,因此该项其实没有实质用途。 |
interface | 节点固有 IP(非 VIP)的网卡,用来发 VRRP 包。因为在配置虚拟 IP 的时候必须是在已有的网卡上添加的。 |
use_vmac | 是否使用 VRRP 的虚拟 MAC 地址。不配置即不使用 |
dont_track_primary | 忽略 VRRP 网卡错误。(默认未设置) |
track_interface | 设置额外的监控,监控以下网卡,如果任何一个不通就会切换到 FALT 状态。(可选项) |
mcast_src_ip | 修改 vrrp 组播包的源地址,默认源地址为 master 的 IP。(由于是组播,因此即使修改了源地址,该 master 还是能收到回应)。这里实际上就是在哪个地址上发送 VRRP 通告,一定要选择稳定的网卡端口来发送,如果没有设置那么就用默认的绑定的网卡的 IP,也就是 interface 指定的 IP 地址。 |
lvs_sync_daemon_interface | 绑定 lvs syncd 的网卡。 |
garp_master_delay | 当切为主状态后多久更新 ARP 缓存,默认 5 秒。 |
virtual_router_id | 设置 VRID,取值在 0-255 之间,用来区分多个 instance 的 VRRP 组播(同一网段中 virtual_router_id 的值不能重复,否则会出错)。将决定多播的 MAC 地址 |
priority | 用来选举 master,要成为 master,这个选项的值最好高于其他机器 50 个点,该项取值范围是 1-255(在此范围之外会被识别成默认值 100)。 |
advert_int | 发 VRRP 包的时间间隔,即多久进行一次 master 选举(可以认为是健康查检时间间隔,默认为 1 秒)。 |
authentication | 认证区域,认证类型(auth_type)有 PASS 和 HA(IPSEC),推荐使用 PASS(密码只识别前 8 位)。认证密码(auth_pass)。 |
virtual_ipaddress | VIP(虚拟 IP 地址),随着 state 的变化而增加删除,当 state 为 master 的时候就添加,当 state 为 backup 的时候删除,主要由优先级来决定的,和 state 设置的值没有多大关系,可以设置多个 IP 地址。 |
virtual_routes | 虚拟路由,当 IP 漂过来之后需要添加的路由信息。原理和 virtual ipaddress 一样,只不过这里是增加和删除路由。 |
virtual_ipaddress_excluded | 发送的 VRRP 包里不包含的 IP 地址,为减少回应 VRRP 包的个数。在网卡上绑定的 IP 地址比较多的时候用。 |
lvs_sync_daemon_interface | lvs syncd 绑定的网卡。 |
nopreempt | 允许一个 priority 比较低的节点作为 master,即使有 priority 更高的节点启动。设置不抢占,只能设置在 state 为 backup 的节点上。次要实现类似于关闭 auto failback 的功能需要将所有节点的 state 都设置为 backup,或者将 master 节点的priority 设置的比 backup 低。 |
preempt_delay | 抢占延迟,master 启动多久之后进行接管资源(VIP/Route 信息等),前提是没有 nopreempt 选项。 |
debug | debug 级别。 |
track_script | 引用健康检查脚本 |
vrrp_script 区域
- 用来做健康检查,当时检查失败时会将 vrrp_instance 的 priority 减少相应的值。
- 首先在 vrrp_script 区域定义脚本名字和脚本执行的间隔和脚本执行的优先级变更。然后在实例 vrrp_instance 里面引用,有点类似脚本里面的函数引用一样:先定义,后引用函数名。
vrrp_script check_running {
script "/usr/local/bin/check_running"
interval 10
weight 10
}
配置项 | 说明 |
---|---|
script | 健康检查脚本名称 |
interval | 脚本执行间隔 |
weight | 脚本结果导致的优先级变更:10 表示优先级 +10;-10 则表示优先级 -10。 |
VRRP 脚本 vrrp_script 和 VRRP 实例 vrrp_instance 属于同一个级别。
2.3.3 LVS 配置
- 如果没有配置 LVS+keepalived 那么无需配置这段区域,如果用 nginx 代替 LVS,也无需配置这段区域,LVS 配置专门为 keepalived+LVS 集成准备。
- LVS 配置区域主要包含了 virtual_server_group(虚拟主机组)配置和 virtual_server(虚拟主机配置)。
virtual_server_group 区域
virtual_server_group {
# VIP port
fwmark
}
virtual_server 区域
virtual_server IP Port {
delay_loop
lb_algo rr|wrr|lc|wlc|lblc|sh|dh
lb_kind NAT|DR|TUN
persistence_timeout
persistence_granularity
protocol TCP
ha_suspend
virtualhost
alpha
omega
quorum
hysteresis
quorum_up |
quorum_down |
sorry_server
real_server {
weight
inhibit_on_failure
notify_up |
notify_down |
# HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK
HTTP_GET|SSL_GET {
url {
path
# Digest computed with genhash
digest
status_code
}
connect_port
connect_timeout
nb_get_retry
delay_before_retry
}
}
}
配置项 | 说明 |
---|---|
delay_loop | 延迟轮询时间(单位秒)。 |
lb_algo | 后端调试算法(load balancing algorithm)。 |
lb_kind | LVS 集群模式 NAT/DR/TUN。 |
persistence_timeout | 会话保持时间(秒为单位),即以用户在指定秒内被分配到同一个后端 realserver。 |
persistence_granularity | LVS 会话保持粒度,ipvsadm 中的 -M 参数,默认是 0xffffffff,即每个客户端都做会话保持。 |
protocol | 健康检查用的是 TCP 还是 UDP。 |
virtualhost | 用来给 HTTP_GET 和 SSL_GET 配置请求 header 的。 |
sorry_server | 当所有 real server 宕掉时,sorry server 顶替。 |
real_server | 真正提供服务的服务器。 |
weight | 权重。 |
notify_up/down | 当 real server 宕掉或启动时执行的脚本。 |
健康检查方式 | 健康检查方式一共有 HTTP_GET、SSL_GET、TCP_CHECK、SMTP_CHECK、MISC_CHECK。 |
path | 请求 real serserver 上的路径。 |
digest/status_code | 分别表示用 genhash 算出的结果和 http 状态码。 |
bindto | 健康检查的 IP 地址。 |
connect_port | 健康检查,如果端口通则认为服务器正常。 |
connect_timeout | 表示超时时长。 |
nb_get_retry | 重试次数。 |
delay_before_retry | 下次重试的时间延迟。 |
misc_path |
外部程序或脚本。 |
misc_timeout |
脚本或程序执行超时时间。 |
misc_dynamic | 可以非常精确的来调整权重,是后端每天服务器的压力都能均衡调配,这个主要是通过执行的程序或脚本返回的状态代码来动态调整 weight 值,使权重根据真实的后端压力来适当调整。(返回 0:健康检查没问题,不修改权重;返回 1:健康检查失败,权重设置为 0;返回 2-255:健康检查没问题,但是权重却要根据返回代码修改为返回码 -2,例如如果程序或脚本执行后返回的代码为 200,那么权重这回被修改为 200-2。 |
- TCP 健康检查方式
TCP_CHECK {
connect_port 80
bindto 192.168.1.1
connect_timeout 4
}
- SMTP 健康检查方式
SMTP_CHECK {
host {
connect_ip
connect_port
14 KEEPALIVED
bindto
}
connect_timeout
retry
delay_before_retry
helo_name |
}
- MISC 健康检查方式,这个可以用来检查很多服务器。
MISC_CHECK
{
misc_path |
misc_timeout
misc_dynamic
}
2.4 使用 Keepalived 实现双机热备
- 双机热备是指两台机器都在运行,但并不是两台机器都同时在提供服务。
- 当提供服务的一台出现故障的时候,另外一台会马上自动接管并且提供服务,而且切换的时间非常短。
- 至少需要两台服务器,其中一台为 master 始终提供服务,另外一台作为 backup 始终处于空闲状态。
- 网络拓扑图
准备工作
- 两台物理服务器和一个虚拟服务器(VIP)
- master redhat6.5 192.168.102.31 nodeA
- backup redhat6.5 192.168.102.32 nodeB
- 192.168.102.30 VIP
- 防火墙设置
注意:务必要设置防火墙开放端口,VRRP 协议需要 master 不断发送 “状态正常” 的广播信息,一旦 backup 不能收到 master 的广播信息,backup 会尝试切换到 master 状态来接管 VIP。
iptables -I INPUT -i eth0 -d 224.0.0.0/8 -p vrrp -j ACCEPT
iptables -I OUTPUT -o eth0 -d 224.0.0.0/8 -p vrrp -j ACCEPT
service iptables restart
安装并配置 Keepalived
- 主机 nodeA 上的配置
global_defs {
router_id nodeA
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.102.30
}
}
- 备机 nodeB 上的配置
global_defs {
router_id nodeB
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.102.30
}
}
- master 上运行 Keepalived 的效果。
[root@nodeA keepalived]# tailf /var/log/messages
Oct 26 02:30:13 nodeA Keepalived_vrrp[12147]: Configuration is using : 61594 Bytes
Oct 26 02:30:13 nodeA Keepalived_vrrp[12147]: Using LinkWatch kernel netlink reflector...
Oct 26 02:30:13 nodeA Keepalived_vrrp[12147]: VRRP sockpool: [ifindex(2), proto(112), unicast(0), fd(10,11)]
Oct 26 02:30:13 nodeA Keepalived_healthcheckers[12146]: Configuration is using : 6137 Bytes
Oct 26 02:30:13 nodeA Keepalived_healthcheckers[12146]: Using LinkWatch kernel netlink reflector...
Oct 26 02:30:14 nodeA Keepalived_vrrp[12147]: VRRP_Instance(VI_1) Transition to MASTER STATE
Oct 26 02:30:15 nodeA Keepalived_vrrp[12147]: VRRP_Instance(VI_1) Entering MASTER STATE
Oct 26 02:30:15 nodeA Keepalived_vrrp[12147]: VRRP_Instance(VI_1) setting protocol VIPs.
Oct 26 02:30:15 nodeA Keepalived_vrrp[12147]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.102.30
Oct 26 02:30:15 nodeA Keepalived_healthcheckers[12146]: Netlink reflector reports IP 192.168.102.30 added
Oct 26 02:30:20 nodeA Keepalived_vrrp[12147]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.102.30
- master 上通过 ip addr 可以看到 192.168.102.30 绑定到了 eth0 上。
[root@nodeA ~]# ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:06:15:3b brd ff:ff:ff:ff:ff:ff
inet 192.168.102.31/21 brd 192.168.103.255 scope global eth0
inet 192.168.102.30/32 scope global eth0
inet6 fe80::20c:29ff:fe06:153b/64 scope link
valid_lft forever preferred_lft forever
- backup 上运行 Keepalived 的效果。
Oct 26 06:57:52 nodeB Keepalived_vrrp[3333]: Opening file '/etc/keepalived/keepalived.conf'.
Oct 26 06:57:52 nodeB Keepalived_healthcheckers[3332]: Registering Kernel netlink reflector
Oct 26 06:57:52 nodeB Keepalived_healthcheckers[3332]: Registering Kernel netlink command channel
Oct 26 06:57:52 nodeB Keepalived_healthcheckers[3332]: Opening file '/etc/keepalived/keepalived.conf'.
Oct 26 06:57:52 nodeB Keepalived_healthcheckers[3332]: Configuration is using : 6115 Bytes
Oct 26 06:57:52 nodeB Keepalived_vrrp[3333]: Configuration is using : 61572 Bytes
Oct 26 06:57:52 nodeB Keepalived_vrrp[3333]: Using LinkWatch kernel netlink reflector...
Oct 26 06:57:52 nodeB Keepalived_vrrp[3333]: VRRP_Instance(VI_1) Entering BACKUP STATE
Oct 26 06:57:52 nodeB Keepalived_vrrp[3333]: VRRP sockpool: [ifindex(2), proto(112), unicast(0), fd(10,11)]
Oct 26 06:57:52 nodeB Keepalived_healthcheckers[3332]: Using LinkWatch kernel netlink reflector...
- 查看 ip_vs 模块 是否自动加载成功。
- 未加载成功 /var/log/messages 系统日志会提示 IPVS: Can't initialize ipvs: Protocol not available,并且不能绑定虚拟 IP。
[root@nodeA ~]# lsmod | grep ip_vs
ip_vs 141092 0
nf_conntrack 133387 3 ip_vs,xt_conntrack,nf_conntrack_ipv4
libcrc32c 12644 3 xfs,ip_vs,nf_conntrack
2.5 防火墙配置
- ${interface} 为网口名称。
- Centos 6.5 中使用 iptables
iptables -I INPUT -i ${interface} -d 224.0.0.0/8 -p vrrp -j ACCEPT
iptables -I OUTPUT -o ${interface} -d 224.0.0.0/8 -p vrrp -j ACCEPT
service iptables save
- Centos 7 中使用 firewalld
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ${interface} --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --out-interface ${interface} --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --reload
- 如果启用了防火墙,不设置 " 系统接收 VRRP 协议 " 的规则,会出现脑裂情况。
- 网卡接收到数据包在防火墙处理数据包之前,就算网络相通,并且能接收到 VRRP 广播包,却也无法改变自身状态。
2.6 selinux 配置
-
Centos 7 中使用 selinux
- 将 /etc/keepalived/ 目录中的文件目录都拷贝至 /usr/libexec/keepalived/ 目录下
-
拷贝 keepalived.conf 配置文件到 /usr/libexec/keepalived/ 目录下。
- 停止 keepalived 服务。
- 执行 /usr/sbin/keepalived --use-file=/usr/libexec/keepalived/keepalived.conf 重新设置配置文件。
- 启动 keepalived 服务。
2.7 脑裂问题
- 脑裂(split-brain)指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。
- 对于无状态服务的 HA,无所谓脑裂不脑裂。
- 但对有状态服务(比如数据库)的 HA,必须要严格防止脑裂。
脑裂原因
- 高可用服务器对之间心跳线链路发生故障,导致无法正常通信。
- 心跳线损坏,心跳线之间的设备故障(网卡及交换机)。
- 高可用服务器上开启了 iptables 防火墙,阻止了心跳传消息输。
- 网卡及相关驱动损坏,IP 配置及冲突问题。
- 心跳网卡地址等信息配置不正确,导致发送心跳失败。
- 其他服务配置不当的原因,如心跳方式不同,心跳广播冲突,软件 bug 等。
- 仲裁的机器出现问题(采用仲裁的方案)。
脑裂方案
- 实际生产环境中可从以下方面防止脑裂。
- 同时使用串行电缆和以太网电缆连接、同时使用两条心跳线路,一条线路损坏,还有另外一条传送心跳消息。
- 当检查脑裂时强行关闭一个心跳节点(功能需要特殊设备支持,如 stonith、fence)相当于备节点接收不到心跳消息,通过单独的线路发送关机命令关闭主节点电源。
- 做好对脑裂的监控报警(正常情况下 keepalived 的 VIP 地址在主节点上,如果在从节点发现 VIP,就设置报警信息)。
仲裁方案
- 可以采用第三方仲裁的方法,即每个节点必须判断自身的状态。
- 最简单的方法是,在主备的 keepalived 配置文件中增加 check 配置,服务器周期性地 ping 网关,如果 ping 不通则认为自身有问题 ,则关闭 keepalived。
- 也可以写一个脚本加入到 crontab 中,循环 ping 网关,累计达到一定地失败次数,则关闭 keepalived 服务,当发现又能够 ping 通网关时,再重启 keepalived 服务。