一、Keepalived 详解
1.Keepalived 定义
Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障。一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备份服务器,当备份服务器收不到这个消息的时候,即主服务器宕机的时候, 备份服务器就会接管虚拟IP,继续提供服务,从而保证了高可用性。Keepalived是VRRP的完美实现,因此在介绍keepalived之前,先介绍一下VRRP的原理。
2.VRRP 协议简介
在现实的网络环境中,两台需要通信的主机大多数情况下并没有直接的物理连接。对于这样的情况,它们之间路由怎样选择?主机如何选定到达目的主机的下一跳路由,这个问题通常的解决方法有二种:
-
在主机上使用动态路由协议(RIP、OSPF等)
-
在主机上配置静态路由
很明显,在主机上配置动态路由是非常不切实际的,因为管理、维护成本以及是否支持等诸多问题。配置静态路由就变得十分流行,但路由器(或者说默认网关default gateway)却经常成为单点故障。VRRP的目的就是为了解决静态路由单点故障问题,VRRP通过一竞选(election)协议来动态的将路由任务交给LAN中虚拟路由器中的某台VRRP路由器。
3.VRRP 工作机制
在一个VRRP虚拟路由器中,有多台物理的VRRP路由器,但是这多台的物理的机器并不能同时工作,而是由一台称为MASTER的负责路由工作,其它的都是BACKUP,MASTER并非一成不变,VRRP让每个VRRP路由器参与竞选,最终获胜的就是MASTER。MASTER拥有一些特权,比如,拥有虚拟路由器的IP地址,我们的主机就是用这个IP地址作为静态路由的。拥有特权的MASTER要负责转发发送给网关地址的包和响应ARP请求。
VRRP通过竞选协议来实现虚拟路由器的功能,所有的协议报文都是通过IP多播(multicast)包(多播地址224.0.0.18)形式发送的。虚拟路由器由VRID(范围0-255)和一组IP地址组成,对外表现为一个周知的MAC地址。所以,在一个虚拟路由 器中,不管谁是MASTER,对外都是相同的MAC和IP(称之为VIP)。客户端主机并不需要因为MASTER的改变而修改自己的路由配置,对客户端来说,这种主从的切换是透明的。
在一个虚拟路由器中,只有作为MASTER的VRRP路由器会一直发送VRRP通告信息(VRRPAdvertisement message),BACKUP不会抢占MASTER,除非它的优先级(priority)更高。当MASTER不可用时(BACKUP收不到通告信息), 多台BACKUP中优先级最高的这台会被抢占为MASTER。这种抢占是非常快速的(<1s),以保证服务的连续性。由于安全性考虑,VRRP包使用了加密协议进行加密。
1.1 安装keepalived
分别在两台httpd的server安装keeepalived,并启动
[root@linux-node1 ~]# yum install -y keepalived[root@linux-node1 ~]# systemctl start keepalived
查看haproxy和httpd状态
[root@linux-node1 ~]# netstat -ntpl|grep 80tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3180/haproxy tcp6 0 0 :::8080 :::* LISTEN 2719/httpd
[root@linux-node2 ~]# netstat -ntpl|grep 80tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5455/haproxy tcp6 0 0 :::8080 :::* LISTEN 5280/httpd
1.2 keepalived配置文件详解
keepalived配置文件分为三类:
-
- 全局配置:整个keepalived起效的配置
- VRRPD配置:keepalived的核心
- LVS配置:有关LVS的配置,此文章不需要 编辑配置文件生效,!和#表示注释
编辑配置文件
[root@linux-node1 ~]# cat /etc/keepalived/keepalived.conf ! Configuration File for keepalivedglobal_defs { notification_email { #keepalived切换时发送email的对象,可以多个,每行一个 zsq@test.cn } notification_email_from haproxy-ha@test.cn #邮件来自哪里,haproxy-ha代表给haproxy做高可用 smtp_server 127.0.0.1 #本地配置的smtp smtp_connect_timeout 30 #连接smtp超时时间30s router_id haproxy-ha #运行haproxy_ha集群的标识,每个集群一个}vrrp_instance HAPROXY_HA { #vrrp实例的名字,根据业务定义 state MASTER #指定instance的初始状态,在两台router都启动后,竞选出Master,这里的state Master并不代表一直是Master interface eth0 #该实例绑定的网卡设备 virtual_router_id 51 #VRIP,范围0~255,默认51 priority 150 #权重值,用来竞选,MASTER要高于BACKUP至少50,linux-node1权重值修改为150 advert_int 4 #竞选检查间隔,默认1s authentication { #设置验证,防止局域网多个keepalived配置混乱 auth_type PASS auth_pass haproxy_ha } virtual_ipaddress { #设置的虚拟ip地址 192.168.230.16 192.168.230.17 }}
将配置文件拷贝到linux-node2上,并更改优先级,注意权重要大于50
[root@linux-node2 ~]# sed -i 's#priority 150#priority 100#g' /etc/keepalived/keepalived.conf [root@linux-node2 ~]# sed -i 's#state MASTER#state BACKUP#' /etc/keepalived/keepalived.conf
启动
systemctl start keepalived.service
查看两台keepalived的虚拟ip情况
[root@linux-node1 ~]# ip a1: lo:mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:34:58:33 brd ff:ff:ff:ff:ff:ff inet 192.168.230.130/24 brd 192.168.230.255 scope global dynamic eth0 valid_lft 1179sec preferred_lft 1179sec inet 192.168.230.16/32 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.230.17/32 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fe34:5833/64 scope link valid_lft forever preferred_lft forever[root@linux-node2 ~]# ip a1: lo: mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:00:dd:15 brd ff:ff:ff:ff:ff:ff inet 192.168.230.131/24 brd 192.168.230.255 scope global dynamic eth0 valid_lft 1228sec preferred_lft 1228sec inet6 fe80::20c:29ff:fe00:dd15/64 scope link valid_lft forever preferred_lft forever
监控VRRP的包查看组播包 ,可以看出竞选的频率为4s,(4s太长了,建议改一秒)MASTER为linux-node1(权重值为150)
[root@linux-node1 ~]# tcpdump -n 'host 224.0.0.18'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes21:20:23.666534 IP 192.168.230.130 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 150, authtype simple, intvl 4s, length 2421:20:27.667590 IP 192.168.230.130 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 150, authtype simple, intvl 4s, length 24手动关闭linux-node1上的keepalived,查看ip,会发现此时VIP已经漂移到linxu-node2上
[root@linux-node2 ~]# ip a1: lo:mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:00:dd:15 brd ff:ff:ff:ff:ff:ff inet 192.168.230.131/24 brd 192.168.230.255 scope global dynamic eth0 valid_lft 1450sec preferred_lft 1450sec inet 192.168.230.16/32 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.230.17/32 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fe00:dd15/64 scope link valid_lft forever preferred_lft forever
二、keepalived不抢占
当MASTER出现问题后,BACKUP会精选出新的MASTER,那么当之前的MASTER重新上线后,是继续成为MASTER还是变成BACKUP呢?默认情况下,不设会不抢占,那么之前的MASTER起来后会继续抢占成为MASTER,也就是说,整个过程需要发生两次切换。
1)MASTER -> BACKUP 2) BACKUP -> MASTER 这样对业务频繁的切换是不能容忍的,因此我们希望MASTER起来后成为BACKUP,所以要设置不抢占。keepalived里面提供了nopreempt这个配置,但是这个配置只能用在state为BACKUP的机器上,但是我们明明希望的是MASTER不进行抢占,没办法,MASTER的state也要设置成BACKUP,也就是说两台keepalived的state都要设置成BACKUP。 具体配置为 1)两台的state处都修改为backup 2)最开始最为MASTER的keepalived的在instance配置段加上nopreempt参数,当此keepalived节点挂了,bakcup将抢占为主,原master恢复后不抢占。三、配置脚本keepalived检查功能
在keepalived.conf中添加vrrp_script配置段
[root@linux-node1 ~]#cat keepalived.conf
! Configuration File for keepalived
global_defs { notification_email { zsq@test.cn } notification_email_from haproxy-ha@test.cn smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id haproxy-ha}vrrp_script chk_haproxy { #增加检测scriptscript "/root/shell/check_haproxy.sh"interval 60weight 2}vrrp_instance HAPROXY_HA state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 4 authentication { auth_type PASS auth_pass haproxy_ha } virtual_ipaddress { 192.168.230.16 192.168.230.17 }track_script {
chk_haproxy }}
检查脚本:
cat /root/shell/check_haproxy.sh #!/bin/shif [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then /etc/init.d/haproxy startfisleep 2if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then /etc/init.d/keepalived stopfi
我们大致讲解一下“ps -C haproxy –no-header | wc -l”这个命令: - ps 这个命令用来进行Linux中进程相关的查询,-C 意思是按照进程名称进行查询。
如果要去掉统计出来的结果表的头部,那么要使用 –no-header参数“|”,这是Linux中的管道流命令,将上一个命令的输出结果作为下一个命令的输入。wc 统计命令,-l 参数,代表按行数进行统计如果当前haproxy的进程数量 == 0,那么执行haproxy的启动命令,试图重新启动haproxy;接下来等待2秒(这是为了给haproxy一定的启动时间),然后再次查看haproxy的进程数量,如果仍然 == 0,那么停止这台机器的keepalived服务,以便备用的Keepalived节点检查到Keepalived已经停止这个事件,并将浮动IP切换到备用服务器上。
四、裂脑
4.1 解释裂脑
在“双机热备”高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体、动作协调的HA系统,就分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障,2个节点上的HA软件像“裂脑人”一样,“本能”地争抢“共享资源”、争起“应用服务”,就会发生严重后果:或者共享资源被瓜分、2边“服务”都起不来了;或者2边“服务”都起来了,但同时读写“共享存储”,导致数据损坏(常见如数据库轮询着的联机日志出错)。
运行于备用主机上的Heartbeat可以通过以太网连接检测主服务器的运行状态,一旦其无法检测到主服务器的“心跳”则自动接管主服务器的资源。通常情况下,主、备服务器间的心跳连接是一个独立的物理连接,这个连接可以是串行线缆、一个由“交叉线”实现的以太网连接。Heartbeat甚至可同时通过多个物理连接检测主服务器的工作状态,而其只要能通过其中一个连接收到主服务器处于活动状态的信息,就会认为主服务器处于正常状态。从实践经验的角度来说,建议为Heartbeat配置多条独立的物理连接,以避免Heartbeat通信线路本身存在单点故障。4.2 产生裂脑的原因
- 高可用服务器之间心跳线链路故障,导致无法正常通信 1)心跳线坏了(线路老化或者意外断了) 2)网卡及相关驱动坏了,IP配置及冲突问题,网卡直连 3)心跳线间链接的设备故障(网卡及交换机) 4)仲裁的机器或者仲裁方案出问题
- 高可用服务器对上开启了iptables防火墙阻挡了心跳消息传输
- 高可用服务器对上心跳网卡地址等信息配置不争取额,导致发送心跳失败
- 启发服务配置不当等原因,如心跳方式不同,心跳广播冲突,软件BUG等
4.3 防止发生裂脑的措施
-
- 同时使用穿线电缆和以太网电缆连接,同时用两条线路,这样一条线路坏了,另一个还是好的,依然能传送心跳信息。
- 当检测到裂脑时强行关闭一个心跳节点,需要特殊设备(Stonith,fence)。相当于程序上备节点发现心跳线故障,发送关机命令到主节点。
- 做好对脑力额的监控报警(邮件短信值班等),发生问题时人为第一时间介入仲裁,降低损失。当然,在实施高可用方案时,要根据业务需求确定是否能容忍这样的损失,对于一般的网站常规业务,这个损失是可控的。
- 启用磁盘锁,正在服务一方锁主共享磁盘,裂脑发生时,让对方完全无法抢占。