解决了任务分发问题,那么我们可以考虑下一个问题了,机器故障怎么办。首先考虑realsserver故障,我们怎么实时发现rs(realserver)的状态,当检测rs到故障后调度器怎么修改调度规则。然后是考虑dr(director)故障,这就是大问题了一旦故障整个后端服务就全部不可用了,这里我称这种节点为单点。原本的设计由于故障导致漏洞百出,有人就引入了一个软件keepalived,帮助lvs解决了单点问题,同时还提供了后端rs故障发现和处理机制。
# 目录
高可用
keepalived
双主模型的实践
多端口统一调度
# 高可用
这里dr一直可以就成为高可用,仔细的考虑dr的特点,一是负责调度规则管理,二对外网提供访问接口,这个访问接口一般是一个ip。
这里引入一个概念,也是一个常识,服务可用率A=MTBF/(MTBF+MTTR)
MTBF #平均无故障时间,也就是服务器正常提供服务的时间
MTTR #平均故障时间,服务器处于故障和维护的时间
提高A的方法有两种一种是在保证MTTP不变的情况下增大MBTF,这种方法常常是硬件级的提高方法,我们可以使用更贵的服务器,并且服务器每个硬件都有一个冗余处于热备。这种方法需要硬件设计商介入,那么就意味着成本会非常高,因为真正正在使用调度器数量很少,不能通过量产来平摊设计费用,那么只能承担硬件设计的高费用。这一种方法显然不太靠谱。
还有就是减MTTR,这种方法首先我们要承认一个前提——我们允许机器故障,减小故障和维护时间那么就有一个方案,就是准备一个和正在运行dr服务器一样的服务器,时时等着dr挂掉立即顶替。既然是顶替那么就会有问题,怎么判断dr挂掉了,让dr实时向备用服务器发送心跳信息,备用服务器一旦收不到心跳信息,立即顶替。
备用dr服务器(backup)怎么顶替dr(master),顶替dr意味着备用服务器要提供dr的全部功能,并且要继承dr的提供的外网访问接口。dr的功能好提供,只要backup服务器运行和master一样服务提供同样的配置文件就可以了。下一项怎么继承dr的外网访问接口,这里我们使用vrrp(虚拟路由协议)
vrrp,是多个硬件使用一个ip信息,其实同时只有一个设备可以使用ip。这个协议的功能就是让ip一直可用,一次工作流程。正常情况master硬件占有ip,并且不停向backup设备发送心跳信息,当master故障backup收不到心跳信息,backup就会发送arp报文问ip的mac地址是多少,然后自己回答ip的mac是自己的mac,这样路由就会收到arp信息更新路由表。这样就把ip抢过来了。
# keepalived
keepalived可以说是为lvs量身定制的高可用软件,之所以这样说是因为它主要有两个核心模块构成如下图
其中vrrp Stack主要是为了实现vrrp功能;Checkers是为了实现监控后端服务器状态的的模块,当后端服务器故障可以实时更改lvs规则,不再向故障的后端服务器调度请求。
### keepalived配置文件的结构
GLOBAL CONFIGURATION
Global definitions
Static routes/addresses
VRRPD CONFIGURATION
VRRP synchronization group(s) #vrrp同步组;
VRRP instance(s) #每个vrrp instance即一个vrrp路由器;
LVS CONFIGURATION
Virtual server group(s)
Virtual server(s) #ipvs集群的vs和rs;
### 配置虚拟路由器:
vrrp_instance <STRING> {
....
}
state MASTER|BACKUP:当前节点在此虚拟路由器上的初始状态;只能有一个是MASTER,余下的都应该为BACKUP;
interface IFACE_NAME:绑定为当前虚拟路由器使用的物理接口;
virtual_router_id VRID:当前虚拟路由器的惟一标识,范围是0-255;
priority 100:当前主机在此虚拟路径器中的优先级;范围1-254;
advert_int 1:vrrp通告的时间间隔;
authentication {
auth_type AH|PASS
auth_pass <PASSWORD>
}
### 虚拟服务器:
virtual_server IP port |
virtual_server fwmark int
{
...
real_server {
...
}
...
}
常用参数:
delay_loop <INT>:服务轮询的时间间隔;
lb_algo rr|wrr|lc|wlc|lblc|sh|dh:定义调度方法;
lb_kind NAT|DR|TUN:集群的类型;
persistence_timeout <INT>:持久连接时长;
protocol TCP:服务协议,仅支持TCP;
sorry_server <IPADDR> <PORT>:备用服务器地址;
real_server <IPADDR> <PORT>
{
weight <INT>
notify_up <STRING>|<QUOTED-STRING>
notify_down <STRING>|<QUOTED-STRING>
HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK { ... }:定义当前主机的健康状态检测方法;
}
HTTP_GET|SSL_GET:应用层检测
HTTP_GET|SSL_GET {
url {
path <URL_PATH>:定义要监控的URL;
status_code <INT>:判断上述检测机制为健康状态的响应码;
digest <STRING>:判断上述检测机制为健康状态的响应的内容的校验码;
}
nb_get_retry <INT>:重试次数;
delay_before_retry <INT>:重试之前的延迟时长;
connect_ip <IP ADDRESS>:向当前RS的哪个IP地址发起健康状态检测请求
connect_port <PORT>:向当前RS的哪个PORT发起健康状态检测请求
bindto <IP ADDRESS>:发出健康状态检测请求时使用的源地址;
bind_port <PORT>:发出健康状态检测请求时使用的源端口;
connect_timeout <INTEGER>:连接请求的超时时长;
}
TCP_CHECK {
connect_ip <IP ADDRESS>:向当前RS的哪个IP地址发起健康状态检测请求
connect_port <PORT>:向当前RS的哪个PORT发起健康状态检测请求
bindto <IP ADDRESS>:发出健康状态检测请求时使用的源地址;
bind_port <PORT>:发出健康状态检测请求时使用的源端口;
connect_timeout <INTEGER>:连接请求的超时时长;
}
# 双主模型的实践
这里我使用lvs的dr模型
### dr1和dr2的设置命令
两台主机keepalived的配置只有很少的一点不同,不同的时候我会标出,这里以dr1的为例
yum -y install keepalived httpd ipvsadm #安装keepalived、httpd和ipvsadm,ipvsadm非必须的,是为了方便我们查看lvs的规则
vim keepalived.conf ! Configuration File for keepalived global_defs { #全局配置 notification_email { [email protected] } notification_email_from [email protected] smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id node1 vrrp_mcast_group4 224.0.29.29 } vrrp_instance VI_1 { #第一个虚拟网络配置 #dr2的配置,state BACKUP state MASTER interface eno16777736 virtual_router_id 51 #dr2的配置,priority 90 priority 100 authentication { auth_type PASS auth_pass oldking1 } virtual_ipaddress { 172.16.29.3/16 dev eno16777736 label eno16777736:0 } } #第二个虚拟网络的配置 vrrp_instance VI_2 { #dr2的配置,state MASTER state BACKUP interface eno16777736 virtual_router_id 52 #dr2的配置,priority 100 priority 90 advert_int 1 authentication { auth_type PASS auth_pass oldking2 } virtual_ipaddress { 172.16.29.4/16 dev eno16777736 label eno16777736:1 } } virtual_server 172.16.29.3 80 { #第一个虚拟网络对应的服务配置 delay_loop 6 lb_algo rr lb_kind DR nat_mask 255.255.0.0 protocol TCP sorry_server 127.0.0.1 80 real_server 172.16.29.1 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 1 nb_get_retry 1 delay_before_retry 1 } } real_server 172.16.29.2 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 1 nb_get_retry 1 delay_before_retry 1 } } } virtual_server 172.16.29.4 80 { #第二个虚拟网络对应的服务配置 delay_loop 6 lb_algo rr lb_kind DR nat_mask 255.255.0.0 protocol TCP sorry_server 127.0.0.1 80 real_server 172.16.29.1 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 1 nb_get_retry 1 delay_before_retry 1 } } real_server 172.16.29.2 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 1 nb_get_retry 1 delay_before_retry 1 } } } echo ‘<h1>dr1</h1>‘ > /var/www/html/index.html #提供网页文件,rs2的话,执行echo ‘<h1>dr2</h1>‘ > /var/www/html/index.html systemctl start keepalived.service systemctl start httpd.service
### rs1和rs2服务器的配置
yum install httpd -y vim setrs.sh #一键配置dr脚步 #!/bin/bash # vip=172.16.29.3 vip1=172.16.29.4 mask=‘255.255.255.255‘ case $1 in start) echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce ifconfig lo:0 $vip netmask $mask broadcast $vip up route add -host $vip dev lo:0 ifconfig lo:1 $vip1 netmask $mask broadcast $vip1 up route add -host $vip1 dev lo:1 ;; stop) ifconfig lo:0 down ifconfig lo:1 down echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce ;; *) echo "Usage $(basename $0) start|stop" exit 1 ;; esac bash -x setrs.sh echo ‘<h1>rs1</h1>‘ > /var/www/html/index.html #提供网页文件,rs2的话,执行echo ‘<h1>rs2</h1>‘ > /var/www/html/index.html systemctl start httpd.service
# 多端口统一调度
首先使用iptables给某几个端口的服务打上同一个标签,大标签的命令
iptables -t mangle -A PREROUTING -i eth2 -p tcp --dport 80 -j MARK --set-mark 20 iptables -t mangle -A PREROUTING -i eth2 -p tcp --dport 443 -j MARK --set-mark 20
然后再编辑keepalived配置文件
#这里不使用ip加port直接使用如下配置 virtual_server fwmark 20 { ... }
# nginx的双主模型
架构图和lvs双主模型的一模一样,只是把代理服务器更替为nginx
yum install nginx keepalived vim /etc/nginx/nginx.conf #在全局配置段添加如下内容 upstream web { server 172.16.29.1:80; server 172.16.29.2:80; } #在server段更改location的配置如下 location / { proxy_pass http://web; }
vim /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { [email protected] } notification_email_from [email protected] smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id node1 vrrp_mcast_group4 224.0.29.29 #这个脚本是为了维护后端服务器时使用的 vrrp_script chk_down { script "[[ -f /etc/nginx/down ]] && exit 1 || exit 0" interval 1 weight -5 } #这个脚本是为了检测代理服务器Nginx的状态 vrrp_script chk_nginx { script "killall -0 nginx && exit 0 || exit 1" interval 1 weight -20 } } #第一个虚拟网络配置 vrrp_instance VI_1 { #dr2的配置,state BACKUP state MASTER interface eno16777736 virtual_router_id 51 #dr2的配置,priority 90 priority 100 authentication { auth_type PASS auth_pass oldking1 } virtual_ipaddress { 172.16.29.3/16 dev eno16777736 label eno16777736:0 } } #第二个虚拟网络的配置 vrrp_instance VI_2 { #dr2的配置,state MASTER state BACKUP interface eno16777736 virtual_router_id 52 #dr2的配置,priority 100 priority 90 advert_int 1 authentication { auth_type PASS auth_pass oldking2 } virtual_ipaddress { 172.16.29.4/16 dev eno16777736 label eno16777736:1 } } #调用chk_down和chk_nginx的运行 track_script { chk_down chk_nginx } }
# 总结
keepalived的是很基本的服务,是我们使用最多的高可用服务,因为它足够轻量级并且可定制性很高,我们可以是keepalived调用我们定义的python脚步实现高级功能,拿高可用nginx服务为例子,备用节点的Nginx服务一直运行着,当主服务器故障,直接获取主服务器的ip,并且向缓存服务器加载session就好了。