- keeplived
- 定义一个vrrp_instance实例,名字是VI_1,每个vvrp_instance实例都可以认为是Keepalived中的一个业务服务。
- keepalived中可以有多个这一的实例,备节点也要存在相同的实例才能进行故障切换接管。
- 优先级决定了VIP在哪个机器上初始运行
- 表示启动nginx而忽略配置中监听的ip是否存在,同样适用于Haproxy。
- 8.解决服务宕后keepalived仍运行
- 9.多组Keepalived局域网内冲突
- 10.指定配置文件接收Keepalived服务日志
- —dump-conf -d 导出备份数据。
- —log-detail -D 详细日志。
- —log-facility -S 设置本地的syslog设备,编号0-7(default=LOG_DAEMON)。
- -S 0 表示指定为local0设备。
- 11.编写监测Keepalived “脑裂”的脚本
keeplived
1.全局定义(globaldefinnition)
这一部分用来设置keepalived的故障通知机制和RouterID标识。
示例:
! Configuration File for keepalivedglobal_defs {notification-email[897959443@qq.com](mailto:897959443@qq.com) #需要抵达的邮箱地址[xilingkunpeng@hotmail.com](mailto:xilingkunpeng@hotmail.com) #需要抵达的邮箱地址}notification_email_from [897959443@qq.com](mailto:897959443@qq.com) #用于发送的邮箱smtp_server smtp.qq.com #stmp服务器smtp_connect_timeout 30 #设置超时时间router_id LVS_DEVEL #keepalived路由标识(router_id)。在统一局域网内,这个标识应该是唯一的。
大括号“{}”用于分割区块,需要成对出现。如果少了半个,keepalived也不会报错,但也得不到预期效果。
2.VRRP实例定义区块部分
这个部分主要用来定义具体服务的实例配置,包括Keepalived主备状态、接口、优先级、认证方式和IP信息等。
示例:
定义一个vrrp_instance实例,名字是VI_1,每个vvrp_instance实例都可以认为是Keepalived中的一个业务服务。
keepalived中可以有多个这一的实例,备节点也要存在相同的实例才能进行故障切换接管。
vrrp_instance VI_1 {
state MASTER #角色为master,其他节点应当为BACKUP,才能进行顺利的故障接管
interface ens33 #网络通信接口,要确定好具体是哪一块网卡
\#虚拟路由ID,这个标识最好是一个数字,并且在一keepalived中是唯一的。
\#但是MASTER和BACKUP中保持一致,否则会出现”脑裂”问题。
virtual_router_id 51
priority 100 #优先级/权重为100,master要比backup大
advert_int 1 #同步时间间隔,master和bakcup之间的通信检查时间,默认为1s
\#往下都是权限认证配置,包括认证类型(auth_type)和认证密码(auth_pass),认证类型有PASS(Simple Passwd(suggested))。
\#AH(ipasec(not recommended))两种,官方推荐类型为PASS。密码为明文模式,最好不要超过8个字符,推荐用4个字符。
\#同一VRRP实例的master和backup使用相同密码才能通信。
authentication {
auth_type PASS
auth_pass 123456 //定义密码,这个密码自定义
}
\#虚拟IP(VIP)地址,可以配置多个虚拟IP(VIP)。
\#配置时,最好指定子网掩码和VIP绑定的网络接口,否则默认验码是32位。绑定的网卡要和前面的interface保持一直。
\#这里就是和我们工作中需要和域名绑定的IP,即和配置的高可用服务监听保持一直。
virtual_ipaddress {
192.168.1.10 #定义VIP_1
192.168.1.20 #定义VIP_2
192.168.1.30 #定义VIP_3
}
track_script {
chk_nginx //定义监控脚本,这里和上面vrr_script后面的字符串保持一致
}
}
3.高可用单实例
3.1 配置主机
切换目录
cd /etc/keepalived/
备份配置文件
cp keepalived.conf{,.ori}
清空配置文件
\>keepalived.conf
编写配置文件
vim keeplived.conf
配置文件内容
global_defs {
router_id web01 #<== ID为web01,不同的keepalived.conf此ID要唯一。
}
vrrp_instance VI_1 { #<== 实例名字为VI_1,相同实例的备节点名字要和这个相同。
state MASTER #<== 状态为MASTER,备节点状态要为BACKUP。
interface ens33 #<== 通信接口为ens33,对于此参数,备节点和主节点相同。
virtual_router_id 51 #<== 实例ID为51,在同一keepalived.conf配置文件内是唯一。
priority 150 #<== 优先级为150,备节点的优先级要小于主节点的优先级。
advert_int 1 #<== 通信检查时间间隔1秒。
authentication {
auth_type PASS #<== PASS认证类型,对于此参数,备节点设置要和主节点相同。
auth_pass 123456 #<== 密码是123456,对于此参数,备节点设置要和主节点相同。
}
virtual_ipaddress {
192.168.1.120 dev ens33 label eth33:0
\#<== 虚拟IP,即VIP,子网验码为24位,绑定接口为eth0,别名为eth33:0,对于此参数,备节点要和主系欸但设置相同。
}
}
\#提示:此处设置的虚拟IP为192.168.1.120,即为域名网站绑定的IP。
检查并启动keepalived
ps -ef |grep keep|grep -v grep
systemctl start keepalived
ps -ef |grep keep|grep -v grep
检查IP情况
ip addr|grep 192.168.1.120
3.2 配置备机
切换目录
cd /etc/keepalived/
备份配置文件
cp keepalived.conf{,.ori}
清空配置文件
\>keepalived.conf
编写配置文件
vim keeplived.conf
配置文件内容
global_defs {
router_id web02 #<== ID为web02,不同的keepalived.conf此ID要唯一。
}
vrrp_instance VI_1 { #<== 实例名字为VI_1,相同实例的备节点名字要和这个相同。
state MASTER #<== 状态为MASTER,备节点状态要为BACKUP。
interface ens33 #<== 通信接口为ens33,对于此参数,备节点和主节点相同。
virtual_router_id 51 #<== 实例ID为51,在同一keepalived.conf配置文件内是唯一。
priority 100 #<== 优先级为100,备节点的优先级要小于主节点的优先级。
advert_int 1 #<== 通信检查时间间隔1秒
authentication {
auth_type PASS #<== PASS认证类型,对于此参数,备节点设置要和主节点相同。
auth_pass 123456 #<== 密码是123456,对于此参数,备节点设置要和主节点相同。
}
virtual_ipaddress {
192.168.1.120 dev ens33 label eth33:0
\#<== 虚拟IP,即VIP,子网验码为24位,绑定接口为eth0,别名为eth33:0,对于此参数,备节点要和主系欸但设置相同。
}
}
\#提示:此处设置的虚拟IP为192.168.1.120,即为域名网站绑定的IP。
检查并启动keepalived
ps -ef |grep keep|grep -v grep
systemctl start keepalived
ps -ef |grep keep|grep -v grep
这里因为没有接管,所以不应该有返回
如果有,就证明脑裂了。1
1.检查通信情况,iptables/firewalld
2.检查配置文件,例如virtual_router_id是否不一致
ip addr|grep 192.168.1.120
3.3 高可用测试
暂停主节点keepalived服务或关机
systemctl stop keepalived
or
shutdown -h now
分别在主节点和备节点上检查ip状态(若主节点已关机则不用检查主节点)
备节点应该拿到了VIP
ip addr|grep 192.168.1.120
重启主节点服务
systemctl start keepalived
检查VIP状态,主节点应当拿回了VIP
ip addr|grep 192.168.1.120
配置差别
| Keepalived 参数差别 | MASTER 节点特殊参数 | BACKUP 节点特殊参数 |
|---|---|---|
| router_id(唯一标识) | routrer_id web01 | routrer_id web02 |
| state | state MASTER | state BACKUP |
| priority | priority 150 | priority 100 |
4.”脑裂”问题
4.1 什么是脑裂
在指定时间内两台高可用服务无法检测到对他心跳消息,各自取得资源以及服务所有权,而此时两台高可用服务器都会去抢占同样的资源,这样会导致同一个IP或服务在两端同时存在发生冲突,最严重的就是两台主机抢占同一个IVP地址,当用户写入数据时,可能会分别写入两端,造成两端数据不一致或数据丢失,这种情况就被成为脑裂。
4.2 导致脑裂发生的原因
常见原因:
(1)高可用服务器之间对心跳链路故障,导致无法正常通信。
□心跳线坏了(断裂、老化)
□网卡以及相关驱动坏了,IP配置以及冲突问题(网卡直连)
□心跳线之间连接设备故障(网卡及交换机)
□仲裁机器出问题(采用仲裁方案)
(2)高可用服务器对上开启了iptables防火墙阻挡了心跳消息传输
(3)高可用服务器上心跳网卡地址等信息配置不正确
(4)其他服务配置不当等原因,如心跳方式不同、心跳广播冲突、软件BUG等
(5)同一VRRP实例virtual_router_id参数两端配置不一样
4.3 解决脑裂常见方案
(1)使用串行电缆和一台电缆链接,同时使用两条心跳线路,做线路高可用。
(2)检测到脑裂时强行关闭一个心跳节点(需要特殊设备支持,如Stonith、fence)。相当于备节点收不到心跳消息,发送关机命令通过单路的线路来关闭
(3)做好对脑裂的状态监控(邮件、手机短信、值班)报警,发生脑裂时第一时间人为介入仲裁。如百度的报警短信可以区分上下行,管理员可以通过短信回复数字或字符串返回给服务器,让服务器根据指令自动操作。或者开发简单app,第一时间点点点操作。
4.4 常见的keepalived脑裂解决方案
互联网应用服务器,前端web负载均衡的的高可用,对于普通业务一般是可以接受的,对于数据库和存储服务不可以接受。
□如果开启防火墙,一定要开放心跳消息通过,一般采用定向IP段可通过。
□可以拉一条以太网线或者串口线作为线路冗余
□开发监测程序通过监控软件(如Nagios)监测脑裂
生产判断脑裂思路:
(1)简单思路:备节点出现VIP就报警,有两种情况,一是主节点宕机了,备节点接管;二是主机没宕,脑裂了,无论是哪一种都要进行报警,然后人工查看。
(2)严谨思路:备节点出现VIP,主节点以及对应服务任然存活,说明脑裂了
5.Keepalived双实例双主机配置
5.1 规划
| HOSTNAME | IP | 说明 |
|---|---|---|
| web01 | 192.168.1.55 | VIP:192.168.1.100(绑定A服务 www.hanpi.com) |
| web02 | 192.168.1.56 | VIP:192.168.1.101(绑定B服务 bbs.91sepi.com) |
5.2 配置web01
在原来的单实例基础上增加一个实例(至于你们怎么搭建服务,我建议用nginx测试)
global_defs {
router_id web01
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100 dev ens33 label eth33:0
}
}
vrrp_instance VI_2 {
state BACKUP
interface ens33
virtual_router_id 52
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 5678
}
virtual_ipaddress {
192.168.1.101 dev ens33 label eth33:1
}
}
5.3 配置web02
建议直接scp然后改一改
global_defs {
router_id web02
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100 dev ens33 label eth33:0
}
}
vrrp_instance VI_2 {
state MASTER
interface ens33
virtual_router_id 52
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 5678
}
virtual_ipaddress {
192.168.1.101 dev ens33 label eth33:1
}
}
5.4 web01、web02上都重启服务
systemctl rstart keepalived
5.5 web01、web02分别查看ip
ip add|egrep “192.168.1.100|192.168.1.101”
5.6 轮流暂停keepalived服务,同时查看未暂停服务的web服务器,是否拿到了了IP
其中一个暂停了服务,另一个服务器应当会拿到两个ip
systemctl stop keepalived
ip add|egrep “192.168.1.100|192.168.1.101”
5.7 在停止服务的服务器上,重新启动之前暂停的服务,再次查看
应当看到服务器把ip拿回来了
ip add|egrep “192.168.1.100|192.168.1.101”
5.8 配置区别
| web01 | web02 |
|---|---|
| state MASTER | state BACKUP |
| priority 150 | priority 100 |
| state BACKUP | state MASTER |
| priority 100 | priority 150 |
5.9 主要区别
□state(状态)
□priority(权重/优先级)
优先级决定了VIP在哪个机器上初始运行
6.Nginx配合Keeplived
6.1 逻辑架构图

6.2 配置两边nginx
cd /pwd/nginx/conf/
vim nginx.conf
nginx内容
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type /pwd/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream www_pools { #<== 这里定义了web服务器池,包含了100、101两个web节点。
server 192.168.1.100:80 weight=1;
server 192.168.1.101:80 weight=1;
}
server { #<== 这里定义了代理的负载均衡域名虚拟主机。
listen 192.168.1.55:80; #<==这里指定了IP监听。
server_name [www.hanpi.com](http://www.hanpi.com);
location / {
proxy_pass https://www_pools; #<== 访问[www.hanpi.com](http://www.hanpi.com),请求发送给www_pools里面的节点。
proxy_set_header Host $host;
}
}
}
6.3 配置keepalived服务
6.3.1 配置web01
global_defs {
router_id web01
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100 dev ens33 label eth33:0
}
}
6.3.2 配置web02
global_defs {
router_id web02
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100 dev ens33 label eth33:0
}
}
6.4 配置DNS解析
192.168.1.100 [www.hanpi.com](http://www.hanpi.com)
6.5 两边重启nginx服务
在web页面进入www.hanpi.com
此时关闭web01高可用服务或者关闭服务器
在nginx页面刷新页面
6.6 查看web02的IP状态
ip addd|grep 192.168.1.100
6.7 开启web01,查看ip
ip addd|grep 192.168.1.100
web重新访问 www.hanpi.com
状态应该处于正常
7.监听网卡上不存在的IP地址
如果配置使用了”listen 192.168.1.100:80;“ 指定IP监听服务,而本地上没有这个IP,nginx就会报错。
如果实施双主(即主备)同时提供不同的服务,配置文件里制定了IP监听,备节点就会因为网卡不存在实际IP而报错。
出现上面的问题原因在于物理网卡上没有与配置文件里监听的IP相对应的IP,我们要让Nginx服务在网卡上没有指定监听的IP时也能启动,不报错。
7.1 解决办法是在/etc/sysctl.conf中加入如下内核参数。
net.ipv4.ip_nonlocal_bind = 1
表示启动nginx而忽略配置中监听的ip是否存在,同样适用于Haproxy。
7.2 快速写入
echo “net.ipv4.ip_nonlocal_bind = 1” >> /etc/sysctl.conf
7.3 刷新生效
sysctl -p
8.解决服务宕后keepalived仍运行
默认情况下,Keepalived软件只有在对方机器宕机或者Keepalived停止的时候会接管业务。生产环境中,有业务服务停止的Keepalived还在工作的情况,这种时候就会造成数据丢失。
8.1 方法一:
写守护进程脚本来处理。当Nginx业务出现问题时,就停掉本地的Keepalived服务,实现飘逸接管。
8.1.1 编写脚本
vim /pwd/check_nginx.sh
8.1.2 脚本内容
#!/bin/sh
while true
do
if [ ‘netstat -lntup|grep nginx|wc -l’-ne 1 ];then
systemctl stop keepalived
break
fi
sleep 5
done
8.1.3 启动脚本
sh /pwd/check_nginx.sh &
8.1.4 检查脚本运行情况
ps -ef | grep check
8.1.5 查看端口
lsof -I :80
8.1.6 停止nginx,查看是否切换
systemctl stop nginx
8.1.7 查看nginx状态
systemctl status nginx
8.1.8 再次检查nginx
netstat -lntup|grep nginx
8.1.9 在备节点上查看
ip add|grep 192.168.1.100
8.2 方法二:
8.2.1 使用keepalived的配置文件参数触发脚本
vim check_nginx_proxy.sh
8.2.2 脚本内容
#!/bin/sh
if [ ‘netstat -lntup|grep nginx|wc -l’ -ne 1 ];then
system stop keeplived
fi
8.2.3 授权
chmod +x check_nginx_proxy.sh
8.2.4 检查授权
ls -l check_nginx_proxy.sh
8.2.5 keepalived配置如下
global_defs {
router_id web01
}
vrrp_script chk_nginx_proxy{ #<== 定义VRRP脚本,检查HTTP端口。
script “/pwd/check_nginx_proxy.sh” #<== 执行脚本,当Nginx服务器出现问题时,就停掉Keepalived服务。
interval 2 #<== 时间间隔2s。
weight 2
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100 dev ens33 label eth33:0
}
tarck_script {
check_nginx_proxy #<== 触发检查。
}
}
8.2.6 测试脚本
8.2.6.1 检查端、服务、ip
lsof -i :80
ps -ef | grep keep
ip add|grep 192.168.1.100
8.2.6.2 停止nginx服务
systemctl stop nginx
8.2.6.3 再次检查
lsof -i :80
ps -ef | grep keep
ip add|grep 192.168.1.100
8.2.6.4 查看日志
cat /var/log/messages | grep Keepalived
9.多组Keepalived局域网内冲突
如果在同一局域网内部署了多组Keepalived服务器,而又未使用专门的心跳线通信时,可能会发生接管故障。
Keepalived高可用是通过VRRP协议实现的,VRRP协议默认通过IP多播实现的高可用服务对之间的通信,如果一个局域网内存在多组Keepalived服务器对,就会造成IP多播地址冲突问题,不同组的Keepalived都会使用默认的224.0.0.18作为多播地址。
所以我们需要在同组Keepalived服务器的所有配置文件中指定独立的多播地址。
9.1 指定多播地址 示例:
global_defs {
router_id LVS_01
vrrp_mcast_group4 224.0.0.20 #<== 这玩意就是多播地址
}
10.指定配置文件接收Keepalived服务日志
日志集成,懂得都懂
将KEEPALIVED_OPTIONS=”-D” 修改为 KEEPALIVED_OPTIONS=”-D -d -S 0”
vim /ect/sysconfig/keepalived
10.1 修改keepalived配置文件
10.1.1 快速替换
sed -i ’14 s# KEEPALIVED_OPTIONS=”-D”# KEEPALIVED_OPTIONS=”-D -d -S 0”#g’ /etc/sysconfig/keepalived
10.1.2 检查
sed -n ‘14p’ /etc/sysconfig/keepalived
说明,查看 /etc/sysconfig/keepalived 里注释获得以上说明
—dump-conf -d 导出备份数据。
—log-detail -D 详细日志。
—log-facility -S 设置本地的syslog设备,编号0-7(default=LOG_DAEMON)。
-S 0 表示指定为local0设备。
10.2 修改系统日志配置文件
10.2.1 修改rsslog配置文件
vim /etc/rsyslog.conf
10.2.2 尾部添加以下两行内容
这两行表示local0设备的所有日志信息都记录到了 /var/log/keepalived.log 文件
#keepalived
local0.* /var/log/keepalived.log
10.2.3 在如下信息的第一列尾部添加”;local0.none”,注意有分号。
表示来自local0设备的所有日志信息不再记录与/var/log/messages
*.info;mail.one;authpriv.none;cron.none;local0.none /var/log/messages
10.2.4 配置完成,重启rsyslog服务
systemctl restart rsyslog.service
10.2.5 重启keepaliaved,查看日志
systemctl restart keepalived
tail -f /var/log/keepalived.log
可以在/var/log/messages上设置对/avr/log/keepalived.log进行轮询,防止单个日志文件变大
11.编写监测Keepalived “脑裂”的脚本
检测思路:在备节点上执行脚本,如果可以ping通主节点并且备节点有VIP就报警,人工介入检查是否发生了”脑裂”。
11.1 编写脚本
vim check_split_brain.sh
脚本内容
#!/bin/sh
web01_vip = 192.168.1.100
web01_ip = 192.168.1.55
while true
do
ping -c 2 -W3 $web01_ip &>/dev/null
if [ $? -eq 0 -a ‘ip add|grep “web01_ip”|wc -1’ -eq 1 ]
then
echo “ha is split brain.waring.”
else
echo “hs is ok”
fi
sleep 5
done
11.2 测试脚本
sh check_split_brain.sh
11.2.1 关闭web01,查看web02报警情况
shutdown -h now
or
systemctl stop nginx
11.2.2 web02报警正常,重启web01服务,查看恢复情况
systemctl start nginx
