目录
1、Keepalive
VRRP 说明
故障切换
工作原理
核心组件
2、Keepalived + DR 集群
拓扑规划
前期准备
配置 Httpd 服务
配置 Nginx 服务
配置 LVS 主 node_01
配置 LVS 从 node_02
测试 LVS 集群
测试主备切换
3、Keepalived 脑裂现象
4、Keepalived 心态检测
TCP_CHECK 检测
HTTP_GET 检测
MISC_CHECK 检测
5、非抢占模式
Keepalived 软件起初是专为 LVS 负载均衡软件设计的,用来管理并监控 LVS 集群系统中各个服务节点的状态,主用来提供故障切换和健检查功能,如判断 LVS 负载调度器、节点服务器的可用性,及时隔离并替换为新的服务器,当故障主机恢复后将其重新加入集群。后来又加入了可以实现高可用的 VRRP 功能。因此,keepalived 除了能够管理 LVS 软件外,还可以作为其他服务的高可用解决方案软件(如nginx、 Mysql 等应用服务)
keepalived 软 件 主 要 是 通 过 VRRP 协 议 实 现 高 可 用 功 能 的 。 VRRP 是 Virtual Router Redundancy Protocol(虚拟路由冗余协议)的缩写,VRRP 出现的目的就是为了解决路由器的单点故障问题的,它能保证当个别节点宕机时,整个网络可以不间断地运行。所以,keepalived 一方面具有配置管理 LVS 的功能,同时还具有对 LVS 下面节点进行健康检查的功能,另一方面也可以实现系统网络服务的高可用功能。
VRRP 是针对局域网中配置静态网关出现单点故障的解决方案,一个局域网络内的所有主机都设置缺省路由(默认网关),当网内主机发出的目的地址不在本网段时,报文将被通过缺省路由发往外部路由器,从而实现了主机与外部网络的通信。
当缺省路由器 down 掉(即端口关闭)之后,内部主机将无法与外部通信,如果路由器设置了 VRRP 时,那么这时,虚拟路由将启用备份路由器,从而实现全网通信。
VRRP 是针对路由器的一种备份解决方案-----由多台路由器组成一个热备组。这个热备组里面有一个 master 和多个 backup。master 上面有一个对外提供服务的 vip,通过 vip 地址对外提供服务;每个热备组内同一时刻只有一台主服务器提供服务,其他服务器处于冗余状态,若当前在线的主服务器失败,其他服务器会自动接替(优先级决定接替顺序)虚拟 IP 地址,以继续提供服务。
热备组内的每台服务器 都可以成为主服务器,虚拟 IP 地址(VIP)可以在热备组内的服务器之间进行转移,所以也称为漂移 IP 地址,使用 Keepalived 时,漂移地址的实现不需要手动建立虚拟接口配置文件(如 ens33:0),而是由 Keepalived 根据配置文件自动管理。
Keepalived 高可用服务对主备之间的故障切换转移,是通过 VRRP 来实现的。 在 keepalived 服务工作时,主 Master 节点会不断地向备节点发送(多播的方式)心跳消息,用来告诉备 Backup 节点自己还活着。当主节点发生故障时,就无法发送心跳的消息了,备节点也因此无法继续检测到来自主节点的心跳了。于是就会调用自身的接管程序,接管主节点的 IP 资源和服务。当主节点恢复时,备节点又会释放主节点故障时自身接管的 IP 资源和服务,恢复到原来的备用角色。
Layer 3、4、5 工作在 IP/TCP 协议栈的 IP 层,TCP 层,及应用层。
keepalived 是一个类似于 layer3、4、5 交换机制的软件,也就是我们平时说的第3 层、第 4 层和第 5 层交换。Keepalived 的作用是检测节点服务器的状态,如果有一台节点服务器宕机,或工作出现故障,Keepalived 将检测到,并将有故障的服务器从集群中剔除,当服务器工作正常后 Keepalived 自动将其加入到服务器集群中,这些工作全部自动完成,不需要人工干涉,只需要修复故障的节点服务器。
Layer3 层检测
进行 ICMP ping 包检测,确认主机是否存活,如果异常,则会将该主机从服务器集群中剔除。
Keepalived 使用 Layer3 的方式工作式时, Keepalived 会定期向集群中的服务器发送一个 ICMP 的数据包(既我们平时用的 Ping 程序),如果发现某台服务的 IP 地址没有激活,Keepalived 便报告这台服务器失效,并将它从集群中剔除,这种情况的典型例子是某台服务器被非法关机。Layer3 的方式是以服务器的 IP 地址是否有效作为服务器工作正常与否的标准。
Layer4 层检测
进行端口检测,例如 80、3306 等,端口不通时,将服务器从集群中剔除;主要以 TCP 端口的状态来决定服务器工作正常与否。如 web server 的服务端口一般是80,如果 Keepalived 检测到 80 端口没有启动,则 Keepalived 将把这台服务器从服务器群中删除。
Layer5 层检测
这个就是基于应用的了,如 http 返回码是否为 200,确认主机是否正常。Layer5 就是工作在具体的应用层了,比 Layer3,Layer4 要复杂一点,在网络上占用的带宽也要大一些。 Keepalived 将根据用户的设定检查服务器程序的运行是否正常,如果与用户的设定不相符,则 Keepalived 将把服务器从服务器群中剔除(例如:http 返回码是否为 200,确认主机是否正常)。
keepalived 也是模块化设计,不同模块负责不同的功能,它主要有三个模块分别是:
其他组件:
① 利用 VRRP 协议进行主备通信。组播 224.0.0.18
② 利用 VRRP 协议进行主备竞选,产生 VIP
③ 利用 VRRP 协议主向备发送组播包。当备服务器接收不到主服务器的组播包,就会认为主出现故障,主动接管资源。
④ 当主恢复时,根据配置决定是否抢占备服务器资源
主机名 |
内网IP |
外网IP |
VIP |
角色 |
node_01 |
192.168.137.101 |
192.168.2.101 |
192.168.2.88 |
lvs+keepalived 主 |
node_02 |
192.168.137.102 |
192.168.2.102 |
lvs+keepalived 从 |
|
node_03 |
192.168.137.103 |
192.168.2.103 |
192.168.2.88 |
nginx |
node_04 |
192.168.137.104 |
192.168.2.104 |
192.168.2.88 |
nginx |
node_05 |
192.168.137.105 |
httpd |
||
node_06 |
192.168.137.106 |
httpd |
① node_01、02、03、04 在虚拟机上新增一块网卡 & 修改宿主机的V1的网段为2.0
② 配置外网ip地址:node 01、02、03、04 根据规划分配指定外网IP地址,这里只演示node_01。
# 先查看新增网卡的名称。本次是ens36
ifconfig -a
# 添加ens36网卡文件
cd /etc/sysconfig/network-scripts/
cp ifcfg-ens33 ifcfg-ens36
# 修改名称、设备名称、IP地址按照外网IP规划分配、网关
vim ifcfg-ens36
systemctl restart network
ifconfig -a
③ 关闭防火墙和selinux
# 所有服务器关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 所有服务器关闭 selinx
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
④ 配置本地yum源
vim /etc/yum.repos.d/centos.repo
#----------------------------------------------------------
[centos7]
name=centos_7
baseurl=file:///mnt/cdrom
enabled=1
gpgcheck=0
#gpgcheck=1
#gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#----------------------------------------------------------
mkdir /mnt/cdrom/
mount /dev/sr0 /mnt/cdrom/
⑤ 所有服务器同步系统时间
yum install -y ntp
ntpdate ntp1.aliyun.com
在node05 和 node06 节点上安装httpd服务
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "192.168.137.105" > /var/www/html/index.html
在node03 和 node04 节点上安装 nginx 服务
① 关闭 ARP 转发
vim /etc/sysctl.conf
net.ipv4.conf.ens33.arp_ignore = 1
net.ipv4.conf.ens33.arp_announce = 2
net.ipv4.conf.ens37.arp_ignore = 1
net.ipv4.conf.ens37.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
② 配置虚拟 IP 地址(VIP)
cd /etc/sysconfig/network-scripts/
cp ifcfg-lo ifcfg-lo:0
vim ifcfg-lo:0
#---------------------------------
DEVICE=lo:0
IPADDR=192.168.2.88
NETMASK=255.255.255.255
ONBOOT=yes
NAME=loopback
#---------------------------------
# 重启 network 服务
systemctl restart network
ifconfig lo:0
③ 安装Nginx
# 解压nginx软件包
tar -zxvf nginx-1.22.1.tar.gz -C /usr/local/src
cd /usr/local/src/nginx-1.22.1/
# 安装编译环境
yum install -y gcc gcc-c++ pcre pcre-devel zlib zlib-devel
# 预编译
./configure --prefix=/usr/local/nginx
# 编译安装
make
make install
# 编辑服务文件
vim /usr/lib/systemd/system/nginx.service
#--------------------------------------------------------------------------
[Unit]
Description=nginx - web server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecQuit=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
#--------------------------------------------------------------------------
# 启动服务
systemctl restart nginx
ps -ef | grep nginx
④ 配置 nginx 负载均衡
upstream apache {
server 192.168.137.105:80 weight=1 max_fails=1 fail_timeout=10s;
server 192.168.137.106:80 weight=1 max_fails=1 fail_timeout=10s;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#root html;
#index index.html index.htm;
proxy_pass http://apache;
}
}
配置 lvs + Keepalived
在这种模式下,虚拟 IP 在某时刻只能属于某一个节点,另一个节点作为备用节点存在。当主节点不可用时,备用节点接管虚拟 IP,提供正常服务。
① 配置keepalived
# 安装 keepalived
yum install -y keepalived
# 查看 keepalived 配置文件
ls /etc/keepalived/keepalived.conf
keepalived 只有一个配置文件 keepalived.conf,里面主要包括以下几个配置区域:
② 编辑Keepalived 配置文件
# 编辑keepalived配置文件
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id node_01
}
vrrp_instance lvs-dr {
state MASTER
interface ens36
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.2.88
}
}
virtual_server 192.168.2.88 80 {
delay_loop 6
lb_algo rr
lb_kind DR
#persistence_timeout 50
protocol TCP
real_server 192.168.2.103 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.2.104 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
# ----------------------------配置文件说明 start ---------------------------------
# !表示注释
! Configuration File for keepalived
# 全局定义部分
global_defs {
# 设置警报邮箱
notification_email {
# 接收警报的邮箱地址,根据实际情况写
[email protected]
[email protected]
[email protected]
}
# 设置发件人地址
notification_email_from [email protected]
# 设置 smtp server 地址,即发邮件服务器
smtp_server 192.168.200.1
# 设置 smtp 超时连接时间,以上参数可以不配置
smtp_connect_timeout 30
#表示运行 keepalived 服务器的一个标识,这个标识(router_id)是唯一的
router_id cong11
}
# 定义一个实例,一个集群就是一个实例。 默认 VI_1 可以随意改
vrrp_instance lvs-dr {
# MASTER 表示指定本节点为主节点,备用节点上设置为BACKUP。注意节点状态均大写。
state MASTER
# 绑定虚拟 IP 的网络接口
interface ens37
# 虚拟路由 ID 标识,这个标识最好是一个数字,在一个keepalived.conf 配 置 中 是 唯 一 的 ,
# MASTER 和 BACKUP 配 置 中 相 同 实 例 的 virtual_router_id 必须是一致的。
virtual_router_id 51
# 节点的优先级(1-255 之间),越大越优先。备用节点必须比主节点优先级低。
priority 100
# 为同步通知间隔。MASTER 与 BACKUP 之间心跳检查的时间间隔,单位为秒,默认为 1。
advert_int 1
# 设置验证信息,两个节点必须一致,同一 vrrp 实例的MASTER 与 BACKUP 使用相同的密码才能正常通信
authentication {
auth_type PASS
auth_pass 1111
}
# 指定虚拟 IP, 两个节点设置必须一样
virtual_ipaddress {
192.168.2.88
}
}
# 至此为止以上为实现高可用配置,如只需使用高可用功能下边配置可删除
# 以下为虚拟服务器定义部分:类似添加虚拟服务器 ipvsadm -A -t 192.168.2.11:80 -s rr
# 设置虚拟服务器,指定虚拟 IP 和端口
virtual_server 192.168.2.88 80 {
# 健康检查时间为 6 秒,即 Keepalived 多长时间监测一次 RS。
delay_loop 6
# 设置负载调度算法为 rr 算法
lb_algo rr
# 设置负载均衡模式,有 NAT,TUN 和 DR 三种模式可选
lb_kind DR
# 非 NAT 模式注释掉此行 注释用!号
nat_mask 255.255.255.0
# 连接保持时间,单位是秒。有了这个会话保持功能,用户的请求会被一直分发到某个服务节点,
# 直到超过这个会话的保持时间。同一 IP地址的客户端 50 秒内的请求都发到同个 real server ,
# 这个会影响 LVS 的 rr 调度算法,同一 IP 的客户端超过 50 秒后,
# 再次访问,才会被转发到另一台 real server上。Persistence 是持久性的意思
persistence_timeout 50
# 指定转发协议类型,有 TCP 和 UDP 两种
protocol TCP
# 配置 RS 节点 1,需要指定 realserver 的真实 IP 地址和端口,IP 和端口之间用空格隔开
real_server 192.168.2.13 80 {
# 权重,权重大小用数字表示,数字越大,权重越高
weight 1
# 节点健康检查。这段内容要手动添加,把原来的内容删除
TCP_CHECK {
# 超时时间,表示 3 秒无响应超时。
connect_timeout 3
# 表示重试次数
nb_get_retry 3
# 表示重试间隔
delay_before_retry 3
# 检测端口,利用 80 端口检查
connect_port 80
}
}
real_server 192.168.2.14 80 { #RS 节点 2
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
#默认配置文件中还有两个 virtual_server 模版,把剩下的都删除了,就可以。如:
#virtual_server 10.10.10.2 1358 { 。。。 }
#virtual_server 10.10.10.3 1358 { 。。。 }
# ----------------------------配置文件说明 end---------------------------------
# 重启 keepalived 服务
systemctl restart keepalived
systemctl enable keepalived
systemctl status keepalived
③ 安装 ipvsadm
注意:安装完成不需要做任何配置,启动方式由 keepalived 控制
yum -y install ipvsadm
lsmod | grep ip_vs
ipvsadm -L -n
# 安装 keepalived
yum install -y keepalived
# 修改 keepalived.conf 配置文件
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id node_02
}
vrrp_instance lvs-dr {
state BACKUP
interface ens36
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.2.88
}
}
virtual_server 192.168.2.88 80 {
delay_loop 6
lb_algo rr
lb_kind DR
#persistence_timeout 50
protocol TCP
real_server 192.168.2.103 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.2.104 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
#-----------------------------------------------
# 启动 keepalived
systemctl start keepalived
systemctl enable keepalived
安装 ipvsadm
yum -y install ipvsadm
① 浏览器访问
② 查看负载调度
③ 查看 Nginx 日志
tail -0f /usr/local/nginx/logs/access.log
④ 查看Apache 日志
tail -0f /var/log/httpd/access_log
① 查看主节点、从节点的VIP情况
ip addr show dev ens36
② 测试主备 vip 地址漂移
# 停止主节点服务
systemctl stop keepalived
# 查看主节点、从节点的VIP情况
ip addr show dev ens36
③ 重新启动LVS旧主(node_01)
systemctl start keepalived
# 查看主节点、从节点的VIP情况
ip addr show dev ens37
由于某些原因,导致两台 keepalived 高可用服务器在指定时间内,无法检测到对方存活心跳信息,从而导致互相抢占对方的资源和服务所有权,然而此时两台高可用服务器有都还存活。表现形式就是备节点上出现了虚拟 IP, 此时主节点也是持有虚拟 IP 的。
脑裂产生的原因:
① 高可用服务器对之间心跳线链路发生故障,导致无法正常通信。
② 高可用服务器上开启了 iptables 防火墙阻挡了心跳消息传输。
③ 高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败。
④ 其他服务配置不当等原因,如心跳方式不同,心跳广插冲突、软件 Bug 等。
⑤ Keepalived 配置里同一 VRRP 实例如果 virtual_router_id 两端参数配置不一致也会导致裂脑问题发生。
real_server 192.168.2.13 80 {
weight 100
TCP_CHECK {
# 检测端口,利用 80 端口检查
connect_port 80
# 连接超时时间
connect_timeout 3
# 重连次数
nb_get_retry 3
# 重连间隔
delay_before_retry 3
}
}
real_server 192.168.2.13 80 {
weight 1
HTTP_GET {
url {
path /index.html
# http://192.168.2.103/index.html 的返回状态码
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
自定义 Shell 脚本监控
real_server 192.168.2.13 80 {
weight 100
MISC_CHECK {
# 脚本名,需全路径
misc_path "/opt/mytools/check_web.sh 192.168.2.103"
# 脚本执行的超时时间
misc_timeout 30
# 如果设置了 misc_dynamic,healthchecker
# 程序的退出状态码会用来动态调整服务器的权重(weight)。
misc_dynamic
}
}
用脚本来检测,脚本如果带有参数,需将脚本和参数放入双引号内。脚本的返回值需为:
keepalived 检测脚本内容/opt/mytools/check_web.sh,返回 0 代表检查正常,返回 1 代表检查异常
/opt/mytools/check_web.sh 内容如下:
#!/bin/sh
serverip=$1
curl -s -m 2 http://$serverip
if [ $? -eq 0 ];then
exit 0
else
exit 1
fi
注意:curl 命令中的-s 选项表示静音模式,不输出任何东西。-m 选项表示设置数据传输的最大时间。传输的最大允许时间
和抢占模式的配置相比,只改了两个地方:
在非抢占模式下,两个 keepalived 节点都启动后,默认都是 BACKUP 状态,双方在发送组播信息后,会根据优先级来选举一个 MASTER 出来。由于两者都配置了 nopreempt,所以 MASTER 从故障中恢复后,不会抢占 vip。这样会避免 VIP 切换可能造成的服务延迟。
! Configuration File for keepalived
global_defs {
router_id cong11
}
vrrp_script chk_nginx {
script "/etc/keepalived/nginx_check.sh"
interval 2
weight -20
}
vrrp_instance lvs-dr {
state BACKUP
interface ens37
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.88
}
track_script {
chk_nginx
}
}