一、keepalived基础
1.1 HA实现
上述演示中,不管是lvs-nat还是lvs-nat模型,都会有2个遗留问题:
(1) 如果调度器服务器挂了,如何对调度器做高可用
(2) 如果RS中某台服务器挂了,如何对RS做集群的健探测
健康监测的方式有很多种,比如网络层可以使用icmp ping监测主机的存活状态,传输层可以使用tcp端口监测工具探测端口的可用性,比如nmap,应用层,比如可以对关键服务发起请求。
而实现高可用的方案一般有2种,一种是vrrp协议的实现,比如keepalived,一种是ais的实现方案,比如heartbeat, corosync, pacemaker。其中ais是非常完备,非常重量级的实现。
首先,这里以非常简单的方式描述下ais方案,首先假设这样一种场景,由多台服务器提供相同的服务,比如是httpd服务,此时集群中每台机器需要知道对方的生存状况,比如机器A持续的向其他机器发送信息表示自己存活(假如连续3次失败则会被判定为非存活状态),这种方式被称为心跳检测,但是可能会有这样一种网络原因造成的故障,A认为自己是存活的,但是信息没有成功被其他服务器接收,比如B和C都认为A是非存活状态,此时会造成分裂现象,解决这个问题需要一个仲裁方案,比如最简单的少数服从多数原则,这也是一般推荐奇数台机器构建集群的原因,有时候只有2台,可以使用比如网关服务器当观察者凑够3台也可以,总之必须有一个仲裁机制。假设此时多数的认为机器B可以当做Master向外提供服务,需要一个机制可以停止掉机器A的服务,并且剥夺他的ip使用权,最简单的方式,就是停掉A,然后在机器B上配置的接口上配置一个别名。而实际上ais的实现非常复杂,分为三层,最底层是集群事务层,还有资源管理层和资源代理层,它是一个非常完备的实现,基本上可以满足一切的高可用方案,后面会详细介绍。
这里我们关注的是vrrp协议,,Virtual Redundant Routing Protocol,vrrp协议是非常老的一个协议,是一个虚拟的路由器协议,而keepalived则是vrrp协议的实现。
1.2 VRRP与keepalived
关于VRRP的协议详情可以参考华为等公司一些vrrp协议白皮书,因为vrrp协议原本就是用来做虚拟路由之类的。
VRRP中术语说明:
- 虚拟路由器:由一个Master路由器和多个Backup组成。主机将虚拟路由器当做默认网关。
- 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
- 非抢占模式:在非抢占式模式下,只要Master设备没有出现故障,Backup设备即使随后被配置了更高的优先级,也不会成为Master设备
VRRP的工作过程:
(1) 虚拟路由器根据优先级选举Master。Master通过发送免费ARP报文,将自己的虚拟MAC地址通知给与它连接的设备或者主机,从而承担报文转发任务。
(2) Master路由器周期性发送VRRP报文,以公布其配置信息和工作状态
(3)如果Master出现故障,根据优先级从Backup中选举
(4)虚拟路由器状态切换时,Master路由器由一台设备切换为另一台,新的Master路由器只是简单地发送一个携带虚拟路由器的MAC地址和虚拟IP地址信息的免费ARP报文,这样就可以更新与它相连接的主机或者设备中的ARP相关信息。网络上的主机感知不到Master路由器已经切换为另外一个台设备
(5)Backup路由器的优先级高于Master时,根据工作方式决定是否重新选举
VRRP的工作模式
- 主备模式,一台Master,多台为Backup
- 主/主模式,其实是互为主备模式
keepalived
keepalived作为vrrp协议的实现,设计目的是为了高可用ipvs服务器,他能够在配置文件定义ipvs规则,并能对RS的健康状态进行探测;vrrp_script,vrrp_track
keepalivedz中包含多个组件:
控制组件:配置文件分析器
内存管理
IO复用
核心组件
vrrp stack
checker
ipvs wrapper
watch dog
HA集群配置的前提,一般Linux都需要以下配置
(1)各节点时间同步,Centos上可以基于ntp协议,Centos7上可以是chrony
(2)确保iptables以及selinux不会阻碍;
(3)各节点之间通过主机名互相铜线,即名称解析服务器的解析结果必须和"uname -n"命令的结果一致;
(4)各个节点之root用户基于密钥认证的ssh通信;
yum -y install keepalived
同步下时间:
ntpdate time.windows.com hwclock -w
二、 keepalived配置文件说明
通过命令rpm -qc keepalived发现配置文件只需要关注keepalived.conf即可,详情使用man keepalived.conf观察,下面简要说明一下,Keepavlived分为多个配置段,global配置段,vppr配置段,lvs配置段
global_defs:定义全局配置
global_defs { notification_email { root@localhost } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id ysz202 vrrp_mcast_group4 224.0.100.18}
说明:
- root@localhost直接使用本地用户当做收件地址
- router_id可以使用主机名
- vrrp_mcast_group4表示的ipv4协议下的组播地址,举个例子,因为集群中的心跳通信用单播每个服务器都要单独发送,用广播会给局域网内所有的服务器都发送信息,因此此处使用组播,向拥有同一组播地址的服务器发送心跳信息比较合适。
vrrp_instance : vrrp实例配置
定义一个虚拟路由实例
state MASTER|BACKUP:在当前VRRP实例中此节点的初始状态;
interface IFACE_NAME:vrrp用于绑定vip的接口; virtual_router_id #:当前VRRP实例的VRID,可用范围为0-255,默认为51; priority #:当前节点的优先级,可用范围0-255; advert_int 1:通告时间间隔; authentication { #认证机制 # PASS||AH # PASS - Simple Passwd (suggested) # AH - IPSEC (not recommended)) auth_type PASS # Password for accessing vrrpd. # should be the same for all machines. # Only the first eight (8) characters are used. auth_pass 1234 }# 最关键的。定义vip
virtual_ipaddress { <IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPE> label <LABEL>192.168.200.17/24 dev eth1
192.168.200.18.24 dev eth2 label eth2:1
}
# 一个主机上可能有多个接口,定义要监控的接口
trace_interface {
eth0
eth1
...
}
nopreempt #非抢占模式,默认是抢占模式,如果2个服务器性能有优劣之别,可以抢占..
#通告脚本定义
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault"
其中的脚本notify.sh可以大致如下
#!/bin/bash#contact='root@localhost'notify() { subject="$(hostname) to be $1 :vip floating" body="$(date +'%F %T'): vrrp transition, $(hostname) change to be $1" echo $body | mail -s "$subject" $contact}case $1 in master) notify master ;; backup) notify backup ;; fault) notify fault ;; *) echo "Usage:$(basename $0) {master|backup|fault}" ;;esac
virtual_server : 虚拟服务器
功能描述:
fvirtual server IP port或者vitual server FWM #
virtual_server 192.168.200.100 443 { delay_loop 6 # lb_algo rr #负载均衡调度算法 lb_kind NAT #调度类型 nat_mask 255.255.255.0 # persistence_timeout 50 #持久连接时长 protocol TCP #只支持TCP协议 # quality regression. Defaults to 1. quorum 1 sorry_server 192.168.1.202 80 real_server 192.168.201.100 443 { weight 1 #notify_up| #notify_down | #应用层检测 SSL_GET { url { path / digest ff20ad2481f97b1754ef3e12ecd3a9cc #特征码 } url { path /mrtg/ status_code 200 #基于状态码判定 } connect_timeout 3 #连接的超时时长 nb_get_retry 3 #连接的重试次数 delay_before_retry 3 #连接的重试间隔 } }}
总结:
如果只是需要vip服务,可以只配置vrrp实例,如果需要keepalived来帮助完成lvs负载均衡才需要配置Vitual Server
vrrp_script和track_script
vrrp_script: 资源脚本
track_script: 调用vrrp_script脚本去监控资源;
vrrp_script chk_httpd { script "killall -0 httpd" interval 2 weight -5}vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 98 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.111/32 brd 192.168.1.111 dev eth0 label eth0:0 } track_script { chk_httpd } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault"}
说明:上述配置中命令killall -0 httpd 用来检测当前httpd进程是否存活,假如没有的话返回失败,当前服务器的优先级会降低,在抢占工作模式下由Master->Backup实现地址漂移,这种方式可以为任何服务做高可用,比如说这里的httpd可以改成Nginx。
三、使用keepalived+lvs集群httpd
设计如下:
ysz211(192.168.1.211)和ysz214(192.168.1.214)作为VS提供ipvsadm服务,使用keepalived做ha实现高可用,虚拟ip为192.168.1.204在ysz211和ysz214上地址漂移
ysz212(192.168.1.212)和ysz213(192.168.1.213)作为RS提供httpd服务
第一步,ysz211和ysz214安装ipvsadm
yum install ipvsadmyum install keepalived
keepalived的配置文件keepalived.conf大致如下:
ysz211为MASTER,ysz214为BACKUP,另外一台只需要将state设置为BACKUP且优先级调低为98即可
global_defs { notification_email { root@localhost } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id LVS_DEVEL vrrp_mcast_group4 224.0.100.18}vrrp_instance VI_1 { state MASTER interface eno16777736 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.204 dev eno16777736 label eno16777736:0 }}virtual_server 192.168.1.204 80 { delay_loop 6 lb_algo rr lb_kind DR protocol TCP real_server 192.168.1.212 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.1.213 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } }}
第二步 ysz212和ysz213启动httpd服务
第三步 ysz211启动keepalived
使用tail -f /var/log/messages发现成功启动,信息如下:
Nov 14 21:38:05 www Keepalived_healthcheckers[5180]: Opening file '/etc/keepalived/keepalived.conf'.Nov 14 21:38:05 www Keepalived_healthcheckers[5180]: Configuration is using : 17026 BytesNov 14 21:38:05 www Keepalived_healthcheckers[5180]: Using LinkWatch kernel netlink reflector...Nov 14 21:38:05 www Keepalived_healthcheckers[5180]: Activating healthchecker for service [192.168.1.212]:80Nov 14 21:38:05 www Keepalived_healthcheckers[5180]: Activating healthchecker for service [192.168.1.213]:80Nov 14 21:38:06 www Keepalived_vrrp[5181]: VRRP_Instance(VI_1) Transition to MASTER STATENov 14 21:38:07 www Keepalived_vrrp[5181]: VRRP_Instance(VI_1) Entering MASTER STATENov 14 21:38:07 www Keepalived_vrrp[5181]: VRRP_Instance(VI_1) setting protocol VIPs.Nov 14 21:38:07 www Keepalived_vrrp[5181]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eno16777736 for 192.168.1.204Nov 14 21:38:07 www Keepalived_healthcheckers[5180]: Netlink reflector reports IP 192.168.1.204 addedNov 14 21:38:12 www Keepalived_vrrp[5181]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eno16777736 for 192.168.1.204
且ipvsadm也成功启动,截图如下
第四步,ysz214上启动备用keepalived
搭建成功,可以模拟ysz211 keepalived 故障和ysz213 httpd服务故障,对外服务均可用,从而同时实现了负载均衡和高可用的目的。
四、演示:使用keepalived完成双主模型
双主模型实际上也是主备模型,2个实例互为主备,比如一个httpd服务,一个nginx服务,尽可能减少资源浪费,注意下面是2个不同的ip地址,因此还可以在DNS解析服务器上再做一次负载均衡,使得请求分散到2个ip中,使得前端2个调度器都不会空闲。
ysz202配置文件
global_defs { notification_email { root@localhost } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id ysz202 vrrp_mcast_group4 224.0.100.18}vrrp_script chk_httpd { script "killall -0 httpd" interval 2 weight -5}vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.111/32 brd 192.168.1.111 dev eth0 label eth0:0 } track_script { chk_httpd } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault"}vrrp_instance VI_2 { state BACKUP interface eth0 virtual_router_id 52 priority 98 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.112/32 brd 192.168.1.111 dev eth0 label eth0:1 } track_script { chk_httpd } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault"}
ysz204上配置文件
global_defs { notification_email { root@localhost } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id ysz202 vrrp_mcast_group4 224.0.100.18}vrrp_script chk_httpd { script "killall -0 httpd" interval 2 weight -5}vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 98 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.111/32 brd 192.168.1.111 dev eth0 label eth0:0 } track_script { chk_httpd } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault"}vrrp_instance VI_2 { state MASTER interface eth0 virtual_router_id 52 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.112/32 brd 192.168.1.111 dev eth0 label eth0:1 } track_script { chk_httpd } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault"}