目录
一、DR 模式的扩展
DR 模式上VIP和RIP在和不在同一网段的实验
主要纪要
- 在虚拟一个路由器,将RIPs的网关都指向这个虚拟出来的路由器
- 虚拟路由器的另一个端口连接至DS所在的交换机
- 或者直接通过另外的路由器响应客户端
物理网络搭建
- 本机当做客户端,创建四个虚拟机
- DS和两个RIP只有一块物理网卡且都是桥接模式
- 第四台虚拟机,一个网卡两个地址或者两块网卡各一个地址,打开网卡转发功能,分别将RIPs的网关都指向其中一个地址,另外一个接口还要连接交换机
1.1 配置都在同一网络
- 物理网卡地址
# DS和RSs都是桥接模式
DS的DIP物理网卡:172.16.100.9
RS1的RIP物理网卡:172.16.100.21
RS2的RIP物理网卡:172.16.100.22
- DS 配置网络地址
# 配置都在同一网络
# DS主机,可以使用ifconfig、ip、setup命令配置
ifconfig eno16777724:0 172.16.100.10 netmask 255.255.255.255 broadcast 172.16.100.10 up
# 别名配置路由
route add -host 172.16.100.10 dev eno16777724:0
# 在本机查看规则是否好了
arp -a
# 使用ip添加规则
ip addr add 172.16.100.10/32 dev eno16777724
ip addr list
ip addr del 172.16.100.10/32 dev eno16777724
# 添加路由规则,可以不加,没有使用别名
ip route add 172.16.100.10 dev eno16777724
ip route list
ip route del 172.16.100.10
# 在本机查看规则是否好了
arp -a
- RSs 配置网络地址
# 分别配置RSs主机,启动web服务
[root@localhost ~]# vim set_lvs_dr.sh
#!/bin/bash
VIP=172.16.100.10
VIP_MASK=255.255.255.255
case $1 in
start_dr)
echo 1 > /proc/sys/net/ipv4/conf/all/arp-ignore
echo 1 > /proc/sys/net/ipv4/conf/eth0/arp-ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp-announce
echo 2 > /proc/sys/net/ipv4/conf/eth0/arp-announce
;;
stop_dr)
echo 0 > /proc/sys/net/ipv4/conf/all/arp-ignore
echo 0 > /proc/sys/net/ipv4/conf/eth0/arp-ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp-announce
echo 0 > /proc/sys/net/ipv4/conf/eth0/arp-announce
;;
start_ip)
ifconfig lo:0 $VIP netmask $(VIP_MASK) broadbcast $VIP up
;;
stop_ip)
ifconfig lo:0 down
;;
esac
[root@localhost ~]# chmod +x set_lvs_dr.sh
[root@localhost ~]# ./set_lvs_dr.sh start_dr
[root@localhost ~]# ./set_lvs_dr.sh start_ip
- DS 配置调度算法
# DS上设置调度规则
ipvsadm -A -t 172.16.100.10:80 -s rr
ipvsadm -L -n
ipvsadm -a -t 172.16.100.10:80 -r 172.16.100.21 -g
ipvsadm -a -t 172.16.100.10:80 -r 172.16.100.22 -g
1.2 配置都不在同一网络
- DS 配置网络地址
# DS上设置网络
# 删除之前配置的网络100.9的物理地址还在
ip addr del 172.16.100.10/32 dev eno16777724
# 添加非本网段地址,VIP地址
# 网关都要指向,172.16.0.1,包括物理地址和本机地址
ip addr add 192.168.0.10/32 dev eno16777724
# 在本机查看规则是否好了
arp -a
- RSs 配置网络地址
# 分别配置RSs主机,启动web服务
[root@localhost ~]# vim set_lvs_dr.sh
#!/bin/bash
VIP=192.168.0.10
VIP_MASK=255.255.255.255
case $1 in
start_dr)
echo 1 > /proc/sys/net/ipv4/conf/all/arp-ignore
echo 1 > /proc/sys/net/ipv4/conf/eth0/arp-ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp-announce
echo 2 > /proc/sys/net/ipv4/conf/eth0/arp-announce
;;
stop_dr)
echo 0 > /proc/sys/net/ipv4/conf/all/arp-ignore
echo 0 > /proc/sys/net/ipv4/conf/eth0/arp-ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp-announce
echo 0 > /proc/sys/net/ipv4/conf/eth0/arp-announce
;;
start_ip)
ifconfig lo:0 $VIP netmask $(VIP_MASK) broadbcast $VIP up
;;
stop_ip)
ifconfig lo:0 down
;;
esac
[root@localhost ~]# chmod +x set_lvs_dr.sh
[root@localhost ~]# ./set_lvs_dr.sh start_dr
[root@localhost ~]# ./set_lvs_dr.sh start_ip
- DS 配置调度算法
# 清除之前配置的规则
ipvsadm -C
# DS上设置调度规则
ipvsadm -A -t 192.168.0.10:80 -s rr
ipvsadm -L -n
ipvsadm -a -t 192.168.0.10:80 -r 172.16.100.21 -g
ipvsadm -a -t 192.168.0.10:80 -r 172.16.100.22 -g
1.3 示例脚本
- DR 类型 director 脚本示例
#!/bin/bash
vip=172.16.100.33
rip=('172.16.100.8' '172.16.100.9')
weight=('1' '2')
port=80
scheduler=rr
ipvstype='-g'
case $1 in
start)
iptables -F -t filter
ipvsadm -C
ifconfig eth0:0 $vip broadcast $vip netmask 255.255.255.255 up
route add -host $vip dev eth0:0
echo 1 > /proc/sys/net/ipv4/ip_forward
ipvsadm -A -t $vip:$port -s $scheduler
[ $? -eq 0 ] && echo "ipvs service $vip:$port added." || exit 2
for i in `seq 0 $[${#rip[@]}-1]`; do
ipvsadm -a -t $vip:$port -r ${rip[$i]} $ipvstype -w ${weight[$i]}
[ $? -eq 0 ] && echo "RS ${rip[$i]} added."
done
touch /var/lock/subsys/ipvs
;;
stop)
echo 0 > /proc/sys/net/ipv4/ip_forward
ipvsadm -C
ifconfig eth0:0 down
rm -f /var/lock/subsys/ipvs
echo "ipvs stopped."
;;
status)
if [ -f /var/lock/subsys/ipvs ]; then
echo "ipvs is running."
ipvsadm -L -n
else
echo "ipvs is stopped."
fi
;;
*)
echo "Usage: `basename $0` {start|stop|status}"
exit 3
;;
esac
- DR 类型 RS 脚本示例
#!/bin/bash
vip=172.16.100.33
interface="lo:0"
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 $interface $vip broadcast $vip netmask 255.255.255.255 up
route add -host $vip dev $interface
;;
stop)
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
ifconfig $interface down
;;
status)
if ifconfig lo:0 |grep $vip &> /dev/null; then
echo "ipvs is running."
else
echo "ipvs is stopped."
fi
;;
*)
echo "Usage: `basename $0` {start|stop|status}"
exit 1
esac
二、LVS 的防火墙标记
我们都已经知道ipvs是定义在INPUT链上的,所有要进行防火墙标记就需要在PREROUTING链上进行,不然ipvs不可能对标记进行处理的。
防火墙标记的要点
- 格式:-j MARK --set-mark 10
- mark的取值范围为0-2^32,一般都会在设置100以内
- 可以过滤某一类特定请求,如tcp/80进行标记处理
- 可以将多个服务进行标记,如tcp/80和tcp/22进行合并处理
定义集群的方式
# (1) 在DS上netfilter的mangle表的PREROUTING定义用于打标的规则
# $vip: VIP地址
# $protocol: 协议
# $port: 协议端口
iptables -t mangle -A PREROUTING -d $vip -p $protocol --dports $port -j MARK --set-mark xxx
# (2) 基于FWM定义集群服务
ipvsadm -A -f xxx -s scheduler
# 功用:将共享一组RS的集群服务统一进行定义
2.1 标记配置方式
- 通过防火墙标记定义集群的方式
# -j MARK:来定义使用防火墙标记
# --set-mark:来设置防火墙标记的数字
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 80 -j MARK --set-mark 10
ipvsadm -C
ipvsadm -A -f 10 -s rr
ipvsadm -a -f 10 -r 172.16.100.21 -g
ipvsadm -a -f 10 -r 172.16.100.22 -g
- 通过防火墙标记将多个服务进行标记
# http访问VIP可以在21和22上跳转
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 80 -j MARK --set-mark 10
# ssh访问VIP可以在21和22上跳转
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 22 -j MARK --set-mark 10
# https访问VIP可以在21和22上跳转
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 443 -j MARK --set-mark 10
ipvsadm -C
ipvsadm -A -f 10 -s rr
ipvsadm -a -f 10 -r 172.16.100.21 -g
ipvsadm -a -f 10 -r 172.16.100.22 -g
2.2 配置 HTTPS 服务
# DS作为CA颁发签名证书
cd /etc/pki/CA
(umask 077; openssl genrsa -out private/cakey.pem 2048)
touch index.txt
echo 01 > serial
openssl -req -new -x509 -key private/cakey.pem -out cacert.pem -days 465
填写信息等
# RS申请证书
mkdir -pv /etc/httpd/ssl
cd /etc/httpd/ssl
(umask 077; openssl genrsa -out httpd.key 1024)
openssl req -new -key httpd.key -out httpd.csr
填写信息等
scp httpd.csr root@172.16.100.0:/tmp
# CA颁发签名
openssl ca -in /tmp/httpd.csr -out /tmp/httpd.crt
scp /tmp/httpd.crt root@172.16.100.21:/etc/httpd/ssl
# 把21的证书复制给22服务器
cd /etc/httpd/ssl
scp -rp ssl/ root@172.16.100.22:/etc/httpd/
# 分别配置RS主机中安装ssl服务
yum install mod_ssl
vim /etc/httpd/conf.d/ssl.conf
启用ssl服务
DocumentRoot "/var/www/html"
SSLCertificateFile /etc/httpd/ssl/httpd.crt
SSLCertificateKeyFile /etc/httpd/ssl/httpd.key
httpd -t
service httpd restart
# 配置DS的ipvs规则的HTTPS服务,80
ipvsadm -C
ipvsadm -A -t 192.168.0.10:443 -s rr
ipvsadm -a -t 192.168.0.10:443 -r 172.16.100.21 -g
ipvsadm -a -t 192.168.0.10:443 -r 172.16.100.22 -g
# 配置DS的ipvs规则的HTTPS服务,80和443
# 也可以通过iptables的配置文件进行修改,查看一下呗
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 80 -j MARK --set-mark 10
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 443 -j MARK --set-mark 10
ipvsadm -C
ipvsadm -A -f 10 -s rr
ipvsadm -a -f 10 -r 172.16.100.21 -g
ipvsadm -a -f 10 -r 172.16.100.22 -g
2.3 session 保持
持久连接的引入
- 对于HTTP和HTTPS的会话保持就很难区分了,即使是sh算法也不可用了,即session绑定不可用了。
- 用户一开始使用HTTP协议进行网页浏览,而结账的时候使用HTTPS协议,这就导致可能用户的请求被调度到不同的服务上了。session绑定就解决不了问题了,session复制和session服务器就可以保证,同一IP地址访问网站始终调用到同一服务器,但是会引入额外的组件。其实LVS自己也只有实现的机制,就是LVS的持久连接lvs persistence。
持久连接的实现方式
- 每端口持久(PPC):单服务持久调度
可以实现sh的功能且可以设置超时时长,而sh不能设置超时时长
用户如果超时之后没有断开连接,会自动续2min时长,之后连接为新请求
- 每 FWM 持久(PFWMC):单防火墙标记持久调度
PORT AFFINITY
只对标记进行调度,不管服务类型,需要将多种服务进行同一打标时使用
- 每客户端持久(PCC):单客户端持久调度
DS会将用户的任何请求都识别为集群服务,并向RS进行调度
请求TCP服务的端口范围:1-65535
请求UDP服务的端口范围:1-65535
持久连接的注意事项
- 持久连接的实现方式,会占据内存空间,而且空间存储的条目有限制
# PPC: DS上设置
# 定义: 将来自于同一个客户端对同一个集群服务的请求,始终定向至此前选定的RS ==> 持久端口连接
# 特点: client --> LVS(80) --> RS1 或 client --> LVS(80) --> RS2
# 缺陷: 期望访问不同的端口到同一台RS上,无法实现
# 单服务持久调度
# 可以实现类似于sh功能的调度算法,并可以设置超时时长
ipvsadm -C
ipvsadm -A -t 192.168.0.10:80 -s rr -p 3600
ipvsadm -a -t 192.168.0.10:80 -r 172.16.100.21 -g -w 1
ipvsadm -a -t 192.168.0.10:80 -r 172.16.100.22 -g -w 2
ipvsadm -L -n
# 加深理解: 原本的调度模式
# 没有-p参数,所有不是持久连接的方式
ipvsadm -A -t 192.168.0.10:22 -s rr
ipvsadm -a -t 192.168.0.10:22 -r 172.16.100.21 -g
ipvsadm -a -t 192.168.0.10:22 -r 172.16.100.22 -g
# PFWMC:DS上设置
# 定义: 根据iptables的规则,将对于某类服务几个不同端口的访问定义为一类 ==> 持久防火墙标记连接
# 配置DS的ipvs规则的HTTP/HTTPS服务,80和443端口
# 也可以通过iptables的配置文件进行修改,查看一下呗
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 80 -j MARK --set-mark 10
iptables -t mangle -A PREROUTING -d 192.168.0.10 -p tcp --dport 443 -j MARK --set-mark 10
# 单防火墙标记持久调度
ipvsadm -C
ipvsadm -A -f 10 -s rr -p 3600
ipvsadm -a -f 10 -r 172.16.100.21 -g
ipvsadm -a -f 10 -r 172.16.100.22 -g
ipvsadm -L -n
# 加深理解:原本的调度模式
ipvsadm -A -t 192.168.0.10:22 -s rr
ipvsadm -a -t 192.168.0.10:22 -r 172.16.100.21 -g
ipvsadm -a -t 192.168.0.10:22 -r 172.16.100.22 -g
# PCC: DS上设置
# 定义: 将来自于同一个客户端对所有端口的请求,始终定向至此前选定的RS ==> 持久客户端连接
# 特点: PCC是一个虚拟服务没有端口号或者端口号为0,使用-p来标识服务超市时长
# 缺陷: 定向所有服务,期望访问不同的RS无法实现
# 单客户端持久调度
ipvsadm -C
ipvsadm -A -t 192.168.0.10:0 -s rr -p
ipvsadm -a -t 192.168.0.10:0 -r 172.16.100.21 -g -w 1
ipvsadm -a -t 192.168.0.10:0 -r 172.16.100.22 -g -w 2
ipvsadm -L -n
# 加深理解: 原本的调度模式
ipvsadm -A -t 192.168.0.10:22 -s rr
ipvsadm -a -t 192.168.0.10:22 -r 172.16.100.21 -g
ipvsadm -a -t 192.168.0.10:22 -r 172.16.100.22 -g
三、LVS 的高可用解决方案
SPOF:Single Point of Failure
故障点
DS 服务器单点故障 -> HA高可用集群
- DS如果挂了,会导致整个服务都不可用,所有需要做高可用
- 如KeepAlived可以进行高可用,而且还可以实现对RS的健康监测
后端真实主机挂了 -> DS对RS做健康监测
- 如果后端主机RS挂了,DS能够监测到并将其上的连接交给其他主机处理
- 当RS恢复的时候,DS能够检测到恢复的主机,并让主机自动上线,继续提供对应的服务
健康监测设计方案
1、基于协议层次检查:效率
- IP 层: icmp
- 传输层:检测端口的开放状态
- 应用层:请求获取关键性的资源
2、检查频度
- 不能过于频繁也不能过于不频繁,折中处理
- 日志中需要对其监测进行过滤,保存或者保存到其他地方
3、状态判断
- 下线:ok --> failure --> failure --> failure
- 上线:failure --> ok --> ok
4、back server
- DS可以在RS都挂了的情况下,DS启动服务响应用户请求
#!/bin/bash
fwm=6
sorry_server=127.0.0.1
rs=('172.16.100.21' '172.16.100.22')
rw=('1' '2')
type='-g'
chkloop=3
rsstatus=(0 0)
logfile=/var/log/ipvs_health_check.log
addrs() {
ipvsadm -a -f $fwm -r $1 $type -w $2
[ $? -eq 0 ] && return 0 || return 1
}
delrs() {
ipvsadm -d -f $fwm -r $1
[ $? -eq 0 ] && return 0 || return 1
}
chkrs() {
local i=1
while [ $i -le $chkloop ]
do
if curl --connect-timeout 1 -s http://$1/.health.html | grep "OK" &> /dev/null; then
return 0
fi
let i++
sleep 1
done
return 1
}
initstatus() {
for host in `seq 0 $[${#rs[@]}-1]`
do
if chkrs ${rs[$host]}; then
if [ ${rsstatus[$host]} -eq 0 ]; then
rsstatus[$host]=1
fi
else
if [ ${rsstatus[$host]} -eq 1 ]; then
rsstatus[$host]=0
fi
fi
done
}
initstatus
while
do
for host in `seq 0 $[${#rs[@]}-1]`
do
if chkrs ${rs[$host]}; then
if [ ${rsstatus[$host]} -eq 0 ]; then
addrs ${rs[$host]} ${rw[$host]}
[ $? -eq 0 ] && rsstatus[$host]=1
fi
else
if [ ${rsstatus[$host]} -eq 1 ]; then
delrs ${rs[$host]} ${rw[$host]}
[ $? -eq 0 ] && rsstatus[$host]=0
fi
fi
done
sleep 5
done
文章作者: Escape