Keepalived简述

一、简介

Keepalived是一个开源的软件,用于在Linux系统上实现高可用性和负载均衡。它提供了一种简单而可靠的方式来确保关键服务的持续可用性,并将流量分发到多个服务器上以实现负载均衡。

Keepalived的主要功能如下:

  1. 高可用性:通过使用虚拟路由冗余协议(VRRP),Keepalived允许多台服务器组成一个虚拟路由器,并提供一个共享的虚拟IP地址。其中一台服务器被指定为主服务器(Master),负责处理所有的请求,而其他服务器则作为备份服务器(Backup)待命。如果主服务器发生故障或不可用,备份服务器会自动接管主服务器的角色,并继续提供服务,实现高可用性。

  2. 健康检查:Keepalived可以定期检查服务器的健康状态,包括检查服务是否正常运行、服务器的负载情况等。如果服务器不可用或负载过高,Keepalived可以自动将其排除在负载均衡的范围之外,确保只有健康的服务器接收请求。

  3. 负载均衡Keepalived的负载均衡由lvs提供,只需在配置中指定 lb_algo 和 lb_kind 参数,就可以直接使用 LVS 的负载均衡算法和转发模式。LVS介绍

  4. 通知和日志:Keepalived可以配置通知机制,以便在发生故障或状态变化时发送通知。它还提供详细的日志记录,便于故障排查和监控。

Keepalived使用简单的配置文件进行配置,可以通过编辑配置文件来定义虚拟路由器、指定服务器的角色和权重、配置健康检查和负载均衡算法等。一旦配置完成,Keepalived会自动运行并监控服务器的状态,并根据配置执行故障转移和负载均衡。

Keepalived通常用于构建高可用性的网络服务,如负载均衡器、防火墙、虚拟专用网络(VPN)等。它在互联网服务提供商、企业网络和数据中心等环境中广泛应用,提供了一种可靠的方式来确保关键服务的持续可用性和性能优化。

 

VRRP(Virtual Router Redundancy Protocol)是一种网络协议,用于在局域网(LAN)环境中提供虚拟路由器的冗余和故障转移功能。它允许多台路由器共同提供一个虚拟IP地址,确保在主路由器故障时能够无缝地切换到备用路由器,从而实现网络的高可用性。

VRRP的工作原理如下:

  1. 虚拟路由器:VRRP允许多台路由器组成一个虚拟路由器组(VRG),并提供一个虚拟IP地址(Virtual IP,VIP)。这个虚拟IP地址是由VRG中的路由器共享的,作为默认网关提供给局域网上的其他设备。

  2. 主备选举:VRG中的路由器通过选举确定一个主路由器(Master)和一个或多个备用路由器(Backup)。主路由器负责处理所有的数据流量,而备用路由器处于待命状态。

  3. 心跳和状态通告:主路由器通过使用组播地址(224.0.0.18),周期性地发送心跳消息(vrrp包)来宣告自己的存在,并通知其他路由器自己的状态。备用路由器监听心跳消息,以检测主路由器的可用性。

  4. 故障转移:如果主节点失去连接或不可用,备节点中的某台(高优先级)会被选举为新的主节点,并接管主节点的功能,包括继续处理数据流量和提供虚拟IP地址(VIP飘移)。

 

选举机制:

  1. 选举过程:当一个 VRRP 组中的节点启动或检测到其他节点故障时,它们将进入选举过程。在选举过程中,每个节点根据其配置的优先级和其他参数竞争成为主节点。
  2. 优先级:每个节点都配置有一个优先级值。具有较高优先级的节点更有可能成为master节点。通常,优先级值越高,成为master节点的机会就越大。

优先级:

  1. priority 参数:在 Keepalived 配置中,可以为每个节点设置 priority 参数,指定其优先级值。较高的优先级值表示更高的优先级。默认情况下,优先级值为 100。
  2. advert_int 参数:advert_int 参数定义了 VRRP 路由器发送广告消息的时间间隔。较短的广告间隔可以提高 VRRP 节点被选举为主节点的机会。

非抢占模式:

keepalived默认为抢占模式,由参数 perrmpt 控制,抢占模式下,当优先级高的主机恢复在线后,会抢占优先级低的主机的master角色,在网络不稳定时,可能导致 VIP 频繁切换,不利于系统稳定性。

如:利用keepalived做热备,其中一台设置为master,一台设置为backup,master优先级高于backup。当master出现异常后,backup自动切换为master。当backup成为master后,原master恢复正常后由于优先级比当前master节点优先级高,所以原master节点会再次抢占成为master

非抢占模式,由参数 nopreempt 控制,非抢占模式下,当master节点故障,vip飘移,后又恢复正常时,不会抢占成为master节点。当其他节点都异常时,vip会再次偏移到最初的master节点上。

配置:

服务器角色都设置为backup,在优先级高的服务器上设置nopreempt

vrrp_instance VI_1 {
    state BACKUP    #角色为backup
    interface eth0 
    virtual_router_id 51
    priority 100    #优先级要高于其他节点
    nopreempt       #设置成非抢占模式
}

 

二、安装及配置

安装:

yum -y install keepalived

配置文件默认位置:/etc/keepalived/keepalived.conf,配置文件都是以块(block)的形式组成,每一个块的内容都包含在{ }中

全局配置

global_defs {                 #全局配置标识
   notification_email {        #用于设置报警的邮件地址,可以设置多个,每行一个。如果要开启邮件报警,需要开启本机的sendmail服务
     acassen@firewall.loc    
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc    #邮件的发送地址
   smtp_server 192.168.200.1      #邮件的smtp server地址
   smtp_connect_timeout 30        #连接smtp server的超时时间
   router_id LVS_DEVEL            #路由标识,唯一
   vrrp_skip_check_adv_addr       #yes:如果收到的通告报文和上一个报文是同一个路由器,则跳过检查,no:默认值为全检查
   vrrp_strict                    #yes:开启严格模式,Keepalived 将对接收到的 VRRP 广告进行更严格的验证和处理,建议关闭
   vrrp_garp_interval 0           #ARP接口之间发送报文的延迟时间,可以精确到毫秒,默认是0,0表示不延迟
   vrrp_gna_interval 0            #非请求消息的发送延迟时间,默认为0
   script_user root               #指定在执行脚本时使用的用户身份,如果未指定,则用户默认为keepalived_script
}

 

VRRPD配置

VRRP同步组(可选)

VRRP Sync Group(VRRP 同步组)是用于在 VRRP(Virtual Router Redundancy Protocol)环境中实现多个 VRRP 实例之间状态同步和协调的配置机制。它的作用是确保在一个组内的 VRRP 实例之间实现一致性,并在故障发生时实现快速主备切换

VRRP Sync Group 在以下场景中非常有用:

  • 多个 VRRP 实例:当存在多个 VRRP 实例时,可以使用 VRRP Sync Group 来确保它们之间的状态同步和一致性,以实现更高级别的冗余和可用性。
  • 多个网段:当有多个网段(如内网和外网)需要进行冗余和故障转移时,VRRP Sync Group 可以确保这些网段的 VRRP 实例之间的状态同步,并在故障发生时进行快速切换。

比如:有两个网段,一个是内网(192.168.1.0/24),一个是外网(203.0.113.0/24),每个网段都有一个 VRRP 实例来提供冗余。为了确保内外网的一致性和故障转移,可以创建一个名为 "VG_1" 的 VRRP Sync Group,并将内网和外网的 VRRP 实例配置为该组的成员。

vrrp_sync_group VG_1 {                #同步组名称
    group {
        vrrp_instance_internal        #与后文的vrrp_instance实例名称一致。内网 VRRP 实例配置
        vrrp_instance_external        #外网 VRRP 实例配置
    }
}

 

VRRP实例
vrrp_instance VI_1 {        #虚拟路由器实例,VI_1为实例名称
    state MASTER            #指定keepalived的角色,MASTER表示此主机是主服务器,BACKUP表示此主机是备服务器
    interface eth0          #指定检测网络的网卡接口
    virtual_router_id 51    #虚拟路由标识,数字形式,取值范围为0-255,同一个VRRP实例使用唯一的标识,即在同一个vrrp_instance下,master和backup必须一致
    priority 100            #节点优先级,取值范围为1-254,数字越大表示节点的优先级越高,在一个VRRP实例下,MASTER的优先级必须要比BACKUP高,不然就会切换角色
    advert_int 1            #VRRP通告的时间间隔,单位为秒,默认1
    nopreempt               #设置ARRT的抢占模式,yes为禁用抢占模式,默认为no
    preempt_delay 300       #抢占延迟,默认5分钟,单位秒
    authentication {        #认证机制
        auth_type PASS      #认证类型,可选择AH和PASS两种,AH为IPSC互联网安全协议认证,PASS为简单密码认证,推荐PASS认证
        auth_pass 1111      #预共享秘钥设置,仅前8位有效,同一虚拟路由器的多个keepalived节点auth_pass值必须保持一致
    }
    virtual_ipaddress {     #虚拟路由器的IP,并可设置IP对应的子网掩码、网卡和标签等,不指定网卡时默认添加在eth0上,不设置子网掩码时默认为32位
        192.168.200.16      #不同的虚拟IP分行隔开
        192.168.200.17
        192.168.200.18
    }
}

 

负载均衡配置(可选)

默认情况下,Keepalived 主要关注的是 VIP 的高可用性,它将监控 VIP 所在的服务器状态,并在主服务器发生故障时将 VIP 转移到备份服务器上。

例:将keeplived部署在nginx上,设置脚本监控nginx进程状态,由keeplived提供vip对外提供服务,同时保障nginx的高可用性(故障飘移),由nginx提供转发和负载均衡功能。

 

不过Keepalived 也支持负载均衡功能,将请求分发到后端的多个服务器上,通过配置 virtual_server,Keepalived 将负责接收请求,并根据负载均衡算法将请求转发到后端服务器上,以实现负载均衡和高可用性。

例:机器上单独部署keeplived,并配置后端,如tomcat,keeplived提供vip对外服务,对内负责转发请求与负载均衡,tomcat则是实际的服务程序。

virtual_server 192.168.200.100 443 {    #VIP地址,可以是IP+PORT;也可以是fwmark 数字,也就是防火墙规则,要和vrrp_instance模块中的virtual_ipaddress地址一致
    delay_loop 6                        #健康检查时间间隔,单位秒
    lb_algo rr                          #指定lvs负载均衡算法:rr(轮询)|wrr(加权轮询)|lc(最少连接)|wlc|lblc|sh|dh
    lb_kind NAT                         #指定lvs负载均衡的类型,可以是 NAT、DR 或 TUN
    persistence_timeout 50              #持久会话的超时时间(以秒为单位)
    protocol TCP                        #虚拟服务器使用的协议,例如 TCP 或 UDP

    real_server 192.168.201.100 443 {   #后端实际服务器的 IP 地址
        weight 1                        #权重,用于加权轮询负载均衡算法
        
        TCP_CHECK {                     #TCP健康检查(常用)
          connect_port 443              #健康检查的端口,默认为real_server定义的端口
          bindto 192.168.201.100        #健康检查的ip,默认为real_server定义的ip
          connect_timeout 3             #连接超时时间,单位秒
          nb_get_retry 3                #重试次数
          delay_before_retry 3          #重试延迟:在重试前等待 3
        }
        
        HTTP_GET {                      #健康检查方法(不常用)
            url {                       #检测url
              path /testurl/test.jsp    
              digest 640205b7b0fc66c1ea91c463fac6334d    #检测内容的哈希值
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }

    }
    
    real_server 192.168.200.3 1358 {
        ...
    }
}

 

VRRP脚本(可选)

适用于自定义脚本来检测服务或资源状态的场景,可以根据脚本的执行结果来决定实例的状态切换。

注:如果脚本中涉及到weight的配置,同时又关闭了抢占模式时,脚本中应添加杀掉keepalived进程的方式。因为当检测到后端进程出现问题,priority变动时,因关闭了抢占模式,即使本机priority值比其他实例低,仍然不会发生主备切换。

vrrp_script check_web_server {                        #定义脚本模块名称
    script "/usr/local/bin/check_web_server.sh"       #脚本路径;也可以是具体的命令,命令用绝对路径
    interval 2                                        #每隔2秒执行一次
    weight 2                                          #权重,如果脚本执行结果为0,并且weight配置的值大于0,则优先级相应的增加,如果脚本执行结果非0,并且weight配置的值小于0,则优先级相应的减少,其他情况,维持原本配置的优先级
    fall 2                                            #连续失败次数达到2时,将视为脚本执行结果为非 0
}

vrrp_instance VI_1 {
    ...
    track_script {
        check_web_server                              #使用定义好的脚本模块
    }
    ...
    
    
    notify_master "/path/to/script.sh <group_name> master"    #在切换到 Master 角色时执行的脚本或命令,如启动nginx
    notify_backup "/path/to/script.sh <group_name> backup"    #在切换到 Backup 角色时执行的脚本或命令
    notify_fault "/path/to/script.sh <group_name> fault"      #在发生故障时执行的脚本或命令
}

 

三、Keepalived 高可用集群脑裂问题

脑裂是指由于网络故障或其他原因导致 Keepalived 实例之间无法正常通信,从而导致多个实例同时认为自己是主节点,进而导致资源冲突和服务中断的情况

脑裂可能发生的原因包括:

  1. 网络分区:网络分区是指由于网络故障或配置错误,导致 Keepalived 实例之间无法通信,从而使它们无法达成一致的状态。
  2. 通信延迟:在高延迟或拥塞的网络环境中,Keepalived 实例之间的通信可能存在延迟,这可能导致实例之间无法及时达成一致。
  3. 服务器上开启了 iptables 防火墙,阻挡了心跳消息传输。

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

为了解决脑裂问题,可以采取以下措施:

  1. 心跳检测:使用可靠的心跳机制进行实例之间的健康状态检测。这可以包括基于网络连接或专用的心跳通道进行通信。如果一个实例无法与其他实例正常通信,它将认为其他实例已经失去联系,并采取适当的动作。
  2. 投票机制:通过引入投票机制,实例之间可以基于多数原则来决定主节点。这可以减少单点故障和脑裂问题的发生。例如,在 VRRP 中,多个实例之间通过优先级和预选主节点来决定主备角色的切换。
  3. 多个监控点:在不同的子网或物理位置设置多个监控点,以减少网络分区的风险。这样,即使一个监控点无法与其他实例通信,其他监控点仍然可以维持正常的通信和状态同步。

示例:检测节点间通信异常并关闭失去联系的节点的 Keepalived 进程

#!/bin/bash

# 检测节点间通信异常并关闭失去联系的节点的 Keepalived 进程的函数
check_communication() {
    # 获取当前节点的主备状态
    local state=$(keepalived --check-state)
    
    # 获取当前节点的通信接口
    local interface="eth0"  # 替换为实际的通信接口
    
    # 获取当前节点的虚拟路由器ID
    local vrid=51  # 替换为实际的虚拟路由器ID
    
    # 获取其他节点的IP地址列表,替换为实际的IP地址
    local other_nodes=("192.168.0.2" "192.168.0.3" "192.168.0.4")
    
    # 遍历其他节点,检测与每个节点的通信状态
    for node in "${other_nodes[@]}"; do
        # 使用 ping 命令检测与其他节点的通信
        if ! ping -c 3 -I $interface -W 1 $node > /dev/null 2>&1; then
            echo "Communication with node $node is lost. Taking corrective action..."
            
            # 关闭失去联系节点的 Keepalived 进程
            killall keepalived
            
            # 删除失去联系节点的状态文件,以便后续重新启动 Keepalived
            rm -f /var/run/keepalived/vrrp_${vrid}_${node}.state
        fi
    done
}

# 主程序
main() {
    while true; do
        # 检测节点间通信异常并关闭失去联系的节点的 Keepalived 进程
        check_communication
        
        # 等待一段时间后再次检测,可以根据实际情况调整等待时间
        sleep 5
    done
}

# 执行主程序
main

 

四、主备,双主,多主

4.1 主备

一般情况下,用的是主备结构,平常由master节点提供服务,backup节点做备份,当master节点故障时,vip飘移到backup节点上,将backup节点变成master节点提供服务。

 

主节点配置(抢占模式):

! Configuration File for keepalived

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.168.1.100
    }
}

virtual_server 192.168.1.100 443 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.1.101 80 {
        weight 1
        
        TCP_CHECK {
          connect_port 443
          bindto 192.168.1.101
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
        }
        
        HTTP_GET {
            url {
              path /testurl/test.jsp    
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }

    }
    
    real_server 192.168.1.102 80 {
        weight 1
     TCP_CHECK {
          connect_port 443
          bindto 192.168.1.102
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
       }
   }
}

备节点配置:

! Configuration File for keepalived

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        192.168.1.100
    }
}

virtual_server 192.168.1.100 443 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.1.101 80 {
        weight 1
        
        TCP_CHECK {
          connect_port 443
          bindto 192.168.1.101
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
        }
        
        HTTP_GET {
            url {
              path /testurl/test.jsp    
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }

    }
    
    real_server 192.168.1.102 80 {
        weight 1
     TCP_CHECK {
          connect_port 443
          bindto 192.168.1.102
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
       }
   }
}

 

4.2 双主

在大流量的场景下,所有流量通过一台机器去分发请求,很容易打满机器负载,造成请求延时,甚至机器宕机。所以,keepalived还支持双主,多主的形式,让多台机器负载流量,减少性能损耗的同时还保证其高可用性。

 

双主即集群有两个主节点,共同向外提供服务,每个主节点有一个vip,如果一个主节点故障,流量会全部切换到另一个主节点上。多主模式也是相同原理。

配置: vrrp_instance 模块配置两个vrrp实例,互为主备。

主节点1:

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mypassword
    }
    virtual_ipaddress {
        192.168.0.100
    }
}

vrrp_instance VI_2 {
    state BACLUP
    interface eth0
    virtual_router_id 52
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mypassword
    }
    virtual_ipaddress {
        192.168.0.101
    }
}

主节点2:

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mypassword
    }
    virtual_ipaddress {
        192.168.0.100
    }
}

vrrp_instance VI_2 {
    state MASTER
    interface eth0
    virtual_router_id 52
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mypassword
    }
    virtual_ipaddress {
        192.168.0.101
    }
}

 

posted @ 2024-04-16 16:15  心恩惠动  阅读(34)  评论(0编辑  收藏  举报