前言
在前面我们介绍了多种实现高可用性的解决方案。而实现高可用集群的组件有heartbeat、corosync、cman和keepalived。对于前面三种集群组件而言都需要借助相应的CRM程序来完成高可用服务。如前面讲到的利用heartbeat+haresource来实现http高可用集群、利用corosync+pacemaker(或heartbeat+pacemaker)来实现mysql的高可用集群以及使用RHCS组件中自带的集群组件CMAN+Rgmanager来实现http的高可用集群。其实这三种集群组件实现的功能都差不多,因此,使用哪种解决方案来实现高可用服务就因人而异了。不过常用的集群组件一般都是heartbeat和corosync,它们都可以和pacemaker结合起来工作。只不过corosync比heartbeat的功能更加强大和丰富,因此如果想要和pacemaker结合起来实现高可用集群,首选应该是corosync。好了,来说说keepalived吧。keepalived也是一种集群组件,它也是实现高可用集群的一种解决方案,只不过它通常用来实现IPVS的高可用集群。即lvs中的前端director高可用集群。

 

keepalived简介
keepalived是一个基于VRRP协议来实现IPVS的高可用的解决方案。对于LVS负载均衡来说,如果前端的调度器direct发生故障,则后端的realserver是无法接受请求并响应的。因此,保证前端direct的高可用性是非常关键的,否则后端的服务器是无法进行服务的。而我们的keepalived就可以用来解决单点故障(如LVS的前端direct故障)问题。keepalived的主要工作原理是:运行keepalived的两台服务器,其中一台为MASTER,另一台为BACKUP,正常情况下,所有的数据转换功能和ARP请求响应都是由MASTER开完成的,一旦MASTER发生故障,则BACKUP会马上接管MASTER的工作,这种切换时非常迅速的。
并且MASTER和BACKUP组成一个虚拟服务器,虚拟服务器有一个虚拟IP地址和一个虚拟MAC地址,这个虚拟IP地址就是对外服务的地址,虚拟IP地址总是运行在MASTER上。因此即便是MASTER发生故障,则BACKUP也参加竞选成为MASTER,因此也就具备了虚拟IP地址,继续向外提供服务。而keepalived之所以能够实现高可用功能,完全是因为它是基于VRRP协议来工作的,因此VRRP协议是keepalived的核心。所在在说keepalived之前,还是先来了解下VRRP协议吧。



相关术语

VRID:虚拟路由器的标识。有相同VRID的一组路由器构成一个虚拟路由器。

Master路由器:虚拟路由器中承担报文转发任务的路由器。

Backup路由器:Master路由器出现故障时,能够代替Master路由器工作的路由器。

虚拟IP地址:虚拟路由器的IP地址。一个虚拟路由器可以拥有一个或多个IP地址。

IP地址拥有者:接口IP地址与虚拟IP地址相同的路由器被称为IP地址拥有者。

虚拟MAC地址:一个虚拟路由器拥有一个虚拟MAC地址。虚拟MAC地址的格式为00-00-5E-00-01-{VRID}。通常情况下,虚拟路由器回应ARP请求使用的是虚拟MAC地址,只有虚拟路由器做特殊配置的时候,才回应接口的真实MAC地址。

优先级:VRRP根据优先级来确定虚拟路由器中每台路由器的地位。

非抢占方式:如果Backup路由器工作在非抢占方式下,则只要Master路由器没有出现故障,Backup路由器即使随后被配置了更高的优先级也不会成为Master路由器。

抢占方式:如果Backup路由器工作在抢占方式下,当它收到VRRP报文后,会将自己的优先级与通告报文中的优先级进行比较。如果自己的优先级比当前的Master路由器的优先级高,就会主动抢占成为Master路由器;否则,将保持Backup状态。


VRRP协议
VRRP协议叫做虚拟路由冗余协议,从它的名称就可以知道它是用来提供冗余功能的。它是为了解决静态路由单点故障而设计的一个主从模式的协议,一旦MASTER节点发生故障,其该节点上的服务和IP地址会立刻转移到BACKUP节点上,从而继续提供高可用性。对于了解网络的朋友,都知道在设计网络的时候,必须要考虑到网络的冗余,这里的冗余指的是设备冗余。否则,一旦某一个单点路由器发生故障,其下行所有用户都不能上网了,这种现象是非常严重的。
而VRRP协议却可以很好的解决这个问题。VRRP协议设计的思想就是将多个物理路由器虚拟成一个路由器。这个路由器我们称作为虚拟路由器。虚拟路由器上有一个IP地址,叫做虚拟IP地址。这个虚拟IP地址是向外提供某种服务的地址或者当做某些主机或节点的网关地址。在这多个物理路由器上,拥有这个虚拟IP地址的路由器叫做MASTER路由器,其他的则是BACKUP路由器。只有MASTER路由器才能接受和转发数据,BACKUP路由器是不能转发数据的。对于谁能够成为MASTER路由器,需要根据每个路由器自身的优先级来判断的。对于虚拟路由器而言,只要有一台物理路由器是正常的,则虚拟路由器永远都不会发生故障,因此,即便MASTER路由器发生故障,其他的BACKUP也会立即参加竞选成为MASTER,从而继续提供数据转发功能和保证网络的连续性。

 

VRRP路由器
在这里先解释一下,这里所说的路由器在linux系统下则叫做服务器或者节点,而在网络中,专业的叫法则是称作为路由器。叫法虽不同,但是表达的都是一个意思。
VRRP路由器就是一台物理路由器,只是这台路由器上面运行了vrrp协议或者VRRPD程序。一台VRRP路由器可以位于多个虚拟路由器中。


VRRP虚拟路由器
虚拟路由器就是将多个VRRP路由器通过某种方式组成一个路由器,既然是虚拟的,就是说并不是实际存在的。虚拟路由器的标识符叫做虚拟路由器ID(VRID),其ID范围是0-255。

 

VRRP实例
VRRP实例就是提供某种相同服务或相同路由的一组路由器,每一个组就是一个实例。

 

MASTER和BACKUP
在一个虚拟路由器中,有多个VRRP路由器,这些VRRP路由器中又有一个叫做MASTER路由器,其他的则叫做BACKUP路由器。当VRRP协议在每一个物理路由器上初始启动时,则所有的路由器都会发送VRRP通告信息,且都会参加竞选成为MASTER路由器。其中每一个路由器都有一个priority,priority最大的路由器将会成为MASTER路由器,其他的则是BACKUP路由器。如果priority相同,则每个路由器上IP地址最大的路由器将会成为MASTER路由器。
MASTER路由器拥有虚拟IP地址,且负责响应ARP报文请求和转发数据。BACKUP只能接受VRRP报文通告。它不会抢占成为MASTER,除非它有更高的优先级。

说明:MASTER路由器和BACKUP路由器并非是一成不变的,有可能现在是MASTER路由器,之后就变成P路由器了。 



VRRP协议的工作机制
VRRP路由器是通过竞选协议来实现虚拟路由器功能的,所有的VRRP报文都是通过多播的形式向外发送。虚拟路由器是由虚拟路由器ID(VRID)和虚拟IP地址组成的。虚拟路由器上有一个虚拟的MAC地址,其地址格式为:00-00-5E-00-01-{VRID}。所以,不管谁是MASTER路由器,其对外提供服务的IP(为VIP)和MAC地址(为虚拟MAC地址)都是相同的。客户端并不会因为MASTER的改变而改变,对他们来说,这种主从切换时透明的。
默认情况下,竞选成功后,只有MASTER路由器能够发送通告信息,且每个1秒钟发送一次。如果BACKUP路由器在这段时间内,没有收到MASTER路由器的VRRP通告信息,则认为MASTER路由器宕机,则BACKUP路由器中优先级最高的路由器会抢占成为为新的MASTER路由器。当然也可以通过VRRP接口跟踪功能来改变路由器的优先级以便让最高优先级的路由器成为MASTER。它的跟踪机制是:如果MASTER上监控的某个接口发生故障,则MASTER的priority值会相应降低,且降低后的priority值一定要小于BACKUP上的priority值。这样才可以保证,其他的BACKUP能够抢占成为新的MASTER路由器。
由于出于安全性的考虑,因此,MASTER和BACKUP之间的数据是加密传输的。

 

VRRP的主从模式
在这种模式下,只有一个MASTER,其他的则作为BACKUP。其中MASTER负责数据转发和响应ARP请求。

 

VRRP双主模式

在这种模式下,两台路由器即是MASTER路由器,也是BACKUP路由器。每台路由器即充当当前的MASTER路由器也充当另一个路由器的BACKUP路由器。这就是VRRP的双主模型。

以haproxy服务为例来进行说明,有两个服务器RS1和RS2,RS1和RS2都运行这haproxy和keepalived这两个服务,并且同时互为backup。其中一部分的请求由RS1进行响应,另一部分的请求由RS2进行响应,这样就可以实现负载分担,当其中的任何一台服务器宕机时,则该服务器上的资源会立即转移到另一台服务器上,从而继续接受请求并进行响应,这样就不会影响另外一部分的请求了。当然了,两台服务器同时运行haproxy服务,则必须提供两个VIP地址才行,每台服务器都有一个不同的VIP地址,那么如何确保请求会被负载分担到不同的服务器了?这就需要利用到DNS的A记录,一个主机名对应着2条A记录,利用DNS轮询方式,每次发起DNS查询请求时,则返回的地址与上次解析的地址是不一样的,这样得到的服务ip也是不一样的,从而可以将请求负载分担到两台不同的服务器上。


 

VRRP中的ARP处理机制
在VRRP协议中,只有MASTER才能够响应ARP请求,因此,当MASTER收到ARP请求时,它响应的是虚拟mac地址,而不是实际的物理机mac地址。因此,不管哪台服务器作为MASTER其虚拟MAC地址都不会变,所以对于客户端而言,其通信的目标mac地址仍然是虚拟mac地址,它是不会发生改变的。整个过程对于客户端而言是透明的,因此也就不会影响到客户端的通信了。

 

VRRP的优势
冗余性:可以使用多个路由器设备作为LAN客户端的默认网关,大大降低了默认网关成为单点故障的可能性;
负载共享:允许来自LAN客户端的流量由多个路由器设备所共享;
多VRRP组:在一个路由器物理接口上可配置多达255个VRRP组,每一个组就是一个实例;
多IP地址:基于接口别名在同一个物理接口上配置多个IP地址,从而支持在同一个物理接口上接入多个子网;
抢占:在master故障时允许优先级更高的backup成为master;
通告协议:使用IANA所指定的组播地址224.0.0.18进行VRRP通告;
VRRP接口追踪:基于接口状态来改变其VRRP优先级来确定最佳的VRRP路由器成为master;


好了,谈完了VRRP协议,我们还是回来谈谈keepalived吧!

keepalived实现高可用服务具有的特性
1、在keepalived实现IPVS的高可用服务中,MASTER和BACKUP服务器上都有IPVS规则。当MASETR或BACKUP发生故障时,则该服务器上的IPVS规则自动被删除。当后端的realserver或相关服务发生故障时,则在MASTER上与这个realserver相应的IPVS规则会被删除。

2、当MASTER路由器发生故障时,其VIP地址必须要转移到另一个BACKUP服务器上,继续对外提供服务。

3、当之前的MASTER由故障转变成恢复状态时,则立即会成为master。则相当于立即抢占成为master服务器。
4、keepalived的主从切换时非常迅速的,一般是秒级切换。



keepalived配置文件详解
keepalived的所有配置都在一个配置文件里,但是所有的配置分为3部分:
1、全局配置(Global Configuration)
 全局配置是对整个keepalived都起效的配置。
2、VRRPD配置
 VRRPD配置是keepalived的核心配置
3、LVS配置
 只有当使用keepalived来配置和管理LVS,才需要配置LVS这部分。否则,如果使用keepalived来做HA,LVS的配置完全不需要。
 
 
1、全局配置
全局配置包含2段,即全局定义和静态地址路由段
全局定义
全局定义是用来设置keepalived的通知机制和vrrp路由器id的
global_defs
{
 notification_email
 {
  root@xsl.com     notification_email用来指定keepalived在发生事件(比如主从切换)时,需要发送email的对象。对象可以有一个或多个,每行只能定义一个。
 }
 notification_email_from root@xsl.com    指定邮件的发送人
 smtp_server 127.0.0.1   这里是指定邮件服务器地址的。如果本地开启了sendmail进程,这里可以使用默认配置。
 stmp_connect_timeout 30  设置与邮件服务器连接的超时时长
 router_id my_hostname    设置vrrp路由器的id,用来标识路由器本身
}

静态地址和路由段(通常这部分我们也不用,了解就行
这里定义的是静态ip地址,静态地址不会随VRRPD而添加/删除。静态地址不会发生漂移。
static_ipaddress
{
 192.168.10.100/24 brd + dev eth0 scope global   这里就是定义静态ip地址的,以及发送广播通告的接口。且作用域为全局
 ...
}
下面一部分是用来定义路由的
static_routes
{
 src $SRC_IP to $DST_IP dev $SRC_DEVICE
 ...
 src $SRC_IP to $DST_IP via $GW dev $SRC_DEVICE
}


2、VRRPD配置
VRRPD配置端也包含2部分:VRRP同步组(synchroization Group)和VRRP实例(VRRP Instance)
VRRP同步组的作用是:如果VRRP路由器上有多个实例的话,其中任何一个实例出现问题,则该VRRP路由器的状态就会发生改变,即发生切换事件,从而导致该路由器上的资源全部转移到另一台路由器上。即实现多个路由器资源同进同退。

VRRP同步组的配置
vrrp_sync_group <string> {
group {      在同步组中至少要有一个实例
 inside_network        这里是用来定义实例名称的,这里有2个实例:一个叫inside_network ,一个叫outside_network
 outside_network   
 ...
 }
 notify_master /path/to/to_master.sh       notify_master表示当切换成为master后要执行的脚本,这个脚本可以接受参数
 notify_backup /path_to/to_backup.sh   notify_backup表示当切换成为backup后要执行的脚本,这个脚本可以接受参数
 notify_fault "/path/fault.sh VG_1"   notify_falut表示当MASTER和BACKUP都发生故障时要执行的脚本
 notify /path/to/notify.sh
 smtp_alert         这个表示当keepalived发生切换事件时要发送邮件给Global_defs中定义的对象
}

VRRP实例配置(这是keepalived的核心配置段,很重要的哦
VRRP实例配置主要是定义了VRRP同步组中每一个实例的具体信息
vrrp_instance inside_network {  定义实例名称
 state MASTER    这里定义的是vrrp路由器的初始状态,状态只有2中:MASTRT和BACKUP。当2台路由器都启动后,马上就会参加竞选,priority高的路由器会成为MASTER。这里的state并不表示这台路由器一直是MASTER。
 interface eth0    定义的是需要监测的接口(也是与BACKUP通信接口),这个接口是与实例绑定在一起的
 dont_track_primary   忽略vrrp的接口错误,默认不设置
 track_interface {   这里是设置要监控的接口,其中任何一个接口出现问题,都会进入FALUT状态
     eth0
     eth1
 }
 mcast_src_ip <IPADDR>     定义多播地址,如果不设置,默认使用绑定网卡的Primary IP
 garp_master_delay 10   当状态变成MASTER后,延迟进行免费ARP请求
 virtual_router_id 51   定义虚拟路由器的ID。ID号的范围为0-255。同一个实例下的虚拟路由器ID要保持一致。
 priority 100     定义VRRP路由器的优先级,处于MASTER状态的VRRP路由器的优先级一定要比处于BACKUP状态的VRRP路由器的优先级要大
 advert_int 1     MASTER发送通告报文给BACKUP的间隔时间,默认为1秒
 authentication {    这一段是用来设置认证的,只有认证通过,才可以加入该实例中
      auth_type PASS        设置认证类型,支持的认证类型有PASS和AH
      autp_pass 1234        设置认证密码,MASTER和BACKUP的密码要一样才可以通过认证
 }
virtual_ipaddress {           这里是定义虚拟路由器地址的,即VIP地址。当服务器的状态切换成MASTER后,这些地址会被添加;当切换成BACKUP时,这些地址会被删除。因此,每台服务器上不需要绑定任何地址,keepalived会自动使用ip addr进行绑定。
#<IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPT> label <LABEL>
 192.168.108.100/24 dev eth1
 192.168.108.101/24 dev eth2 label eth2:1
 }
virtual_routes {    这里是用来定义虚拟路由的,当服务器的状态切换成MASTER后,这些路由会被添加;当切换成BACKUP时,这些路由会被删除
# src <IPADDR> [to] <IPADDR>/<MASK> via|gw <IPADDR> dev <STRING> scope <SCOPE> tab
 src 192.168.100.1 to 192.168.109.0/24 via 192.168.200.254 dev eth1
 192.168.110.0/24 via 192.168.200.254 dev eth1
 192.168.111.0/24 dev eth2
 192.168.112.0/24 via 192.168.100.254
 }
 nopreempt     设置不抢占功能。且这个参数只能设置state为BACKUP的主机上。而且这个BACKUP的优先级要比另一台BACKUP的优先要高(如果有另一个BACKUP的话)
 preemtp_delay 300   设置抢占延迟时间,默认为5分钟,即300秒
 debug   设置为Debug级别
}

3、LVS配置
对于LVS配置这部分,只有当使用keepalived来管理和配置LVS时才需要这部分的配置。否则这部分可以不需要。
LVS配置包含2部分:虚拟服务器组(Virtual Server Group)和虚拟服务器(Virtual Server)。这些配置都会传递给ipvsadm作为参数。
虚拟服务器组(Virtual Server Group)
这一段配置的主要目的是让一台realserver上的某个service可以属于多个Virtual Server,并且只做一次健康状况检查。
virtual_server_group <STRING> {
# VIP port
 <IPADDR> <PORT>
 <IPADDR> <PORT>
 ...
 fwmark <INT>
}

虚拟服务器配置
Virtual Server可以以下面3种方式的任意一种方式进行配置:
a、 virtual server IP port
b、 virtual server fwmark int
c、 virtual server group string

这里以a方式的配置来说明
virtual_server 192.168.108.100 80 {   定义虚拟服务器的地址和(服务)端口,这个地址是之前定义好的VIP地址
 delay_loop 3                      定义每隔几秒钟检查一下realserver的状态
 lb_algo rr|wrr|lc|wlc|lblc|sh|dh    LVS的调度算法
 lb_kind NAT|DR|TUN     LVS的集群模式
 persistence_timeout 120    持久连接超时时长,如果在这段时间内用户没有进行任何操作,则用户的下一次请求可能会被调度到另一个节点上去。因此,这种情况下,可能会导致之前保留的session信息不在另一个节点上,会出现一些意外现象。该值设置为0时,表示不启用持久功能。
 persistence_granularity <NETMASK>   会话保持粒度,ipvsadm中的-M参数,默认是0xffffffff,即根据每个客户端做会话保持。
 protocol TCP      使用的协议是TCP还是UDP
 virtualhost <string>
 sorry_server <IPADDR> <PORT>        定义一个备用机的ip地址和服务端口。当所有的realserver都失效后才会启用,可以用来返回一些提示信息给用户。
#下面是用来定义realserver的,每一个realserver都需要定义其相关配置,如下:
 real_server <IPADDR> <PORT>         这里是realserver的ip地址和服务端口
 {
  weight 1       定义服务器的权重
  inhibit_on_failure    在服务器健康状况检查失败后,将其weight设置为0,而不是直接从ipvs中删除。weight为0的服务器将不会被调度。
  notify_up <STRING> | <QUOTED-STRING>    在检测到service up时执行的脚本
  notify_down <STRING> | <QUOTED-STRING>  在检测到service down时执行的脚本
 #下面定义的是一些服务的健康检查方式。健康检查方式只需要定义一次即可,如http服务既可以使用http服务的健康检查方式来配置也可以使用TCP服务的健康检查方式来配置,只需要配置一段即可。
  HTTP_GET | SSL_GET      这里定义是http和https的检查方式
  {
   url {             http和https检查的url,如果有多个url,可以定义多个。每一个url使用“{}”括起来
    path /           http服务检查的默认路径
    digest <STRING>  https检查后的摘要信息
    status_code 200  http检查的返回状态码
   }
   connect_port 80       健康检查的服务端口
   bindto <IPADD>        以此地址发送请求对服务器端进行健康检查
   connect_timeout       连接超时时间
   nb_get_retry 3        设置重连次数
   delay_before_retry 2  重连间隔时间
  }
 #下面配置的是对所有的TCP服务进行健康检查的方式。
  TCP_CHECK {           TCP服务的健康检查方式
   connect_port 80   
   bindto 192.168.1.1
   connect_timeout 4  
  }

  SMTP_CHECK {         SMTP服务的健康检查方式

   host {
    connect_ip <IP ADDRESS>
    connect_port <PORT>
    bindto <IP ADDRESS>  
   }
   connect_timeout <INTEGER>
   retry <INTEGER>
   delay_before_retry <INTEGER> 
   helo_name <STRING>|<QUOTED-STRING   smtp helo请求命令的参数
  }
 #下面定义的是MISC健康检查方式,执行一个程序
  MISC_CHECK
  {
   misc_path <STRING>|<QUOTED-STRING>    这里是一个外部程序或脚本
   misc_timeout <INT>                    脚本执行的超时时间
   #如果定义了misc_dynamic的话,健康检查程序的退出码会动态的调整服务器的weight。
   #返回0,表示健康检查ok,权重wight不被修改
   #返回1,表示健康检查失败,weight设置为0
   #返回2-255,表示检查检查ok,weight=退出状态码-2.例如如果返回的状态码为10,则weight=10-2=8
   misc_dynamic
  }
 }
}

 

实战
利用keepalived来实现IPVS的高可用集群