6、lvs使用进阶(02)
把web server服务和443服务绑定在一起之后呢?
假设一种场景,对web服务器来讲需要session保持。一个在线购物网站,在购物时,如果不结账,一般是http协议,当结账时,需要网站跳转,可能会在同一个域名下,但是协议必须自动转换为https协议。对于一个大型站点来讲,无论是http或https背后都会有一大堆服务器及负载均衡。当访问时本来是http协议被当作80这个服务被调度到real server1,等会付账时把协议改成了https协议了,和上次80服务的调度还有关系吗?即http集群服务和https集群服务是同一种服务吗?即便把两种服务定义为相同的防火墙标记,但是这两个服务仍是独立的服务,只不过通过防火墙标记把它们绑定在一起进行调度,但是两个服务仍然在不同的RS上。
虽然有一种调度算法SH会把来自同一个客户端的请求都发送至同一个RS,假如开始是使用http协议访问,于是用户请求第一次被调度到RS1上,但结账时,协议转为https了,https和http不是同一种服务,所以不会放在同一个RS上进行调度,所以在协议转换为https时,请求可能被调度到RS2上。不同的服务维护的会话表是不一样的。
解决方法:session保持三种方法:session绑定、session复制、session服务器,但这三种方法要依赖iptables以外的组件,所以可以使用iptables持久连接的功能解决上述问题。
通过FWM定义集群的方式:
(1) 在director上netfilter的mangle表的PREROUTING定义用于"打标"的规则
# iptables -t mangle -A PREROUTING -d $vip -p $protocol --dports $port -j MARK --set-mark #
$vip: VIP地址
$protocol:协议
$port:协议端口
(2) 基于FWM定义集群服务
# ipvsadm -A -f # -s scheduler //定义集群
# ipvsadm -a -f # -r $rip1 -g(-s scheduler) //添加real server
# ipvsadm -a -f # -r $rip2 -g
功用:将共享一组RS的集群服务统一进行定义;
session保持三种方法:
session绑定、session复制、session服务器
session绑定:lvs sh算法
对某一中特定服务有效果,但对于防火墙标记的同享两种服务就没有效果了,
lvs persistence:lvs的持久链接:
功能:无论lvs使用什么算法,都可以在一定时间之内把来自同一个client的请求始终调度至第一次挑选出的real server
持久链接如何实现的?需要一个持久链接模板,这个模板独立于算法之外的,
持久链接模板:sourceip rs timer
模板中保存的内容是第一次调度时,sourceip RS timer (来自哪一个sourceip),real sever(被调度至哪个RS),timer(计时器三部分),当同一个client再次请求时,通过检查持久链接模板,将同一个client的请求调度至同一个RS,此时调度算法就失效了。如果用户此前没有请求过,或timer过时,就根据算法调度。
对某一种特定服务有效果,但对多个共享同一组RS的服务,需要统一进行绑定?
lvs的持久链接实现方式:
每端口持久: PPC, 单服务持久调度(既可以实现SH算法,也可以定义时长)(persistent port connection)
每FWM持久: PFWMC,单FWM持久调度,只要防火墙标记是同一个,就能进行统一持久调度(只识别标记,不识别端口)就可以解决将两个服务统一进行调度。
只持久有限个服务:port affinity
每客户端持久:PCC, 单客户端持久调度,director会将用户的任何请求都识别为集群服务,并向RS进行调度。如何实现?在定义集群服务时,把端口定义成0,
所有服务指: tcp-->1-65535 udp-->1-65535 因为0端口已经被定义
持久连接演示:每端口持久PPC (这里仍然使用RIP/DIP/VIP在同一个网段内,在笔记5中已经有配置步骤,这里只是将ipvsadm和iptables规则清空,不再对网络进行配置)
ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] [-b sched-flags]
-p, --persistent [timeout]:就表示启用lvs的persistence,在后面指定时长,如果没有指定时长,那么默认是300秒
# ipvsadm -C //清空之前的规则
# ipvsadm -A -t 192.168.184.145:80 -s rr //先不添加持久链接功能,只做集群
# ipvsadm -a -t 192.168.184.145:80 -r 192.168.184.142 -g
# ipvsadm -a -t 192.168.184.145:80 -r 192.168.184.143 -g
RS1和RS2是轮询响应的
但此时是短链接,响应之后就断开了
下面添加持久连接
# ipvsadm -E -t 192.168.184.145:80 -s rr -p //对定义集群规则做修改,在后面加-p
此时再在浏览器中刷新查看,就需要等待300秒了,从下图可以看出,在指定时长没有结束之前,同一个client的请求全部发送至同一个RS上了
加了-p选项,但也只能调度单独的服务,如果想调度多种服务的话,可以使用持久链接的独特的专用机制
lvs的持久链接实现方式:
每端口持久: PPC, 单服务持久调度(既可以实现SH算法,也可以定义时长)(persistent port connection)
每FWM持久: PFWMC,单FWM持久调度,只要防火墙标记是同一个,就能进行统一持久调度(只识别标记,不识别端口)就可以解决将两个服务统一进行调度。
只持久有限个服务:port affinity
每客户端持久:PCC, 单客户端持久调度,director会将用户的任何请求都识别为集群服务,并向RS进行调度。如何实现?在定义集群服务时,把端口定义成0,
所有服务指: tcp-->1-65535 udp-->1-65535 因为0端口已经被定义
下面是每客户端持久:PCC示例
# ipvsadm -C //清空之前的规则
# ipvsadm -A -t 192.168.194.145:0 -s rr -p //访问的是VIP的0端口,0端口意味着把所有服务都自动识别为集群服务,并向后方转发
# ipvsadm -a -t 192.168.184.145:0 -r 192.168.184.142 -g
# ipvsadm -a -t 192.168.184.145:0 -r 192.168.184.143 -g
此时进行测试,先访问http://192.168.184.145
在访问https://192.168.184.145,此时依然是RS2,表示即使请求更改了服务(这里是协议),依然会调度至同一个RS
同样也可以用ssh进行测试:调度结果依然是RS2即192.168.184.143,这就可以证明不但可以提供持久链接,而且可以将多个服务绑定在同一个real server上
利用MySQL进行测试(这里演示的依然是每客户端持久:PCC)//这里是重新配置后又调用的,可能出了些问题,不出问题的话是在RS2上
1、安装并配置mariadb-server,两台RS都需要
# yum install mariadb-server -y
如果出现无法启动的问题,如ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2),
https://www.jianshu.com/p/c355f28ff535 https://www.jianshu.com/p/c355f28ff535
解决办法:需要配置环境变量 https://blog.csdn.net/guyan0319/article/details/79542836
# export PATH=$PATH:/usr/lib/systemd/system/mariadb.service //临时生效
# mysql //授权MySQL可以执行远程访问,
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>grant all on *.* to root@'%' identified by 'hanshan'; //两台RS要同一个数据集
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)
为了区别主机访问的是RS1还是RS2,这里分别在两台RS上创建数据库node1和node2
RS1:
> create database node1;
Query OK, 1 row affected (0.00 sec)
RS2:
> create database node2;
Query OK, 1 row affected (0.00 sec)
2、找一个服务器模拟客户端进行测试,注意无论是director还是RS都有VIP:145的IP,所以自己无法给自己发请求(centos7 IP:192.168.184.144)
可以ping同VIP
这里mysql链接的是RS1,退出再登陆时链接的依然时RS1,直到时间过时。
每FWM持久: PFWMC 持久了有限的几个服务,并且服务
每客户端持久PCC是将所有服务都当作集群服务,调度至同一个RS,但是在实际中并不常见,每FWM持久可以将有限个即你想把那些服务定义到一起,而不是所有,并且是持久调度
这里的网络依然是配置好的,见随笔5,只需要对ipvsadm和iptables规则进行配置
演示http服务和MySQL服务打上防火墙标记,绑定在一起,而ssh服务未打防火墙标记,从而对三种服务分别进行调度,从而进行区分防火墙标记的功能
也可以用https服务代替MySQL服务,见随笔5,这里不再演示
添加了两条ipvsadm规则,进行测试,测试发现无论是http服务还MySQL服务,都是轮询的,即
# ipvsadm -C //清空ipvsadm规则
# iptables -t mangle -L -n //查看之前的iptables规则,如果有则清除
# iptables -t mangle -A PREROUTING -d 192.168.184.145 -p tcp --dport 80 -j MARK --set-mark 10 //给80端口打标记
# iptables -t mangle -A PREROUTING -d 192.168.184.145 -p tcp --dport 3306 -j MARK --set-mark 10 //给3306端口打标记
# iptables -t mangle -L -n
# ipvsadm -A -f 10 -s rr -p 3600
# ipvsadm -a -f 10 -r 192.168.184.142 -g
# ipvsadm -a -f 10 -r 192.168.184.143 -g
这是请求http服务是RS2
用另外一台服务器请求MySQL服务也是RS2
测试未打防火墙标记的ssh服务
# ipvsadm -A -t 192.168.184.145:22 -s rr
# ipvsadm -a -t 192.168.184.145:22 -r 192.168.184.142 -g
# ipvsadm -a -t 192.168.184.145:22 -r 192.168.184.143 -g
可以看出没有打防火墙标记的ssh服务是轮询的,即没有被调度到同一个RS上
使用wlc调度算法,并使用持久链接等就可以解决集群服务中调转服务时仍保持在同一个RS上
LVS高可用解决方案:HA (lvs不具有后端RS健康状态检查功能)
SPOF:Single Point of Failure 单点故障
故障地点:一台director很容易出故障,做高可用集群
如果RS出故障,director还会把请求发送到RS上,让director对其做健康状态检查,并且根据检测的结果自动完成添加或移除等管理功能;
如何做健康状态检测:
1、基于协议层次检查(层次越低,效率越高,但精确度差;层次越高,效率越低,但精确度高,不能过于频繁会产生日志,也不能太少)
ip层(网络层):icmp(ping,探测主机的在线状态,处于最低级别,因为即使主机在线,并不保证主机可以提供服务)
传输层:检测端口的开放状态(使用扫描工具或网络链接模拟的工具,保证应用程序可以在传输层响应,但这只能保证服务在线,但不能保证资源可以被请求到)
应用层:请求获取关键性资源,根据资源获取到与否做判断
2、检查频度
关键性服务和不关键性服务
3、状态判断
下线:ok --> failure(软状态) --> failure(软状态) --> failure(硬状态) --> 下线
下线不能检查一下没有响应就直接pass,有可能是服务器繁忙,没有来得及响应检查请求,应该多检查几次
上线:failure --> ok(软状态) --> ok(硬状态)
4、back server,sorry server
全部RS有可能同时挂掉,可以在director上建立一个页面访问错误的服务器,用来响应、提醒用户
检查健康状态的脚本
1 #!/bin/bash
2 #
3 fwm=10 //防火墙标记是10
4 sorry_server=127.0.0.1 //用director充当sorry_server
5 rs=('192.168.184.142' '192.168.184.143') //两台RS
6 rw=('1' '2') //权重
7 type='-g' //集群类型
8 chkloop=3 //检查次数,即状态转变,从软状态-->硬状态或硬-->软
9 rsstatus=('0' '0') //服务器的初始状态,这个可以定义和查看服务器状态是否发生了变化
10 logfile=/var/log/ipvs_health_check.log //状态转换的记录日志
11
12 addrs() { //添加RS
13 ipvsadm -a -f $fwm -r $1 $type -w $2
14 [ $? -eq 0 ] && return 0 || return 1
15 }
16
17 delrs() { //删除RS
18 ipvsadm -d -f $fwm -r $1
19 [ $? -eq 0 ] && return 0 || return 1
20 }
21
22 chkrs() { //检查RS
23 local i=1
24 while [ $i -le $chkloop ]; do //判断检查次数是不少于3次
25 if curl --connect-timeout 1 -s http://$1/.health.html | grep "OK" &>/dev/null; then
26 return 0
27 fi
28 let i++ //至少检查三次
29 sleep 1
30 done
31 }
32 //RS状态值为0表示不在集群中,没有提供服务,则用curl进行检查,检查通过,则添加RS到集群中,并把状态值改为1
33 initstatus() { //初始化状态
34 for host in `seq 0 $[${#rs[@]}-1]`; do //因为把RS定义为数组,所以${#rs[a]}表示数组中元素个数即数组长度,${#rs[a]}=2
//$[2-1]=1,所以`seq 0 1`表示0 1表示两个RS
35 if chkrs ${rs[$host]}; then //for循环对rs数组进行遍历,检查数组下标是0 1的主机,即对应的是142、143
36 if [ ${rsstatus[$host]} -eq 0 ]; then //检查主机健康状态良好后,且能提供服务,表示在集群中,判断状态值是否为0,
//为0则改状态值为1,${rsstatus[$host]-->${rsstatus[0]}=0
37 rsstatus[$host]=1 //如果下标为0的数组元素等于0,那么让这个元素值为1
38 fi
39 else
40 if [ ${rsstatus[$host]} -eq 1]; then //如果检查服务器健康状态为宕机,状态值为1,即RS是宕机,则把状态值改为0
41 rsstatus[$host]=0
42 fi
43 fi
44 done
45 }
46
47 initstatus
48 while :; do
49 for host in `seq 0 $[${#rs[@]}-1]`; do
50 if chkrs ${rs[$host]}; then
51 if [ ${rsstatus[$host]} -eq 0 ]; then //如果健康状态良好,且状态值是0,表示RS不在集群中,添加RS到集群中
52 addrs ${rs[$host]} ${rw[$host]} //${rs[$host]}对应于addrs函数中的$1,${rw[$host]}对应于addrs中的$2
53 [ $? -eq 0 ] && rsstatus[$host]=1 //添加RS到进群成功后,把RS的状态值改为1
54 fi
55 else
56 if [ ${rsstatus[$host]} -eq 1 ]; then //如果检查没通过,且状态值是1,则先删除RS,然后把状态值改为0
57 delrs ${rs[$host]} ${rw[$host]}
58 [ $? -eq 0 ] && rsstatus[$host]=0
59 fi
60 fi
61 done
62 sleep 5
63 done
DR类型director脚本示例:
#!/bin/bash
#
vip=192.168.184.45
rip=('192.168.184.142' '192.168.184.143')
weight=('1' '2')
port=80
scheduler=rr
ipvstype='-g'
case $1 in
start) //添加RS
iptables -F -t filter //清空filter表
ipvsadm -C //清空ipvsadm规则
ifconfig eth0:0 $vip broadcast $vip netmask 255.255.255.255 up //添加VIP到网卡别名,并只对本IP广播
echo 1 > /proc/sys/net/ipv4/ip_forward //开启IP转发功能
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]} //为集群服务添加RS,并定义集群类型和权重
[ $? -eq 0 ] && echo "RS ${rip[$i]} added."
done
touch /var/lock/subsys/ipvs
;;
stop)
echo 0 > /proc/sys/net/ipv4/ip_forward //关闭IP转发功能
ipvsadm -C
ifconfig eth0:0 down //关闭VIP别名接口
rm -f /var/lock/subsys/ipvs
echo "ipvs stopped."
;;
status)
if [ -f /var/lock/subsys/ipvs ]; then //判断日志文件是否存在
echo "ipvs is running." //如果存在,证明ipvsadm定义有规则,且功能正常
ipvsadm -L -n //查看ipvsadm定义好的规则
else
echo "ipvs is stopped."
fi
;;
*)
echo "Usage: `basename $0` {start|stop|status}"
exit 3
;;
esac
DR类型RS脚本示例:
#!/bin/bash
#
vip=192.168.184.145
interface="lo:0"
case $1 in
start) //添加RS
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) //删除RS
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) //查看RS的状态
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