软件Keepalived的基础知识

一、Keepalived介绍
Keepalived是Linux下一个轻量级的高可用解决方案,它与HeartBeat、RoseHA实现的功能类似,都可以实现服务或者网络的高可用,但是又有差别:HeartBeat是一个专业的、功能完善的高可用软件,它提供了HA软件所需的基本功能,比如心跳检测和资源接管,监测集群中的系统服务,在群集节点间转移共享IP地址的所有者等,HeartBeat功能强大,但是部署和使用相对比较麻烦;与HeartBeat相比,Keepalived主要是通过虚拟路由冗余来实现高可用功能,虽然它没有HeartBeat功能强大,但Keepalived部署和使用非常简单,所有配置只需一个配置文件即可完成。这也是本章重点介绍Keepalived的原因。
二、Keepalived是什么
Keepalived起初是为LVS设计的,专门用来监控集群系统中各个服务节点的状态。它根据layer3, 4 & 5交换机制检测每个服务节点的状态,如果某个服务节点出现异常,或工作出现故障,Keepalived将检测到,并将出现故障的服务节点从集群系统中剔除,而在故障节点恢复正常后,Keepalived又可以自动将此服务节点重新加入到服务器集群中,这些工作全部自动完成,不需要人工干涉,需要人工完成的只是修复出现故障的服务节点。
Keepalived后来又加入了VRRP的功能,VRRP是Virtual Router Redundancy Protocol(虚拟路由器冗余协议)的缩写,它出现的目的是为了解决静态路由出现的单点故障问题,通过VRRP可以实现网络不间断地、稳定地运行。因此,Keepalived一方面具有服务器状态检测和故障隔离功能,另一方面也具有HA cluster功能.下面详细介绍下VRRP协议的实现过程。
三、 VRRP协议与工作原理
    在现实的 网络环境中,主机之间的通信都是通过配置静态路由(默认网关)完成的,而主机之间的路由器一旦出现故障,通信就会失败,因此,在这种通信模式中,路由器就成了一个单点瓶颈,为了解决这个问题,就引入了VRRP协议。
    熟悉网络的读者对VRRP协议应该并不陌生。它是一种主备模式的协议,通过VRRP可以在网络发生故障时透明地进行设备切换而不影响主机间的数据通信,这其中涉及两个概念:物理路由器和虚拟路由器。
    VRRP可以将两台或多台物理路由器设备虚拟成一个虚拟路由器,这个虚拟路由器通过虚拟IP(一个或多个)对外提供服务,而在虚拟路由器内部,是多个物理路由器协同工作,同一时间只有一台物理路由器对外提供服务,这台物理路由器被称为主路由器(处于MASTER角色)。一般情况下MASTER由选举算法产生,它拥有对外服务的虚拟IP,提供各种网络功能,如ARP请求、ICMP、数据转发等。而其他物理路由器不拥有对外的虚拟IP,也不提供对外网络功能,仅仅接收MASTER的VRRP状态通告信息,这些路由器被统称为备份路由器(处于BACKUP角色)。当主路由器失效时,处于BACKUP角色的备份路由器将重新进行选举,产生一个新的主路由器进入MASTER角色继续提供对外服务,整个切换过程对网络营销用户来说完全透明。
    每个虚拟路由器都有一个唯一标识,称为VRID,一个VRID与一组IP地址构成了一个虚拟路由器。在VRRP协议中,所有的报文都是通过IP多播形式发送的,而在一个虚拟路由器中,只有处于MASTER角色的路由器会一直发送VRRP数据包,处于BACKUP角色的路由器只接收MASTER发过来的报文信息,用来监控MASTER运行状态,因此,不会发生BACKUP抢占的现象,除非它的优先级更高。而当MASTER不可用时,BACKUP网络策划也就无法收到MASTER发过来的报文信息,于是就认定MASTER出现故障,接着多台BACKUP就会进行选举,优先级最高的BACKUP将成为新的MASTER,这种选举并进行角色切换的过程非常快,因而也就保证了服务的持续可用性。
四、Keepalived工作原理
上节简单介绍了Keepalived通过VRRP实现高可用功能的工作原理,而Keepalived作为一个高性能集群软件,它还能实现对集群中服务器运行状态的监控及故障隔离。下面继续介绍下Keepalived对服务器运行状态监控和检测的工作原理。
Keepalived工作在TCP/IP参考模型的第三、第四和第五层,也就是网络层、传输层和网络应用层。根据TCP/IP参考模型各层所能实现的功能,Keepalived运行机制如下。
在网络层,运行着四个重要的协议:互连网协议IP、互连网控制报文协议ICMP、地址转换协议ARP以及反向地址转换协议RARP。Keepalived在网络层采用的最常见的工作方式是通过ICMP协议向服务器集群中的每个节点发送一个ICMP的数据包(类似于ping实现的功能),如果某个节点没有返回响应数据包,那么就认为此节点发生了故障,Keepalived将报告此节点失效,并从服务器集群中剔除故障节点。
在传输层,提供了两个主要的协议:传输控制协议TCP和用户数据协议UDP。传输控制协议TCP可以提供可靠的数据传输服务,IP地址和端口,代表一个TCP连接的一个连接端。要获得TCP服务,须在发送机的一个端口上和接收机的一个端口上建立连接,而Keepalived在传输层就是利用TCP协议的端口连接和扫描技术来判断集群节点是否正常的。比如,对于常见的Web服务默认的80端口、SSH服务默认的22端口等,Keepalived一旦在传输层探测到网络公司这些端口没有响应数据返回,就认为这些端口发生异常,然后强制将此端口对应的节点从服务器集群组中移除。
在应用层,可以运行FTP、TELNET、SMTP、DNS等各种不同类型的高层协议,Keepalived的运行方式也更加全面化和复杂化,用户可以通过自定义Keepalived的工作方式,例如用户可以通过编写程序来运行Keepalived,而Keepalived将根据用户的设定检测各种程序或服务是否允许正常,如果Keepalived的检测结果与用户设定不一致时,Keepalived将把对应的服务从服务器中网络推广移除。
五、Keepalived的体系结构
Keepalived是一个高度模块化的软件,结构简单,但扩展性很强,如有兴趣的读者,可以阅读下Keepalived的源码。下图是官方给出的Keepalived体系结构拓扑图。


网络图中可以看出,Keepalived的体系结构从整体上分为两层,分别是用户空间层(User Space)和内核空间层(Kernel Space).下面介绍Keepalived两层结构的详细组成及实现的功能。
   内核空间层处于最底层,它包括IPVS和NETLINK两个模块。IPVS模块是Keepalived引入的一个第三方模块,通过IPVS可以实现基于IP的负载均衡集群。IPVS默认包含在LVS集群软件中。而对于LVS集群软件,相信做运维的朋友并不陌生:在LVS集群中,IPVS安装在一个叫做Director Server的服务器上,同时在Director Server上虚拟出一个IP地址来对外提供服务,而用户必须通过这个虚拟IP地址才能访问服务。这个虚拟IP一般称为LVS的VIP,即Virtual IP。访问的请求首先经过VIP到达Director Server,然后由Director Server从服务器集群节点中选取一个服务节点响应用户的请求。
    Keepalived最初就是为LVS提供服务的,由于Keepalived可以实现对集群节点的状态检测,而IPVS可以实现负载均衡功能,因此,Keepalived借助于第三方模块IPVS就可以很方便地搭建一套负载均衡系统。在这里有个误区,由于Keepalived可以和IPVS一起很好地工作,因此很多初学者都以为Keepalived就是一个负载均衡软件,这种理解是错误的。
    在Keepalived中,IPVS模块是可配置的,如果需要负载均衡功能,可以在编译Keepalived时打开负载均衡功能,反正,也可以通过配置编译参数关闭。
    NETLINK模块主要用于实现一些高级路由框架和一些相关的网络功能,完成用户空间层Netlink Reflector模块发来的各种网络请求。
    用户空间层位于内核空间层之上,Keepalived的所有具体功能都在这里实现,下面介绍、几个重要部分所实现的功能。
    在用户空间层,Keepalived又分为四个部分,分别是Scheduler I/O Multiplexer、Memory Management、Control Plane和Core components。其中,Scheduler I/O Multiplexer是一个I/O复用分发调度器,它负责安排Keepalived所有内部的任务请求。Memory Management是一个内存管理机制,这个框架提供了访问内存的一些通用方法。Control Plane是Keepalived的控制面板,可以实现对配置文件进行编译和解析,Keepalived的配置文件解析比较特殊,它并不是一次解析所有模块的配置,而是只有在用到某模块时才解析网络公司相应的配置。最后详细说一下Core components,这个部分是Keepalived的核心组件,包含了一些列功能模块,主要有WatchDog、Checkers、VRRP Stack、IPVS wrapper和Netlink Reflector,下面介绍每个模块所实现的功能如下。
(1)WatchDog
WatchDog是计算机可靠性领域中一个极为简单又非常有效的检测工具,它的工作网络原理是针对被监视的目标设置一个计数器和一个阈值,WatchDog会自己增加此计数值,然后等待被监视的目标周期性地重置该计数值。一旦被监控目标发生错误,就无法重置此计数值,WatchDog就会检测到,于是就采取对应的恢复措施,例如重启或关闭。
在Linux中很早就引入了WatchDog功能,而Keepalived正是通过WatchDog的运行机制来监控Checkers和VRRP进程的。
(2)Checkers
这是Keepalived最基础的功能,也是最主要的功能,可实现对服务器运行状态检测和故障隔离。
(3)VRRP Stack
这是Keepalived后来引入的VRRP功能,可以实现HA集群中失败切换(Failover)功能。Keepalived通过VRRP功能再结合LVS负载均衡软件即可部署一套高性能的负载均衡集群系统。
(4)IPVS wrapper
这是IPVS功能的一个实现。IPVS wrapper模块可以将设置好的IPVS规则发送到内核空间并提交给IPVS模块,最终实现IPVS模块的负载均衡功能。
(5)Netlink Reflector

用来实现高可用集群中Failover时虚拟IP(VIP)的设置和切换。Netlink Reflector的所有请求最后都发送到内核空间的NETLINK模块来完成。

Keepalived的安装

环境:LVS+keepalived
前期,安装相关包:
yum -y installopenssl-devel 
进行安装
[root@RServer2 soft]# wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz 
[root@RServer2 soft]# wget http://www.keepalived.org/software/keepalived-1.1.17.tar.gz 
[root@RServer2 soft]#ln -s /usr/src/kernels/2.6.32-71.el6.i686/ /usr/src/linux 
[root@RServer2 soft]# tar -zxvf ipvsadm-1.24.tar.gz 
[root@RServer2 soft]# cd ipvsadm-1.24 
[root@RServer2 ipvsadm-1.24]# make;make install 
[root@RServer2 ipvsadm-1.24]# cd .. 
[root@RServer2 soft]# tar -zxvf keepalived-1.1.17.tar.gz 
[root@RServer2 soft]# cd keepalived-1.1.17 
[root@RServer2 soft]# ./configure 
[root@RServer2 keepalived-1.1.17]# make;make install 

下面是keepalived详细配置文件解析:

[root@localhost kernels]# cat /etc/keepalived/keepalived.conf
! 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_sync_group VGM {  //定义一个vrrp组
group {
VI_1
}
}
vrrp_instance VI_1 {    //定义vrrp实例
state MASTER        //主LVS是MASTER,从的BACKUP
interface eth0      LVS监控的网络接口
virtual_router_id 51  //同一实例下virtual_router_id必须相同
priority 100            //定义优先级,数字越大,优先级越高
advert_int 5          //MASTER与BACKUP负载均衡器之间同步检查的时间间隔,单位是秒
authentication {      //验证类型和密码
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {    //虚拟IP
192.168.1.8
#        192.168.1.9    //如果有多个,往下加就行了
#        192.168.1.7
}
}
virtual_server 192.168.1.8 80 {    //定义虚拟服务器
delay_loop 6                  //健康检查时间,单位是秒
lb_algo rr              //负载调度算法,这里设置为rr,即轮询算法
lb_kind DR              //LVS实现负载均衡的机制,可以有NAT、TUN和DR三个模式可选
persistence_timeout 50        //会话保持时间,单位是秒(可以适当延长时间以保持session)
protocol TCP                  //转发协议类型,有tcp和udp两种
sorry_server 127.0.0.1 80      //web服务器全部失败,vip指向本机80端口
real_server 192.168.1.16 80 {  //定义WEB服务器
weight 1                  //权重
TCP_CHECK {                //通过tcpcheck判断RealServer的健康状态
connect_timeout 5      //连接超时时间
nb_get_retry 3        //重连次数
delay_before_retry 3  //重连间隔时间
connect_port 80        //检测端口
}
}
real_server 192.168.1.17 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

keepalived配置文件解析系列之(三)配置文件解析过程

virHappy(zhuozch@163.com)

  如(一)所言, keepalived在配置文件解析方面拥有非常灵活的方式, 采用关键字分层(每层的关键字数量不限,且关键字的层次也不限制)的方法进行组织一个配置文件, 且支持平行或者嵌套地include多个其它配置文件语句和正则表达式记法的配置文件名。文(二)中介绍了keepalived关键字的存储和相关的操作,下面将具体分析怎么样解析配置文件。

一、入口点及全局流程

  位于parser.c文件中的init_data(char *conf_file, vector (*init_keywords) (void))函数是解析配置文件的入口点, 该函数第一个参数为需要解析的配置文件名(可以由正则表达式构成,如*.conf), 第二个参数为函数指针,指向关键字组织结构(实际取值为check_init_keywords 或者vrrp_init_keywords)。

  解析配置文件过程中用到的几个全局变量包括current_keywords(当前关键字列表)、keywords(层次为0的关键字列表, 整个关键字组织的最顶层)、current_stream(当前打开的文件的流, 即文件指针, 指向当前打开的文件,因为keepalived支持嵌套的文件,所以必须设置这样的变量)、current_conf_file(当前解析的文件的名字, 同上, 是为支持嵌套的配置文件而设立的)、kw_level(当前关键字列表的层次, 处理下一层关键字列表之前递增, 回退到上一层关键字列表时递减网络推广)。

  全局流程如下: 在init_data()中,调用read_conf_file(conf_file), 把要解析的配置文件的名字传递给read_conf_file()函数;read_conf_file()函数先利用glob库取得所有的conf_file(尤其是带正则表达式符号的名字), 然后依次根据 当前关键字列表current_keywords, 调用process_stream(current_keywords)进行配置文件的解析。解析 的方法是依次读取配置文件中的一行, 把该行网络转化为一个字符串数组, 再根据该字符串数组的第一个元素(即该行的第一个字符串)进行以下四种情况的处理:  1)若该字符串是井号或者感叹号(#or!) 表明这是一行注释, 不做处理, 继续读取下一行; 2)若该字符串为右大括号(”}”),且不是层次0的关键字列表, 意味着当前网络层次的关键字解析结束, 直接退出process_stream()函数; 3)若该字符串为”include”, 说明包含嵌套配置文件, 则在保存了当前的文件流和配置文件名字后,递归调用read_conf_file(conf_file)处理include进行来的配置文件, 处理结束后, 再恢复之前保存的文件流和配置文件名字, 继续原配置文件的处理; 4)若该字符串不属于上述三种情况, 那它预期是一个关键字, 则遍历当前关键字列表current_keywords, 并逐一和该字符串进行配置, 若找到了确切的关键字, 则调用 该关键字的handler()进行处理, 若该关键字还关联着下一层次的关键字列表, 则先递增关键字列表层次变量kw_level, 再递归调用process_stream(keyword->sub)处理下一层次的关键字列表, 处理结束后再递减kw_level。 若该字符串不属于于当前关键字列表中的关键字, 则忽略该行。配置文件的解析结束发生在读取到EOF, 而 一个合法的配置文件,一般都 是从层次0开始处理关键字, 中间会依次处理下一层次的关键字列表, 而最终又回归到层次0的关键字列表中。

二、函数的具体分析

  根据上面的总体流程, 在整个解析 配置文件的过程中有5个关键的函数: init_data(char *conf_file, vector (*init_keywords) (void))、 read_conf_file(char *conf_file)、 process_stream(vector keywords_vec)、 read_line(char *buf, int size) 和check_include(char *buf)。下面分别对这个5个函数 进行分析。

  init_data(char *conf_file, vector (*init_keywords) (void))该函数首先调用vector_alloc()分配一个关键字列表, 并令全局变量keywords指向该列表, 然后设置当前的关键字列表current_keywords为keywords, 表示从层次0的关键字列表开始解析配置文件, 接着调用read_conf_file(conf_file)进行具体的配置文件解析, 结束后,释放一开始分配的关键字列表keywords。

  read_conf_file(char *conf_file)该函数首先调用glob(conf_file, 0, NULL, &globbuf)取得配置文件名字conf_file对应的所有配置文件, 然后依次取出每个配置文件进行处理。每个配置文件具体是这样处理的:先用fopen()打开该配置文件, 并保存文件流到当前文件流变量current_stream中, 并保存当前配置文件名字到current_conf_file中, 同时为了在被递归调用后可以回退到当前的配置文件继续处理, 它还保存了当前的路径到prev_path中, 然后调用process_stream(current_keywords)根据当前的关键字层次解析配置文件。直到由glob()取得的所有的配置文件解析完毕才退出read_conf_file()函数。

  process_stream(vector keywords_vec)该函数以当前关键字列表为参数, 并从当前的文件流current_stream中取得配置文件中的内容, 进行相应的处理。 具体地, 先保存当前的关键字列表到prev_keywords中(同样地, 为了后面网络公司的递归调用结束后可以回退到当前的处理), 然后循环调用read_line(buf, MAXBUF)从当前 文件流中读取一行, 若读取到的是EOF, 则退出循环;否则调用alloc_strvec(buf)把读取的该行数据转化为字符串列表, 并取得该列表的第一个元素(即行首的字符串)到str中,若str是大括号(“}”), 且当前 的关键字列表层次变量kw_level大于0, 则退出循环, 结束当前层次的关键字处理; 否则依次遍历当前关键字列表, 若逐一匹配str, 若找到与str相同的关键字, 则调用该关键字的handler()处理该行数据,若该关键字存在下一层次关键字列表, 则递增关键字列表变量kw_level, 再递归调用process_stream(keyword->sub)处理下一层次的关键字列表, 处理结束后,再递减关键字列表变量kw_level。实际上, 一个process_stream()对应着一层关键字列表处理(这里要注意一点, 即同一层次的关键字列表可以有多个, 只要它们的上一层关键字不同即可)。 (可参考下面的网络流程图)

 

process_stream()函数流程

  read_line(char *buf, int size)该函数用来从当前文件流中读取一行数据,并调用check_include(检测是否以”include”开头,若是的话,进入”include”的情况处理(下面的check_include()函数详细介绍),  且不返回该行数据给调用者, 继续读取下一行数据。若读到非”include”语句则返回该行数据(通过参数), 若遇到EOF, 则返回0( return 0)。

  check_include(char *buf)该函数检查该行数据是否包含”include”, 、网络策划、若不含”include”直接返回0, 否则会进一步解析include进来的文件。 具体地, 调用alloc_strvec(buf) 把该行数据转化为字符串列表, 然后判断行首的字符串是否为”include”, 是的话, 先保存当前的文件流current_stream到prev_stream, 当前的配置文件current_conf_file到prev_conf_file,当前的路径到prev_path中, 然后递归调用read_conf_file(conf_file)函数解析include进来的配置文件, 解析结束后, 还原current_stream, current_conf_file为之前保存的值。

三、小结

  keepalived在解析配置文件时充分地利用了递归, 如process_stream()函数中,会根据当前的关键字是否有下一层的关键字列表递归调用process_stream();在check_include()函数中, 会递归调用read_conf_file()去解析新的配置文件。网络营销正是这些递归的设计, 使它在解析配置文件方面显得很强大。

  然而,事情并不总是完美的。 keepalived在配置文件解析方面也存在一些问题, 如没有限制配置文件的嵌套层次(考虑这样一个场景include * 或者自包含),没有对关键字进行严格检查(相应的出错提示可能不够详细)等等, 这些问题其实也可以在现有的代码框架里面进行修改增强的。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值