无论在使用任何调度算法,LVS持久连接都能实现在一定时间内,将来自同一个客户端请求派发至此前选定的服务器;当一个新的客户端请求连接时,LVS就会在内存的缓冲区内记录客户端的IP以及所选的服务器,在一定时间内用户再次访问时,LVS会通过内存缓冲区来查找是否有此用户记录,如果有将直接连接到已选定的服务器上,否则记录IP及连接的服务器;这个内存缓冲区称之为持久连接模板,它存储了每一个客户端,及分配给它的RS的映射关系。

持久连接在一定环境下还是非常有用的,由于在SSL回话中,比如当用户和服务器好不容易建立了SSL回话,用户一不小心刷新了页面,director有给用户分发了一个新的服务器,用户还要从新建立SSL连接请求,这是很不爽的!这种连接方式称为持久端口连接(PPC),将来自于同一个客户端对同一个集群服务的请求,始终定向至此前选定的RS

持久连接还会将同个用户的其他服务请求连接到已建立连接的服务器上,比如当用户访问web服务时,还要能实现https认证,如果访问web时,分配了一个RS,要通过https认证则又分配了一个RS;这样就产生了矛盾,它认证的不是一个RS,使得访问无法安全进行;因此持久连接是必不可少的,这种称为持久客户端连接(PCC),将来自于同一个客户端对所有端口的请求,始终定向至此前选定的RS;把所有端口统统定义为集群服务,一律向RS转发!

持久防火墙标记连接(PNMPP):定义端口间的姻亲关系,将特定端口定义在同一个RS上。这是通过在防火墙内部PREROUTING链上,将规定的端口打上标记;比如:80端口标记为1023端口也标记为10;这样在写规则时只需将端口该为10即可,8023端口就会在同一个RS上响应了

PPC的实现:分别在ipvsdam规则中添加请求

eg80端口

# ipvsadm -A -t 192.168.22.12:80 -s rr
# ipvsadm -a -t 192.168.22.12:80 -r 172.16.15.1 -m
# ipvsadm -a -t 192.168.22.12:80 -r 172.16.15.2 -m

23端口

# ipvsadm -A -t 192.168.22.12:23 -s rr
# ipvsadm -a -t 192.168.22.12:23 -r 172.16.15.1 -m
# ipvsadm -a -t 192.168.22.12:23 -r 172.16.15.2 -m

PCC的实现:只需定义所有端口的规则,并规定超时时间(-P)

# ipvsadm -A -t 192.168.22.12:0 -s -rr -p 600
# ipvsadm -a -t 192.168.22.12:0 -r 172.16.15.1 -m
# ipvsadm -a -t 192.168.22.12:0 -r 172.16.15.2 -m

PNMPP的实现:

# iptables -t mangle -A PREROUTING -d 192.168.22.12 -i eth0 -p tcp --dport 80 -j MARK --set-make 10
# iptables -t mangle -A PREROUTING -d 192.168.22.12 -i eth0 -p tcp --dport 23 -j MARK --set-make 10

8023端口标记为10,并指定从eth0网卡进出

# ipvsadm -A -f 10 -s rr
# ipvsadm -a -f 10 -r 172.16.15.1 -m
# ipvsadm -a -f 10 -r 172.16.15.2 -m

LVS的健康状态检查

LVS模型中,director不负责检查RS的健康状况,这就使得当有的RS出故障了,director还会将服务请求派发至此服务器,这种情况对用户、企业都是很不爽的,哪个用户倒霉说不定就遇到类似了,为了让director更人性化、可靠还要给director提供健康检查功能;如何实现?Director没有自带检查工具,只有手动编写脚本给director实现健康状态检查功能!

#!/bin/bash
#
VIP=192.168.10.3
CPORT=80
FAIL_BACK=127.0.0.1
RS=("192.168.10.7" "192.168.10.8")
declare -a RSSTATUS
RW=("2" "1")
RPORT=80
TYPE=g
CHKLOOP=3
LOG=/var/log/ipvsmonitor.log
addrs() {
ipvsadm -a -t $VIP:$CPORT -r $1:$RPORT -$TYPE -w $2
[ $? -eq 0 ] && return 0 || return 1
}
delrs() {
ipvsadm -d -t $VIP:$CPORT -r $1:$RPORT
[ $? -eq 0 ] && return 0 || return 1
}
checkrs() {
local I=1
while [ $I -le $CHKLOOP ]; do
if curl --connect-timeout 1 http://$1 &> /dev/null; then
return 0
fi
let I++
done
return 1
}
initstatus() {
local I
local COUNT=0;
for I in ${RS[*]}; do
if ipvsadm -L -n | grep "$I:$RPORT" && > /dev/null ; then
RSSTATUS[$COUNT]=1
else
RSSTATUS[$COUNT]=0
A++
Dir[0]=$A
fi
let COUNT++
done
}
initstatus
while :; do
let COUNT=0
for I in ${RS[*]}; do
if checkrs $I; then
if [ ${RSSTATUS[$COUNT]} -eq 0 ]; then
addrs $I ${RW[$COUNT]}
[ $? -eq 0 ] && RSSTATUS[$COUNT]=1 && echo "`date +'%F %H:%M:%S'`, $I is back." >> $LOG
fi
else
if [ ${RSSTATUS[$COUNT]} -eq 1 ]; then
delrs $I
[ $? -eq 0 ] && RSSTATUS[$COUNT]=0 && echo "`date +'%F %H:%M:%S'`, $I is gone." >> $LOG
fi
fi
let COUNT++
done
sleep 5
done