Keepalived工作原理、高可用分析及脑裂等问题解决方式

一、VRRP

1.1 VRRP协议

虚拟路由冗余协议(virtual router redundancy protocol,简称VRRP),是由IETF提出的解决局域网中配置静态网关出现单点失效现象的路由协议,1998年已推出正式的RFC2338协议标准,VRRP广泛应用在边缘网络中,它的设计目标是支持特定情况下IP数据流量失败转移不会引起混乱,允许主机使用单路由器,以及及时在实际第一跳路由器使用失败的情形下仍能够维护路由器间的连通性。

1.2 VRRP术语

  • 虚拟路由器
    • 由一个Master路由器和多个Backup路由器组成,主机将虚拟路由器当作默认网关
  • VRID
    • 虚拟路由器的标识,有相同VRID的一组路由器构成一个虚拟路由器
  • Master路由器
    • 虚拟路由器中承担报文转发任务的路由器,即主节点(仅能有一个)
  • Backup路由器
    • Master路由器出现故障时,能够代替Master路由器工作的路由器,即备用节点(可以有多个)
  • 虚拟IP地址(VIP)
    • 虚拟路由器的IP地址,已改为虚拟路由器可以拥有一个或多个IP地址
  • IP地址拥有者
    • 接口IP地址与虚拟IP地址相同的路由器被称之为IP地址拥有者
  • 虚拟MAC地址(VMAC)
    • 一个虚拟路由器拥有一个虚拟MAC地址,虚拟路由器回应ARP请求使用的是虚拟MAC地址
  • 优先级
    • VRRP根据优先级来确定虚拟路由器中每台路由器的地位。
  • 非抢占方式
    • 若Backup路由器工作在非抢占模式下,则只要Master路由器没有故障,Backup路由器即使随后被配置了更高的优先级也不会成为Master路由器
  • 抢占方式
    • 如果backup路由器工作在抢占方式下, 当它收到VRRP报文后,会将自己的优先级与通告报文中的优先级进行比较,如果自己的优先级比当前的Master优先级高,就会主动抢占成为Master路由器,否则,将保持Backup状态

1.3 VRRP工作过程

  • 1、虚拟路由器中的路由器根据优先级选举出Master,Master通过发送ARP报文,将自己的虚拟MAC地址发送给其它设备和主机
  • 2、Master路由器周期性发送VRRP报文,以公布其配置信息(优先级等)和工作状态
  • 3、如果Master路由器出现故障, 虚拟路由器的backup路由器根据优先级重新选举新的Master
  • 4、虚拟路由器状态切换时,新的Master路由器只是简单地发送一个携带虚拟路由器的MAC地址和IP地下信息的ARP报文,这样就可以更新与它连接的主机或设备中的ARP相关信息,网络中的主机感知不到Master的切换
  • 5、backup路由器优先级高于master路由器时,由backup路由的工作方式(抢占或非抢占方式)决定是否重新选举Master
  • VRRP优先级的取值范围为0-255(数值越大优先级越高),可配置的范围为1到254,优先级0为系统保留给路由器放弃master位置时使用,255则是系统保留给IP地址拥有者使用,当路由器为IP地址拥有者时,其优先级始终为255,当虚拟路由器拥有虚拟IP地址时,只要其工作正常,则为Master路由器。

1.4 路由通告的工作原理

  • Master路由器周期发送VRRP报文,在虚拟路由器中公布其配置信息(优先级)和工作状态,backup路由器通过接收vrrp报文情况来判断master是否工作正常
  • master路由器主动放弃master地位时,发送优先级为0的VRRP报文,致使backup路由器切换为master路由器,这个切换时间为skew time, 计算方式为:(256-backup路由器的优先级/256,单位为秒)
  • 当master路由器发送网络故障不能发送VRRP报文的时,backup路由器不能立即知道其工作状态,backup路由器等待一段时间后,如果还没有收到VRRP报文, 会认为master工作不正常, 而把自己升级为master路由器,周期发送VRRP报文,如果此时多个backup路由器竞争master路由的位置,将通过优先级选举master路由器,backup路由器默认等待的时间为master_down_interval,取值为:(3*VRRP报文的发送时间间隔+skew time,单位为秒)
  • 在性能不稳定的网络中, backup路由器可能因为网络堵塞而在master_down_interval期间没有收到master路由的报文,而主动抢占master位置, 如果此时master报文又到达了, 就会出现虚拟路由器的成员频繁的进行master抢占现象,为了缓解这种情况发生,特制定了延迟等待定时器,它可以使得backup路由器在等待了master_down_interval后,再等待延迟等待时间,如果在此期间仍然没有收到VRRP报文,则此backup路由器才会切换为master路由器,对外发送VRRP报文。

1.5 VRRP实现的工作

  • 路由选举
  • 路由状态通知
  • 为了提高安全性,VRRP还软件娃娃了认证功能

1.6 VRRP认证方式

  • 无认证
  • 简单字符认证,通常用于局域网
  • MD5认证,跨越互联网

1.7 VRRP高可用工作模型

  • 主备备份

    • 主备备份方式表示业务仅由Master路由器承担,当Master路由器出现故障时,才会由选举出来的Backup路由器接替它的工作,如下图:
      Keepalived工作原理、高可用分析及脑裂等问题解决方式_第1张图片
       
  • 主主备份

    • 在路由器的一个接口上可以创建多个虚拟路由器,使得该路由器可以在一个虚拟路由器中作为Master路由器,同时在其它的虚拟路由器中作为Bacup路由器,主主备份模式可以实现负载分担方式,是指多台路由器同时承担业务,因此负载分担方式需要两个或两个以上的虚拟路由器,每个虚拟路由器都包括一个Master路由器和若干个Backup路由器。各虚拟路由器的Master路由器可以不相同,如下图:
      Keepalived工作原理、高可用分析及脑裂等问题解决方式_第2张图片

 

二、keepalived

2.1 keepalived架构

keepalived程序是vrrp协议在linux主机上以守护进程方式的实现,能够根据配置文件生成IPVS规则 ,并对各real server的健康做检测,以及Loadbalance主机和backup主机之间failover的实现,keepalived在Centos6.4+收录到了发行版光盘中。

Keepalived工作原理、高可用分析及脑裂等问题解决方式_第3张图片

  • 核心组件
    • Watchdog : 高可用监视器(监控服务本身,可实现重启的)
    • Checkers : 健康状态检测器,可实现如下协议
      • TCP
      • HTTP
      • SSL
      • MISC
    • SMTP : 支持发送邮件通知机制
    • System Call : 通过系统调用做出管理操作
    • VRRP stack : VRRP栈的实现,实现VRRP协议调用
    • NetLink Reflectior : VRRP借助于netlink监控网络,实现网络功能配置
    • Ipvs wrapper : ipvs控制
  • IO复用器
  • 内存管理
  • 控制面板(配件文件分析器,以实现应用配置文件)

2.2 keepalived工作原理

  • 1、主节点主动向备用节点发送存活通知消息(只是3层判断)
  • 2、发送存活通知消息机制:
    • 广播(broadcast)
    • 组播(multicast)
    • 单播(unicast)
  • 3、设定各服务器的优先级,优先级判断方法
    • 手动设定
    • 根据IP地址数值大小,大的优先级高
    • 随机的挑选
  • 4、需要监控服务器的存活状态,如果服务故障需要重启服务,如重启服务无效,就需要降低主节点的优先级
  • 5、各节点需要安装keepalive服务,并且都加入到同一个集群中,并且每个节点都监听在某个套接字止,不断向外传递心跳信息
  • 6、多个节点配置域共享密钥,防止有人恶意加入集群
  • 7、集群自行决定来启动服务,不能够也不应该手动启动(建立策略来决定哪个节点启动服务)
  • 8、将多个资源绑定在一起,一同调用或配置
  • 9、模拟VRRP协议,实现地址飘移,keepalived仅能飘移IP地址
  • 10、不能转移服务,内置了一个模块,能直接向内核的ipvs添加规则,创建一人LVS(keepalved天生高可用lvs)
  • 11、内置的提供了一个接口,可以通过编写脚本,来检测服务的状态,根据返回的状态,如果发生了故障,就主动降低服务器的优先级(vrrp_script,track_script)

2.3 Keepalived高可用集群配置前提

  • 各节点时间要同步,一般使用网络时间服务器
  • 确保iptables及selinux服务关闭
  • 各节点之间可通过主机名互相通信,节点的名称设定与hosts文件中解析的主机名都要保持一致(AIS架构必须项)
    • uname -n 获得主机名,与解析的主机名要相同
  • 各节点基于密钥认证的方式通过ssh互信通信

三、keepalived配置详解

/etc/keepalived/keepalived.conf

  • Global configuration : 全局配置

      global_defs {
          ...
      }
  • VRRP Configuration : 配置VRRP实例

      vrrp_instance NAME {
          ...
    
      }
  • LVS Configuration : IPVS的相关配置

      virtual_server IP PORT {
          ...
          real_server IP PORT {
              ...
          }
      }

3.1 Global指令

  • notification_email {} : 邮件通知的对象,收件人邮箱
  • notification_email_from : 发件人邮箱
  • smtp_server : 邮件发送服务器IP地址
  • smtp_connect_timeout : 连接邮件服务器的超时时长
  • router-id HOSTNAME : 物理节点的标识符,建议使用主机名
  • vrrp_mcast_grou4 224.0.0.18 : vrrp的多播地址,IPV4,默认为224.0.0.18
  • vrrp_mcast_group6 ff02::12 : vrrp的多播地址, IPV6
  • vrrp_script NAME { } : 定义脚本,可以在vrrp_instance中使用track_script引用
    • script COMMAND : script是固定字段,后面为脚本的内容,有空格需要使用引号包括起来
    • interval # : 间隔多长时间进行状态查看,以秒为单位
    • weight [+|-] # : 如果脚本的返回状态是失败的,将优先级减去相应的数值
  • nopreempt : 定义为非抢占模式
  • preempt_delay TIME : 定义为延迟抢占模式

3.2 VRRP_instance指令

  • state MASTER | BACKUP : 在当前VRRP实例中(虚拟路由器组)此节点的初始实例
  • Interface IFACE_NAME : vrrp用于绑定VIP的接口,各节点网卡接口名称需保持一致
  • virtual_route_id # : 虚拟路由器的ID(VRID),可用值为0-255,默认为51
  • priority # : 当前路由器节点的优先级,可用范围为0-255
  • advert_in # : 通告时间间隔,单位是秒种,默认是1秒
  • authentication { } : 定义认证的特殊引用段
    • auth type PASS : 指定集群密钥方式
    • auth_pass 1234 : 字符密钥吸有前8个有效
  • virtual_ipaddress { } : 定义集群中主机的特殊引用
    • \/brd \Dev\scope \label \
  • notify_master | : 当前节点转为主节点触发的脚本
  • notify_backup | : 当前节点转为备用节点触发的脚本
  • notify_fault | : 当前节点出现故障时触发的脚本
  • notify | : 一般情况下, 只使用上面三个, 或者只使用下面一个
  • track_script { VRRP_SCRIPT_NAME } : 使用此引用,可以调用vrrp_script定义的脚本并执行
  • track_script { IFACE_NAME } : 调用vrrp_script内置方法,可以判断主机的网络接口是否正常,如果不正常将自动降低其权重,转为backup模式

3.3 virtual_server指令

  • delay_loop : 延迟多长时间检测集群服务是否OK
  • lb_algo rr|wrr|lc|wlc|lblc|sh|dh : lvs的调度算法
  • lb_kind NAT|DR|TUN : lvs的类型,如需支持fullnat,需要打补丁
  • persistence_timeout : 持久时长,0表示不启用
  • nat_mask 255.255.255.0 : IP掩码地址,此处的nat没有写错
  • protocol TCP : lvs调度的协议,默认是udp,如果是udp可以不用添加此指令
  • virtual_host : 对哪个虚拟主机做健康状态检测,可以不定义
  • quorum : 最少法定票数,判断realserver有几台才是OK的
  • quorum_up : 添加票数
  • quorum_down : 降低票数
  • sorry_server : 定义sorry server
  • real_server IP PORT { } :定义一个real_server主机
    • weight : 权重
    • inhibit_no_failure : 如果检测失败,就把权重设置为0
    • notify_up | : realserver上线通知,依赖脚本完成
    • notify_down | : realserver下线通知,依赖脚本完成
    • HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK : 对后端的realserver主机,使用相应的方法做健康状态检测
      • url { } : 对url做健康检测的特殊引用
        • path : 检测的url路径
        • status_code : 依赖返回状态码进行检测
        • digest : 依赖页面的hash值进行检测,基于genhash命令完成hash值计算
      • nb_get_retry : get请求的重试次数
      • delay_befor_retry : 两次重试之间的时间间隔,要延迟多长时间,再retry
      • connect_ip : 默认会按real server的IP做健康状态检测,一般不需要再写,但有的时候可能有一个IP专门做健康状态检测的IP,故要手动添加上去
      • connect_port : 连接的端口
      • bindto : 如果keepalived主机有多个IP,定义用哪个IP完成健康状态检测
      • connect_timeout : 连接超时时长,默认为5秒,但这个时长比较长, 建议调整至3秒
      • warmup : 做健康状态检测的延迟, 即keepalived服务起来后,等待多长时间再开始健康状态检测,有时候后端的real server还未启动完成,故需要等待一段时间
    • TCP_CHECK { } : 传输层健康状态检测
      • connect_timeout : 连接超时时长
      • connect_ip : 检测的realserver的IP,一般不需要写,同url中的参数一样
      • connect_port : 检测的realserver的port,一般不需要写,同url中的参数一样
      • bindto : 同url中的参数一样
      • bind_port : 使用哪个端口做健康状态检测

3.4 主备模式的可高可用nginx的配置实例

实验环境:
172.16.36.70
172.16.36.71
######172.16.36.70的配置
~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
~]# ssh-copy-id [email protected]
~]# vim /etc/hosts
172.16.36.71 Centos7.pc2
~]# ntpdate 172.16.0.1
~]# yum install nginx
~]# mv /usr/share/nginx/html/index.html{,.bak}
~]# vim /usr/share/nginx/html/index.html
172.16.36.70
~]# systemctl start nginx
使用客户端IE测试测试页面,是否正常显示
~]# yum install keepalived
~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
   notification_email {
    root@localhost
   }
   notification_email_from keepalived_admin@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Centos7.pc1 #路由设备在网络中的名称,一般为hostname
}
######使用vrrp_script实现依赖脚本监测文件的存在性,来降低节点的优先级,以此实现主备模式的切换
vrrp_script chk_down {
    script "[ -f /etc/keepalived/down ] && exit 1 || exit 0"
    interval 1
    weight -20
}
######监测web的访问返回结果,判断服务的可用性, 来了解你节点的优先级
vrrp_script chk_nginx {
    script "curl -s 172.16.36.70 | grep 172 &> /dev/null"
    interval 1
    weight -20
}
######监控主机的nginx是否存在,0信号只是做进程探测的
vrrp_script chk_nginx2 {
        script "killall -0 nginx"   
        interval 1
        weigth -20
}
vrrp_instance VI_1 {
    state MASTER
    interface eno16777736
    virtual_router_id 100
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 99999999
    }
    virtual_ipaddress {
    172.16.36.100/16 dev eno16777736 label eno16777736:1
    }
    notify_master "/etc/keepalived/keepalived.sh master"
    notify_bakcup "/etc/keepalived/keepalived.sh backup"
    notify_fault "/etc/keepalived/keepalived.sh fault"
    track_script {
    chk_down
    chk_nginx
    eno16777736    #监控主机的网卡,如果出现故障可自动降低优先级。 此脚本调用不用定义,是vrrp_script内置的

}
~]# vim /etc/keepalived/keepalived.sh
#!/bin/bash
#author :Magedu
#Description : an example of notify script
contact='root@localhost'
notify() {
    mailsubject="$(hostname) to be $1:vip floating"
    mailbody="$(date +'%F %H:%M:%S'): vrrp transition,$(hostname) change to be $1"
    echo $mailbody | mail -s "$mailsubject" $contact
case $1 in
master)
    notify master
    systemctl start nginx.service
    exit 0
    ;;
backup)
    notify backup
    systemctl restart nginx.service
    exit 0
    ;;
fault)
    notify fault
    systemctl stop nginx.service
    exit 0
    ;;
*)
    echo "Usage: $(basename $0) {master|backup|fault}"
    exit
    ;;
esac
######172.16.36.71的配置
172.16.36.71
~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
~]# ssh-copy-id [email protected]
~]# vim /etc/hosts
172.16.36.70 Centos7.pc1
~]# ntpdate 172.16.0.1

~]# yum install nginx
~]# mv /usr/share/nginx/html/index.html{,.bak}
~]# vim /usr/share/nginx/html/index.html
172.16.36.70
~]# systemctl start nginx
使用客户端IE测试测试页面,是否正常显示
~]# yum install keepalived
~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
   notification_email {
        root@localhost
   }
   notification_email_from keepalived_admin@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Centos7.pc2
}
vrrp_script chk_down {
        script "[ -f /etc/keepalived/down ] && exit 1 || exit 0"
        interval 1
        weight -20
}
vrrp_script chk_nginx {
        script "curl -s http://172.16.36.100 | grep 172 &> /dev/null"
        interval 1
        weight -10
}
vrrp_instance VI_1 {
    state BACKUP
    interface eno16777736
    virtual_router_id 100
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 99999999
    }
    virtual_ipaddress {
        172.16.36.100/16 dev eno16777736 label eno16777736:1
    }
    notify_master "/etc/keepalived/keepalived.sh master"
    notify_bakcup "/etc/keepalived/keepalived.sh backup"
    notify_fault "/etc/keepalived/keepalived.sh fault"
    track_script {
        chk_down
        chk_nginx
    }
}
~]# vim /etc/keepalived/keepalived.sh
#!/bin/bash
#author :Magedu
#Description : an example of notify script
contact='root@localhost'
notify() {
    mailsubject="$(hostname) to be $1:vip floating"
    mailbody="$(date +'%F %H:%M:%S'): vrrp transition,$(hostname) change to be $1"
    echo $mailbody | mail -s "$mailsubject" $contact
case $1 in
master)
    notify master
    systemctl start nginx.service
    exit 0
    ;;
backup)
    notify backup
    systemctl restart nginx.service
    exit 0
    ;;
fault)
    notify fault
    systemctl stop nginx.service
    exit 0
    ;;
*)
    echo "Usage: $(basename $0) {master|backup|fault}"
    exit
    ;;
esac



//Nginx Web服务的守护脚本

#!/bin/bash
while true
do
if [ $(netstat -tlnp|grep nginx|wc -l) -ne 1 ]
then
	/etc/init.d/keepalived stop
fi
sleep 2
done

 

四、如何避免互相抢占问题

问题:keepalived 一个作为 master,另一个做为backup 。当 master 挂了后,backup 接管。但存在一个问题,当 master 恢复了后,master 又会接管会来,这个频繁切换对于业务来说是不好的,再快的切换也会有影响。

解决方案:两个配置都使用backup,然后权重高的使用nopreempt,也就是不抢占的意思,这样子,就不会有两次切换的操作了。

五、脑裂问题

1、何为脑裂

在高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障。两个节点上的HA软件像“裂脑人”一样,争抢“共享资源”、争起“应用服务”,就会发生严重后果——或者共享资源被瓜分、2边“服务”都起不来了;或者2边“服务”都起来了,但同时读写“共享存储”,导致数据损坏。

2、脑裂现象如何发生

(1)高可用服务器对之间心跳线链路发生故障,导致无法正常通信。

(2)因心跳线坏了(包括断了,老化)。

(3)因网卡及相关驱动坏了,ip配置及冲突问题(网卡直连)。

(4)因心跳线间连接的设备故障(网卡及交换机)。

(5)因仲裁的机器出问题(采用仲裁的方案)。

(6)高可用服务器上开启了 iptables防火墙阻挡了心跳消息传输。

(7)高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败。

(8)其他服务配置不当等原因,如心跳方式不同,心跳广插冲突、软件Bug等。

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

keepalived 进程被强制kill后,虚拟 ip 移除不掉,导致脑裂的现象。

3、如何避免脑裂现象

在实际生产环境中,可以从以下几个方面来防止裂脑问题的发生:

(1)同时使用串行电缆和以太网电缆连接,同时用两条心跳线路,这样一条线路坏了,另一个还是好的,依然能传送心跳消息。

(2)当检测到裂脑时强行关闭一个心跳节点(这个功能需特殊设备支持,如Stonith、feyce)。相当于备节点接收不到心跳消患,通过单独的线路发送关机命令关闭主节点的电源。

(3)做好对裂脑的监控报警(如邮件及手机短信等或值班).在问题发生时人为第一时间介入仲裁,降低损失。例如,百度的监控报警短倍就有上行和下行的区别。报警消息发送到管理员手机上,管理员可以通过手机回复对应数字或简单的字符串操作返回给服务器.让服务器根据指令自动处理相应故障,这样解决故障的时间更短。

4、keepalived互相检测防止脑裂发生脚本

#!/bin/bash

while true
do
Master=10.0.0.10
Backup=10.0.0.11
Vip=10.0.0.100
M_num01=/bin/ping -c 2 -W 3 $Master >/dev/null 2>&1 ; echo $?
B_num01=/bin/ping -c 2 -W 3 $Backup >/dev/null 2>&1 ; echo $?
if [ "B_num01" -ne 0 ];then
exit 1
fi

M_num02=ssh $Master ip addr | grep $Vip | wc -l
B_num02=ssh $Backup ip addr | grep $Vip | wc -l

if [ "$M_num02" -ne 0 -a "$B_num02" -ne 0 ];then            
  echo "The server suffered a brain fracture"    
else            
  echo "Server normal"    
fi

done

上边脚本检测,但如果使用iptables把vrrp的output禁止掉,也会脑裂,因为ping是通的,但vrrp包发不出去,另外一台虚拟ip也会起来, 当检测到虚拟ip的arp响应时,就把虚拟ip给delete掉,可以再加上kill掉keepalived。

Keepalived工作原理、高可用分析及脑裂等问题解决方式_第4张图片

六、解决多组Keepalived服务器在一个局域网的冲突问题

当在同一个局域网内部署了多组Keepalived服务器对,而又未使用专门的心跳线通信时,可能会发生高可用接管的严重故障问题。之前已经讲解过Keepalived高可用功能是通过VRRP协议实现的,VRRP协议默认通过IP多播的形式实现高可用对之间的通信,如果同一个局域网内存在多组Keepalived服务器对,就会造成IP多播地址冲突问题,导致接管错乱,不同组的Keepalived都会使用默认的224.0.0.18作为多播地址。此时的解决办法是,在同组的Keepalived服务器所有的配置文件里指定独一无二的多播地址,配置如下:

global_defs {                                 #全局配置
router_id LVS_19                              #服务标识
vrrp_mcast_group4 224.0.0.19    #这个就是指定多播地址的配置
}
#提示:
1)不同实例的通信认证密码也最好不同,以确保接管正常。
2)另一款高可用软件Heartbeat,如果采用多播方式实现主备通信,同样会有多播地址冲突问题。
    
 

————————————————————

来源:公众号LINUX运维ZHAO,运维部落

你可能感兴趣的:(Java)