Keepalived介绍

  • Keepalived软件起初是专门为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入了可以实现高可用的VRRP功能。因此,Keepalived除了能够管理LVS软件外,还可以作为其他服务(例如:Nginx,Haproxy,MySQL等)的高可用解决方案软件。
  • Keepalived软件主要是通过VRRP协议实现高可用功能的。VRRP是Virtual Router Redundancy Protocol(虚拟路由器冗余协议)的缩写,VRRP出现的目的就是为了解决静态路由单点故障问题的,他能够保证当个别节点宕机时,整个网络可以不间断地运行。所以,Keepalived一方面具有配置管理LVS的功能,同时还具有对LVS下面节点进行健康检查的功能,另一方面也可实现系统网络服务的高可用功能。

Keepalived的重要功能

  • (1) 管理LVS负载均衡软件:早期的LVS软件,需要通过命令行或脚本实现管理,并且没有针对LVS节点的健康检查功能。为了解决LVS的这些使用不便问题,Keepalived诞生了,可以说,Keepalived软件起初是专为解决LVS的问题而诞生的。因此,Keepalived和LVS的感情很深,他们的关系如同夫妻一样,可以紧密地结合,愉快地工作。Keepalived可以通过读取自身的配置文件,实现通过更底层的接口直接管理LVS的配置以及控制服务的启动,停止功能,这使得LVS的应用更加简单方便了。
  • (2) 实现对LVS集群节点健康检查功能(healthcheck):Keepalived可以通过在自身的Keepalived.conf文件里配置LVS的节点IP和相关参数实现对LVS的直接管理;除此之外,当LVS集群中的某一个甚至是几个节点服务器同时发生故障无法提供服务时,Keepalived服务会自动将失效的节点服务器从LVS的正常转发队列中清除出去,并将请求调度到别的正常节点服务器上,从而保证最终用户的访问不受影响;当故障的节点服务器被修复以后,Keepalived服务又会自动地把它们加入到正常转发队列中,对客户提供服务。
  • (3) 作为系统网络服务的高可用功能(failover):Keepalived高可用功能实现的简单原理为,两台主机同时安装好Keepalived软件并启动服务,开始正常工作时,由角色为Master的主机获得所有资源并对用户提供服务,角色为Backup的主机作为Master主机的热备;当角色为Master的主机失效或出现故障时,角色为Backup的主机将自动接管Master主机的所有工作,包括接管VIP资源及相应资源服务;而当角色为Master的主机故障修复后,又会自动接管回它原来处理的工作,角色为Backup的主机则同时释放Master主机失效时它接管的工作,此时,两台主机将恢复到最初启动时各自的原始角色及工作状态。

Keepalived如何故障切换实现高可用?

  • (1) Keepalived高可用服务之间的故障切换转移,是通过VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议)来实现的。
    • (a) VRRP,全称Virtual Router Redundancy Protocol,中文名为虚拟路由冗余协议,VRRP的出现就是为了解决静态路由的单点故障问题,VRRP是通过一种竞选机制来将路由的任务交给某台VRRP路由器的。
    • (b) VRRP早期是用来解决交换机,路由器等设备单点故障的,下面是交换,路由的Master和Backup切换原理描述,同样适用于Keepalived的工作原理。
    • (c) 在一组VRRP路由器集群中,有多台物理VRRP路由器,但是这多台物理的机器并不是同时工作的,而是由一台称为Master的机器负责路由工作,其他的机器都是Backup。Master角色并非一成不变的,VRRP会让每个VRRP路由参与竞选,最终获胜的就是Master。获胜的Master有一些特权,比如拥有虚拟路由器的IP地址等,拥有系统资源的Master负责转发发送给网关地址的包和响应ARP请求。
    • (d) VRRP通过竞选机制来实现虚拟路由器的功能,所有的协议报文都是通过IP多播(Multicast)包(默认的多播地址224.0.0.18)形式发送的。虚拟路由器由VRID(范围0-225)和一组IP地址组成,对外表现为一个周知的MAC地址:00-00-5E-00-01-{VRID}。所以,在一个虚拟路由器中,不管谁是Master,对外都是相同的MAC和IP(称之为VIP)。客户端主机并不需要因Master的改变而修改自己的路由配置。对他们来说,这种切换是透明的。
    • (e) 在一组虚拟路由器中,只有作为Master的VRRP路由器会一直发送VRRP广播包(VRRP Advertisement messages),此时Backup不会抢占Master。当Master不可用时,Backup就收不到来自Master的广播包了,此时多台Backup中优先级最高的路由器会抢占为Master。这种抢占是非常快速的(可能只有1秒甚至更少),以保证服务的连续性。出于安全性考虑,VRRP数据包使用了加密协议进行了加密。
  • (2) 在Keepalived服务正常工作时,主Master节点会不断地向备节点发送(多播的方式)心跳消息,用以告诉备Backup节点自己还活着,当主Master节点发生故障时,就无法发送心跳消息,备节点也就因此无法继续检测到来自主Master节点的心跳了,于是调用自身的接管程序,接管主Master节点的IP资源及服务。而当主Master节点恢复时,备Backup节点又会释放主节点故障时自身接管的IP资源及服务,恢复到原来的备用角色。

Keepalived工作原理

  • keepalived可提供vrrp以及health-check功能,可以只用它提供双机浮动的vip(vrrp虚拟路由功能),这样可以简单实现一个双机热备高可用功能;keepalived是以VRRP虚拟路由冗余协议为基础实现高可用的,可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip(该路由器所在局域网内其他机器的默认路由为该vip),master会发组播,当backup收不到VRRP包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master。这样的话就可以保证路由器的高可用了。

Keepalived的组件图

    Linux下实现高可用软件-Keepalived基础知识梳理-LMLPHP

上图是Keepalived的功能体系结构,大致分两层:用户空间(user space)和内核空间(kernel space)。

  • 内核空间:主要包括IPVS(IP虚拟服务器,用于实现网络服务的负载均衡)和NETLINK(提供高级路由及其他相关的网络功能)两个部份。
  • 用户空间:
    • WatchDog:负载监控checkers和VRRP进程的状况
    • VRRP Stack:负载负载均衡器之间的失败切换FailOver,如果只用一个负载均稀器,则VRRP不是必须的。
    • Checkers:负责真实服务器的健康检查healthchecking,是keepalived最主要的功能。换言之,可以没有VRRP Stack,但健康检查healthchecking是一定要有的。
    • IPVS wrapper:用户发送设定的规则到内核ipvs代码
    • Netlink Reflector:用来设定vrrp的vip地址等。

Keepalived的所有功能是配置keepalived.conf文件来实现的。

 Keepalived正常启动的时候,共启动3个进程

  • 一个是父进程,负责监控其子进程;一个是VRRP子进程,另外一个是checkers子进程;两个子进程都被系统watchlog看管,两个子进程各自负责复杂自己的事。
  • Healthcheck子进程检查各自服务器的健康状况,,例如http,lvs。如果healthchecks进程检查到master上服务不可用了,就会通知本机上的VRRP子进程,让他删除通告,并且去掉虚拟IP,转换为BACKUP状态。

  注意:keepalived和LVS完全是两码事,只不过他们各负其责相互配合而已。

Keepalived高可用服务器的“裂脑”问题——什么是裂脑。

  • 由于某些原因,导致两台高可用服务器对在指定时间内,无法检测到对方的心跳消息,各自取得资源及服务的所有权,而此时的两台高可用服务器对都还活着并在正常运行,这样就会导致同一个IP或服务在两端同时存在而发生冲突,最严重的是两台主机占用同一个VIP地址,当用户写入数据时可能会分别写入到两端,这可能会导致服务器两端的数据不一致或造成数据丢失,这种情况就被称为裂脑。

导致裂脑发生的原因,有以下几种原因:

  • 高可用服务器对之间心跳线链路发生故障,导致无法正常通信。
  • 心跳线坏了(包括断了,老化)
  • 网卡及相关驱动坏了,IP配置及冲突问题(网卡直连)。
  • 心跳线间连接的设备故障(网卡及交换机)
  • 仲裁的机器出问题(采用仲裁的方案)
  • 高可用服务器上开启了iptables防火墙阻挡了心跳消息传输
  • 高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败。
  • 其他服务配置不当等原因,如心跳方式不同,心跳广播冲突,软件BUG等

提示:Keepalived配置里同一VRRP实例如果virtual_router_id两端参数配置不一致,也会导致裂脑问题发生。

解决裂脑的常见方案。

  • 同时使用串行电缆和以太网电缆连接,同时用两条心跳线路,这样一条线路坏了,另一个还是好的,依然能传送心跳消息。
  • 当检测到裂脑时强行关闭一个心跳节点(这个功能需特殊设备支持,如Stonith,fence)。相当于备节点接收不到心跳消息,通过单独的线路发送关机命令关闭主节点的电源。
  • 做好对裂脑的监控报警(如邮件及手机短信等或值班),在问题发生时人为第一时间介入仲裁,降低损失。

下面是生产场景检测裂脑故障的一些思路:

  • (1)简单判断的思想:只要备节点出现VIP就报警,这个报警有两种情况,一是主机宕机了备机接管了;二是主机没宕,裂脑了。不管属于哪个情况,都进行报警,然后由人工查看判断及解决。
  • (2)比较严谨的判断:备节点出现对应VIP,并且主节点及对应服务(如果能远程连接主节点看是否有VIP就更好了)还活着,就说明发生裂脑了。

 第一部分:Keepalived软件安装过程:【官方下载载点:源码包;第三方下载载点:rpm包

  • 准备环境
  • 以KeepAlived-Master为例。(KeepAlived-Backup相同操作)
# 修改主机名
[root@locahost ~]# hostnamectl set-hostname --static KeepAlived-Master && exec bash

# 查看系统版本信息
[root@KeepAlived-Master ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
[root@KeepAlived-Master ~]# uname -r
3.10.0-862.el7.x86_64

# 关闭SELinux及firewalld
[root@KeepAlived-Master ~]# sed -i '7s/enforcing/disabled/' /etc/selinux/config
[root@KeepAlived-Master ~]# setenforce 0
[root@KeepAlived-Master ~]# systemctl stop firewalld && systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@KeepAlived-Master ~]# hostname -I
172.16.70.37

# 查找centos7自带keepalived版本
[root@KeepAlived-Master ~]# yum list | grep keepalived
keepalived.x86_64                           1.3.5-19.el7               base

# 安装基础软件
[root@KeepAlived-Master ~]# yum install -y vim net-tools wget curl lrzsz lsof

# 安装依赖并下载keepalived
[root@KeepAlived-Master ~]# yum install -y openssl openssl-devel libnl libnl-devel gcc
[root@KeepAlived-Master ~]# wget www.keepalived.org/software/keepalived-2.0.20.tar.gz
[root@KeepAlived-Master ~]# md5sum keepalived-2.0.20.tar.gz
a5966e8433b60998709c4a922a407bac  keepalived-2.0.20.tar.gz
[root@KeepAlived-Master ~]# tar -xf keepalived-2.0.20.tar.gz
[root@KeepAlived-Master ~]# cd keepalived-2.0.20
[root@KeepAlived-Master keepalived-2.0.20]# ./configure --help | less    # 查看选择适合的编译参数
[root@KeepAlived-Master keepalived-2.0.20]# ./configure --prefix=/usr/local/app/keepalived --with-systemdsystemunitdir=/usr/local/app/keepalived --enable-log-file
......
....最后正常编译完成后如下
Keepalived configuration
------------------------
Keepalived version       : 2.0.20
Compiler                 : gcc
Preprocessor flags       : -D_GNU_SOURCE
......
......
Linker flags             : -pie -Wl,-z,relro -Wl,-z,now
Extra Lib                : -lm -lcrypto -lssl -lnl
Use IPVS Framework       : Yes
IPVS use libnl           : Yes
IPVS syncd attributes    : No
IPVS 64 bit stats        : No
HTTP_GET regex support   : No
fwmark socket support    : Yes
Use VRRP Framework       : Yes
Use VRRP VMAC            : Yes
Use VRRP authentication  : Yes
With ip rules/routes     : Yes
With track_process       : Yes
With linkbeat            : Yes
Use BFD Framework        : No
SNMP vrrp support        : No
SNMP checker support     : No
SNMP RFCv2 support       : No
SNMP RFCv3 support       : No
DBUS support             : No
SHA1 support             : No
Use JSON output          : No
libnl version            : 1
Use IPv4 devconf         : No
Use iptables             : Yes
Use libiptc              : No
Use libipset             : No
Use nftables             : No
init type                : systemd
Strict config checks     : No
Build genhash            : Yes
Build documentation      : No

[root@KeepAlived-Master keepalived-2.0.20]# make -j 4 && make install

# 设置环境变量
[root@KeepAlived-Master ~]# ls /usr/local/app/keepalived/
bin  etc  keepalived.service  sbin  share
[root@KeepAlived-Master ~]# ln -s /usr/local/app/keepalived/sbin/keepalived /usr/local/sbin/
[root@KeepAlived-Master ~]# ls -l /usr/sbin/keepalived
lrwxrwxrwx. 1 root root 42 Sep 18 14:31 /usr/sbin/keepalived -> /usr/local/apps/keepalived/sbin/keepalived
[root@KeepAlived-Master ~]# keepalived -v
Keepalived v2.0.20 (01/22,2020)

Copyright(C) 2001-2020 Alexandre Cassen, <acassen@gmail.com>

Built with kernel headers for Linux 3.10.0
Running on Linux 3.10.0-862.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018

configure options: --prefix=/usr/local/app/keepalived --with-systemdsystemunitdir=/usr/local/app/keepalived --enable-log-file

Config options:  LVS VRRP VRRP_AUTH OLD_CHKSUM_COMPAT FIB_ROUTING FILE_LOGGING LOG_FILE_APPEND

System options:  PIPE2 SIGNALFD INOTIFY_INIT1 VSYSLOG ...... INET6_ADDR_GEN_MODE SO_MARK SCHED_RESET_ON_FORK

[root@KeepAlived-Master ~]# keepalived -h
Usage: keepalived [OPTION...]
  -f, --use-file=FILE          Use the specified configuration file
  -P, --vrrp                   Only run with VRRP subsystem
  -C, --check                  Only run with Health-checker subsystem
      --all                    Force all child processes to run, even if have no configuration
  -l, --log-console            Log messages to local console
  -D, --log-detail             Detailed log messages
  -S, --log-facility=[0-7]     Set syslog facility to LOG_LOCAL[0-7]
  -G, --no-syslog              Don't log via syslog
  -u, --umask=MASK             umask for file creation (in numeric form)
  -X, --release-vips           Drop VIP on transition from signal.
  -V, --dont-release-vrrp      Don't remove VRRP VIPs and VROUTEs on daemon stop
  -I, --dont-release-ipvs      Don't remove IPVS topology on daemon stop
  -R, --dont-respawn           Don't respawn child processes
  -n, --dont-fork              Don't fork the daemon process
  -d, --dump-conf              Dump the configuration data
  -p, --pid=FILE               Use specified pidfile for parent process
  -r, --vrrp_pid=FILE          Use specified pidfile for VRRP child process
  -c, --checkers_pid=FILE      Use specified pidfile for checkers child process
  -a, --address-monitoring     Report all address additions/deletions notified via netlink
  -s, --namespace=NAME         Run in network namespace NAME (overrides config)
  -m, --core-dump              Produce core dump if terminate abnormally
  -M, --core-dump-pattern=PATN Also set /proc/sys/kernel/core_pattern to PATN (default 'core')
  -i, --config-id id           Skip any configuration lines beginning '@' that don't match id
                                or any lines beginning @^ that do match.
                                The config-id defaults to the node name if option not used
      --signum=SIGFUNC         Return signal number for STOP, RELOAD, DATA, STATS
  -t, --config-test[=LOG_FILE] Check the configuration for obvious errors, output to
                                stderr by default
  -v, --version                Display the version number
  -h, --help                   Display this help message

# keepalived配置文件
[root@KeepAlived-Master ~]# cd /usr/local/app/keepalived/
[root@KeepAlived-Master keepalived]# ls
bin  etc  keepalived.service  logs  run  sbin  share
[root@KeepAlived-Master keepalived]# cp etc/keepalived/keepalived.conf etc/keepalived/keepalived.conf_bak
[root@KeepAlived-Master keepalived]# diff etc/keepalived/keepalived.conf etc/keepalived/keepalived.conf_bak
21c21
<     interface ens33  # 修改此行
---
>     interface eth0
23c23
<     priority 110    # 修改此行
---
>     priority 100

---------------------------------------------------------------------------------
# Master与Bacpup对比的差异项如下
[root@KeepAlived-Master keepalived]# diff keepalived.conf keepalived.conf_BACKUP
20c20
<     state MASTER
---
>     state BACKUP
23c23
<     priority 110
---
>     priority 100
---------------------------------------------------------------------------------

# 根据编译安装,自行创建systemd管理
[root@KeepAlived-Master ~]# vim /usr/lib/systemd/system/keepalived.service
[Unit]
Description=LVS and VRRP High Availability Monitor
After=network-online.target syslog.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/keepalived.pid    # 自定义项
KillMode=process
EnvironmentFile=-/usr/local/app/keepalived/etc/sysconfig/keepalived    # 自定义项
ExecStart=/usr/local/app/keepalived/sbin/keepalived -f /usr/local/app/keepalived/etc/keepalived/keepalived.conf $KEEPALIVED_OPTIONS    # 自定义项
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

[root@KeepAlived-Master ~]# systemctl daemon-reload
[root@KeepAlived-Master ~]# systemctl start|stop|restart keepalived
[root@KeepAlived-Master ~]# ps -ef| grep keepalived
root       8235      1  0 15:37 ?        00:00:00 /usr/local/app/keepalived/sbin/keepalived -f /usr/local/app/keepalived/etc/keepalived/keepalived.conf -D -S 0
root       8236   8235  1 15:37 ?        00:00:03 /usr/local/app/keepalived/sbin/keepalived -f /usr/local/app/keepalived/etc/keepalived/keepalived.conf -D -S 0
root       8237   8235  0 15:37 ?        00:00:00 /usr/local/app/keepalived/sbin/keepalived -f /usr/local/app/keepalived/etc/keepalived/keepalived.conf -D -S 0
root       8249   1149  0 15:41 pts/0    00:00:00 grep --color=auto keepalived
[root@KeepAlived-Master ~]# ip addr | grep '192.168.200'
    inet 192.168.200.16/32 scope global ens33
    inet 192.168.200.17/32 scope global ens33
    inet 192.168.200.18/32 scope global ens33

# 设置开机自启动
[root@KeepAlived-Master ~]# systemctl enable keepalived
[root@KeepAlived-Master ~]# systemctl list-unit-files | grep keepalived
keepalived.service                            enabled

# 开启keepalived日志
[root@KeepAlived-Master ~]# vim /usr/local/app/keepalived/etc/sysconfig/keepalived
.....修为如下
KEEPALIVED_OPTIONS="-D -S 0"

[root@KeepAlived-Master ~]# echo "local0.*            /usr/local/app/keepalived/logs/keepalived.log" >> /etc/rsyslog.conf
[root@KeepAlived-Master ~]# systemctl restart rsyslog
09-27 12:55