一、 基本概念

1. lvs的架构类型

在lvs架构模型中的三种角色

  • 客户端:公网中的用户,在lvs架构中其IP称为CIP
  • 调度器:可以称为Director、dispatcher、balancer,负责将客户端的请求调度至真正提供服务的服务器上,调度器中有两个IP地址,其一为向互联网提供服务的IP地址,称为VIP。其二为与后端服务器通信的IP地址称为DIP
  • RS:Real Server,真正提供服务的主机,其上的IP地址称为RIP

(1) nat类型

lvs的nat模型架构
结合上图分析nat类型中的调度机制

  • ① 当用户请求到达时,源地址是CIP,目标地址是VIP
  • ② 调度器收到请求后,按照常规应该送到本机的INPUT链上,但是通过IPVS规则强行将报文定向至POSTROUTING链完成出站,并调度到后端的某个RS上,此时报文的源地址是CIP,目标地址是RIP
  • ③ 请求处理完成后,回复报文将原路返回,此时的源地址为RIP,目标地址为CIP
  • ④ 调度器收到请求后,将报文的源地址改为VIP,目标地址为CIP并返回给客户端

nat类型其实就是后端多目标的DNAT,通过修改请求报文的目标IP地址至挑选出某RS的RIP地址实现转发,因此这种类型具有下列几种特性

  • IP地址设置:RIP和DIP应使用私网地址,且调度器为了完成报文修改,RS的网关要指向DIP
  • 请求和响应报文都要经由调度器转发,在极高负载的场景中,调度器可能会成为集群性能瓶颈,不过lvs性能强大,倒也不必太过担心
  • 支持端口映射
  • 后端的RS可以使用任意操作系统

(2) direct routing类型

DR模型

在DR模型中,需要注意的是只有客户端的请求报文经由调度器转发,而RS的响应报文会直接返回给客户端,不会经由调度器,并且每一台RS上都会有VIP地址。结合上图分析dr模型中的调度机制

  • ① 客户端通过公网地址CIP访问VIP,此时路由器会将请求发往调度器,源地址为CIP,目标地址为VIP
  • ② 调度器收到请求后,它不会将目标地址改为RIP,其原因是DR模型中响应报文不会经由调度器转发了,一旦改成RIP,RS会使用RIP提供服务,但是客户端请求的是VIP,客户端不会认可RIP的响应。于是请求报文到达调度器后,调度器会先挑选一个RIP并发起广播获取其MAC地址,并将报文的目标MAC地址改为RIP对应的MAC地址并返回给交换机,此时源IP还是CIP,目标IP还是VIP,但是重新封装了MAC报文
  • ③ 交换机将报文发给MAC地址对应的RS
  • ④ RS收到请求后开始拆封,发现MAC地址是自己并且目标IP为VIP,于是进入本机开始响应

对于每一个RS来讲,RIP是配置在物理网卡上的,而VIP是配置在lo接口的别名上的。因此每个请求都是从RIP的网络接口进入的,入站之后发现地址在lo接口上,于是就转发至lo接口并经由lo送至用户空间的进程。而响应报文正常会从RIP的接口出站,因此需要强行限制报文出站必须先经过lo接口,但是到了lo查路由表发现只能通过物理网卡出站,于是会再次转发给物理网卡完成出站,经过这样绕一个圈子,就保证了响应报文的源IP为VIP

DR模型的几个特性:

  • 因为个RS都配置有VIP,所以必须保证前端路由器将目标地址是VIP的请求报文发送至调度器,不然调度将无法进行。常见的方法其一为静态绑定,就是将调度器的MAC地址和VIP在路由器中绑定,但是这种方式当调度器宕机时将导致整个集群不可用。其二为使用arptables规则,在每个RS上限制对VIP地址广播的回应。其三为修改RS主机内核参数
  • RIP可以使用私有地址,但也可以使用公网地址。RIP和DIP必须在同一物理网络中,不过为了便于操作,最好都设置为同一网段,但是RIP的网关不能指向DIP,因为DR模型中响应报文不经由调度器
  • DR模型中请求报文经由Director调度,但响应报文一定不能经由Director,这个模型是改MAC地址,所以不支持端口映射
  • RS可以是大多数操作系统

(3) tun类型

tun类型

在tun类型中,调度器和各RS可以不在同一机房、同一地域、甚至不在同一半球都是没有问题的,但是一定要确保请求必须要被调度到调度器的VIP,每个RS的RIP必须是公网地址,结合上图分析调度过程

  • ① 客户端请求被送往调度器,此时原地址为CIP,目标地址为VIP
  • ② 从RS池中挑选一台,在源地址、目标IP不变的情况下, 再封装一个IP首部,这个新封装的IP首部中源地址为DIP,目标地址为RIP
  • ③ 当RS收到请求后,首先拆封新的首部,拆完之后会发现内部还有一个IP首部,源为CIP、目标为VIP。为了可以正常入站,每个RS上也会配置VIP,同样以类似DR模型的方式进行工作并响应

tun类型不修改请求报文的ip首部,而是在原有的ip首部之外,在封装一个ip首部。tun类型的特性:

  • RIP、DIP、VIP全得是公网地址
  • RS得网关不指向DIP
  • 请求报文必须经由调度器,但响应报文不能经由调度器
  • 不支持端口映射
  • RS的操作系统必须支持隧道功能,否则将无法理解IP首部外层为什么还要在封装一个IP首部

(4) fullnat类型

在这里插入图片描述
在fullnat类型中,调度方式类似于nat类型,但是各RS可以不在同一网段,结合上图分析调度过程

  • ① 当客户端请求到来时,此时源地址为CIP,目标地址为VIP
  • ② 调度器收到请求后,会同时修改源IP和目标IP,此时源IP为DIP,目标IP为RIP,经过层层路由送给RS
  • ③ RS收到请求后,正常进行响应,将报文送回给调度器,此时报文的源IP为RIP,目标IP为DIP
  • ④ 调度器收到请求后,会再次修改报文的IP地址,将源IP改为VIP,目标IP改为CIP

fullnet类型就是通过同时修改请求报文的目标地址和源地址实现调度的,其特点为:

  • VIP是公网地址,RIP和DIP是私网地址,二者无须再同一网络中,因为RS接受到的请求报文的源地址为DIP,所以只要能路由到即可
  • 请求报文和响应报文都必须经由调度器
  • 支持端口映射机制
  • RS可以是任意操作系统

2. lvs中的调度算法(scheduler)

(1) 静态方法

仅根据算法本身进行调度,不考虑当前的负载情况,可以保证起点公平

  • RR:round robin,轮调
  • WRR:weighted rr,加权的rr
  • SH:source ip hash,来自同一个IP地址的请求,将始终被调度至同一个RS,实现session保持机制
  • DH:destination hash,将对同一个目标的请求始终发往同一个RS

(2) 动态方法

根据算法及各RS的当前负载状态进行调度

  • LC:Least Connection,最少链接数
    Overhead=Active*256+Inactive,活动链接乘以256加上非活动链接
  • WLC:Weighted,加权最少链接
    Overhead=(Active*256+Inactive)/weight
  • SED:Shortest Expect Delay,最短期望延迟
    Overhead=(Active+1)*256/weight
  • NQ:Never Queue,刚来的请求按照权重大小一次分配,一个主机至少分一个,之后再根据SED算法分配
  • LBLC:Locality-Based LC,基于本地的最少链接,动态的DH算法,正向代理情形下得cache server调度
  • LBLCR:Localiit-Based LC with Replication,带复制功能的lblc

3. session保持

session是用于追踪用户行为的重要机制,在负载均衡的集群中,为了让用户的请求被调度器调度完成后,他的session依然存在,而不会丢失,是一个动态站点必须要解决的问题

(1) session绑定

将来自于同一用户的请求,始终调度到一台RS上,这种方式简单粗暴,缺点在于服务器宕机后,session也随之消失了

  • source ip hash:源地址哈希机制,将来自于同一个IP的请求始终发往同一个服务器,缺点在于同一源IP背后的客户数量不同,看似均衡
  • cookie绑定:基于应用层协议,通过插入cookie的方式进行调度的,它的粒度非常细,因为它是在进程级别的

(2) session集群

任何两个主机会对自己的session做同步,缺点在于集群中会大量存储同一个session

(3) session服务器

提供一台专门存储session的主机,其负责session存储、管理,缺点在于session如果是跨网络,必然会带来延迟,如果是单点还要做高可用

4. ipvs的持久连接

ipvs的持久连接是实现用户会话绑定的,其sh算法可以将用户始终调度至某一台RS,但是sh算法是对某一特定服务的调度,当用户访问其他服务时,sh算法可能会将用户请求调度至其他RS上。这时就需要用到lvs的persistence机制,这个机制可以实现不管使用任何算法,都可以在规定时间内将同一用户的请求调度至同一台RS

  • PPC:用户对某个服务进行请求,会被持续调度至同一台RS,类似sh算法,一旦用户请求其他服务,就有可能被调度至其他RS
  • PFWM:只要用户访问的服务是同一个防火墙标记,就会始终调度至同一台主机
  • PCC:实现单客户端持久调度,调度器会将用户的任何请求都识别为集群服务并向RS进行调度,此种方式需要在定义集群服务时将端口指定为0

5. 基于防火墙标记调度

在ipvs中可以借助防火墙标记进行调度,需要基于防火墙的PREROUTING链进行打标,这个就可以将共享一组RS的集群服务使用同一条ipvs规则进行调度。比如,可以将请求80/TCP和443/TCP的报文都打上相同的标记,接着在ipvs规则中只用将相同标记的报文进行调度即可,便于对规则的维护

二、命令用法

1. 管理集群服务

1. ipvsadm -A|E -t|u|f service-address [-s scheduler]

2. ipvsadm -D -t|u|f service-address

3. ipvsadm -C

4. ipvsadm -L|l [options]
--------------------------------------------------------------

service-address:集群服务地址
-t:指定为tcp协议,格式为ip:port
-u:指定为udp协议,格式为ip:port
-f:-f mark,防火墙标记

scheculer:指明调度算法,默认为wlc

2. 管理集群服务中的RS

1. ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m]

2. ipvsadm -d -t|u|f service-address -r server-address [-g|i|m]

------------------------------------------------------------------

server-address:指定RS的地址,格式为ip[:port]

lvs-type:指定lvs的类型
-g:gateway,dr模型
-i:ipip,tun类型
-m:masquerade,nat类型

3. 显示链接

需要结合-L选项使用
-c:显示链接
--stats:统计数据
--rate:显示速率,能显示每秒的包个数
--exact:显示精确值,不要做单位换算

三、实现方法

1. nat模型架构

实验架构

1. 使用三台主机搭建环境
1)调度器地址:VIP 192.168.60.200 DIP 192.168.80.254
2)两台RS:RIP 192.168.80.100 192.168.80.200
3)将各主机IP配置完毕,并ping通

2. 两台RS主机安装httpd,并提供不同的网页文件,便于后续查看调度算法

3. 打开调度器的核心转发功能
~]# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1

~]# sysctl -p

4. 添加ipvs规则
~]# ipvsadm -A -t 192.168.60.200:80 -s rr
~]# ipvsadm -a -t 192.168.60.200:80 -r 192.168.80.100 -m
~]# ipvsadm -a -t 192.168.60.200:80 -r 192.168.80.200 -m

2. dr模型架构一

VIP、DIP、RIP都在同一网段
在这里插入图片描述

1. 使用三台主机搭建实验环境
1)调度器: DIP:192.168.60.200(ens33) VIP:192.168.60.30(ens33:0)
2)RS1:RIP:192.168.60.70(ens33) VIP:192.168.60.30(lo:0)
3)RS2:RIP:192.168.60.80(ens33) VIP:192.168.60.30(lo:0)

2. 两台RS主机安装httpd,并提供不同的网页文件,便于后续查看调度算法

3. 将调度器、RS1、RS2的DIP、RIP配置完成并调通

4. 在调度器中加入VIP地址
~]# ip addr add 192.168.60.30 dev ens33 label 'ens33:0'

5. 在两台RS主机中加入ARP设置参数(注意:为了避免RS的VIP发广播公告,需先配置ARP参数在配置VIP)
1)arp_announce:定义是否向其他主机发起arp通告
0:通告所有本机地址
1:尽量避免向非本网络中的主机通告非本网络的地址
2:总是用最佳网络地址来向网络通告
2)arp_ignore:定义是否响应arp请求
0:只要收到请求,无论从那个接口进来的,只要有这个地址,就响应
1:请求报文从哪个接口进入的,就必须使用这个接口的地址响应

~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
~]# echo 1 > /proc/sys/net/ipv4/conf/ens33/arp_ignore
~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
~]# echo 2 > /proc/sys/net/ipv4/conf/ens33/arp_announce

6. 在两台RS中加入VIP地址、路由
~]# ip addr add 192.168.60.30/32 broadcast 192.168.60.30 dev lo label lo:0
~]# ip route add 192.168.60.30 dev lo:0

7. 在调度器中添加ipvs规则
~]# ipvsadm -A -t 192.168.60.30:80 -s rr
~]# ipvsadm -a -t 192.168.60.30:80 -r 192.168.60.70 -g
~]# ipvsadm -a -t 192.168.60.30:80 -r 192.168.60.80 -g

---------------------------------------------
当主机不做RS后记得取消arp限制

3. dr模型架构二

VIP与DIP、RIP不在同一网段
在这里插入图片描述

  • 环境介绍:使用5台主机搭建实验环境
客户端:CIP 192.168.150.100
路由器:192.168.150.254 192.168.200.254
调度器:DIP 192.168.150.30(ens32) VIP 192.168.200.100(ens32)
RS1:DIP 192.168.150.40(ens32) VIP 192.168.200.100(lo:0)
RS2:DIP 192.168.150.50(eth0) VIP 192.168.200.100(lo:0)
  • 第一步:配置各主机的IP地址(除了VIP),开启路由器的核心转发功能,使RS1可以ping通客户端

  • 第二步:RS1、RS2安装httpd,提供不同的网页文件

  • 第三步:给调度器配置VIP地址
    ~]# ip addr add 192.168.200.100 dev ens32

  • 第四步:在两台RS主机中加入ARP设置参数、加入VIP地址、路由(注意:为了避免RS的VIP发广播公告,需先配置ARP参数在配置VIP),第四步我是使用脚本完成的

(1)arp_announce:定义是否向其他主机发起arp通告
0:通告所有本机地址
1:尽量避免向非本网络中的主机通告非本网络的地址
2:总是用最佳网络地址来向网络通告
(2)arp_ignore:定义是否响应arp请求
0:只要收到请求,无论从那个接口进来的,只要有这个地址,就响应
1:请求报文从哪个接口进入的,就必须使用这个接口的地址响应
#!/bin/bash
vip=192.168.200.100

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 1 > /proc/sys/net/ipv4/conf/ens32/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/ens32/arp_announce

ip addr add ${vip}/32 broadcast $vip dev lo label lo:0
ip route add $vip dev lo:0
;;

stop)

ip addr del $vip dev lo label lo:0
ip route del $vip dev lo:0
echo 0 > /proc/sys/net/ipv4/conf/ens32/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/ens32/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
;;

esac
  • 第五步:在调度器中加入ipvs调度规则
~]# ipvsadm -A -t 192.168.200.100:80 -s rr
~]# ipvsadm -a -t 192.168.200.100:80 -r 192.168.150.40 -g
~]# ipvsadm -a -t 192.168.200.100:80 -r 192.168.150.50 -g

在做DR模型VIP与DIP、RIP不是一个网段的过程中,遇到一些目前无法理解的问题,如下

  • 关于VIP的配置的一些问题:
  1. VIP的配置信息写在文件中ping不通:再做实验的过程中,刚开始给调度器设置了两块网卡,并且把VIP配置信息都写入了第二块网卡的配置信息中,于是这个VIP就只能和自己的网关ping通,与其他网段的地址互相ping怎么也不通,然后我尝试将调度器的DIP的网卡down掉,此时VIP就可以通了,这个问题目前推测是路由表问题

  2. 使用命令将IP地址配置到调度器的第二块网卡上,有时能通、有时不通,就很迷

  3. 于是我只给调度器设置一块网卡,将VIP地址使用命令配置到这块网卡上,最开始的时候不通,可是过一会就通了,很玄学。不过大多数都是可以ping通的,我推测不通的原因是我在做实验的过程中,不断的将VIP地址配置来配置去,其他主机可能会有错乱的ARP解析信息,等过一段时间ARP失效于是就通了

  • 关于RS主机设置ARP参数的问题
  1. /proc/sys/net/ipv4/conf目录下,每个网卡接口都有对应的目录,设置RS的VIP参数时,我只是调整了all子目录的arp_ignorearp_announce,为了测试效果,我将调度器的VIP地址删掉,保留了RS的VIP地址,我惊奇的发现VIP地址依然可以ping通,并且在物理机中查看arp解析信息发现VIP对应的虚拟机已经变为了其中一台RS的MAC地址

  2. 然后我尝试调整ens32网卡的arp_ignorearp_announce,同样禁掉调度器的VIP,此时VIP依然可以ping通,只不过前面的几个包会丢,后面就一直可以通

  3. 所以在DR模型的过程中,个人强烈建议RS的全部接口都要调整一下ARP解析参数,如脚本所示

  • 关于CIP的问题:
    此实验环境CIP和DIP、RIP是同一网段的,我尝试将CIP调整为不同网段的地址,并且在路由器中也加入了网关地址,会发现CIP和DIP、RIP可以ping通,直接使用curl去请求RS,也可能正常发起请求,但是CIP去ping VIP就不通了,curl也不通。此问题我猜测是路由器的路由信息设置的不对,目前没有找到解决办法,不过将CIP调整到与RIP一个网段就全都通了

4. 基于防火墙标记调度80/TCP、443/TCP

本实验基于DR模型二环境搭建

  • 第一步:创建私有CA,为两台RS颁发证书,颁发证书可以参考这里

  • 第二步:添加iptables规则
    ~]# iptables -t mangle -A PREROUTING -d 192.168.200.100 -p tcp --dport 80 -j MARK --set-mark 10
    ~]# iptables -t mangle -A PREROUTING -d 192.168.200.100 -p tcp --dport 443 -j MARK --set-mark 10

  • 第三步:清除原先的ipvs规则,添加新的基于防火墙标记调度的规则
    ~]# ipvsadm -A -f 10 -s rr
    ~]# ipvsadm -a -f 10 -r 192.168.150.40 -g
    ~]# ipvsadm -a -f 10 -r 192.168.150.50 -g

5. lvs的持久连接实现

(1) PPC

与定义集群服务一样,只是在后面加-p选项即可
ipvsadm -A -t 192.168.100.100:80 -s rr -p
ipvsadm -a -t 192.168.100.100:80 -r 192.168.200.100 -g
ipvsadm -a -t 192.168.100.100:80 -r 192.168.200.200 -g

(2) PFWM

  • 首先在调度器的防火墙中将报文打标,以http、https举例
    iptables -t mangle -A PREROUTING -d 192.168.100.100 -p tcp -m multiport --dports 80,443 -j MARK --set-mark 10
  • 然后在调度器中加入ipvs规则即可
    ipvsadm -A -f 10 -s rr -p
    ipvsadm -a -f 10 -r 192.168.200.100 -g
    ipvsadm -a -f 10 -r 192.168.200.200 -g

(3) PCC

定义方式需要将端口指定为0
ipvsadm -A -t 192.168.100.100:0 -s rr -p
ipvsadm -a -t 192.168.100.100:0 -r 192.168.200.100 -g
ipvsadm -a -t 192.168.100.100:0 -r 192.168.200.200 -g