系列一文章简述了LVS常见的五种工作模式,接下来主要讲述LVS的工作原理
IPVSADM 与 IPVS
LVS负责四层均衡负载调度,当我们要定义集群的调度规则时需要借助于一个管理工具,就是ipvsadm
。而ipvsadm
定义的规则最终是通过IPVS
来实现,也就是说ipvsadm
是IPVS
的管理工具,ipvsadm
工作于用户空间,IPVS
工作于内核空间,两者之间的关系好比iptables与netfliter。
IPVS
支持TCP/UDP协议,会从TCP SYNC包开始为一个TCP连接所有的数据包建立状态跟踪机制,保证一个TCP连接中所有的数据包能到同一个后端。所以IPVS是基于TCP状态机进行控制管理,只感知TCP头而不对TCP的payload进行查看;因此,对IPVS后端服务器集群还有一个假定,那就是所有后端都具有同样的应用层的服务功能,但是由于IPVS可以给后端设定权重,所以每个后端的服务的能力可以不同。
`IPVS(IP Virtual Server)发展史:
- 早在2.2内核时,
IPVS
就已经以内核补丁的形式出现。 - 从2.4.23版本开始
IPVS
软件就是合并到linux内核的常用版本的内核补丁的集合。 - 从2.4.24以后
IPVS
已经成为linux官方标准内核的一部分并作为Netfilter的一个模块存在
当Client访问服务时,会访问VIP及其对应的端口,所以LVS接收到的请求报文首先经过PREROUTING链然后进行路由判断,由于此时的DIP为VIP,为设备IP(网卡接口上有配置)所以请求报文会经过INPUT链,此时如果IPVS
发现报文访问的VIP和端口与定义的规则相匹配,IPVS
会根据定义好的规则和算法将报文直接发往POSTROUTING链,最后报文会从LVS发出到达后端RS。
IPVSADM 用法
我们以LVS的DR模式为例,安装好ipvsadm
后在调度机上执行以下命令
ipvsadm -A -t VIP:port -s rr
ipvsadm -a -t VIP:port -r RIP1 -g
ipvsadm -a -t VIP:port -r RIP2 -g
//本案例中配置如下
//ipvsadm -A -t 192.168.0.100:80 -s rr
//ipvsadm -a -t 192.168.0.100:80 -r 192.168.0.4 -g
//ipvsadm -a -t 192.168.0.100:80 -r 192.168.0.5 -g
ipvsadm -A -t VIP:port -s rr
-A 选项为添加一条虚拟服务器记录,即创建一个LVS集群
-t 标识创建的LVS集群服务为tcp协议,VIP:port 标识集群服务IP及端口号
-s Scheduling 调度之意,后面参数为指定的调度算法,有rr、wrr、lc、wlc、lblc、lblcr、dh、sh、sed、nq,默认为wlc,其中rr为Round-Robin缩写,代表轮询算法
所以在创建好一个LVS服务集群后,我们需要设置具体的后端RS、调度算法等信息
ipvsadm -a -t VIP:port -r RIP -g
-a 选项表示添加一个RS到集群中
-t 同上
-r 用于指定需要添加的RIP(RS对应IP)
-g 表示LVS工作模式为DR模式,-i为TUN模式,-m为NAT模式
配置完后我们通过 ipvsadm -Ln
查看生效的规则,但要注意一点,如果没有提前将规则进行保存,在设备重启后配置会消失,所以我们配置完需要用 service ipvsadm save 保存命令,重启后用 service ipvsadm reload
重新载入规则。除此之外,可以用-S将LVS规则保存在指定文件中,通过-R进行重载
ipvsadm -S > file
ipvsadm -R < file
IPVSADM命令可参考该链接
LVS-DR 示例
为模拟集群环境,我们准备了四台虚拟机分别为客户端、LVS服务器、RealServer1、RealServer2
- Client IP:192.168.0.2
- LVS IP:192.168.0.3
- RealServer1 IP:192.168.0.4
- RealServer2 IP:192.168.0.5
- Vitual IP:192.168.0.100(虚IP)
LVS 配置
首先配置LVS,在yum安装ipvsadm
后,此时系统还没有把ipvs模块加载进系统,需要我们执行ipvsadm命令才会加载进去或者modprobe ip_vs。
在配置完规则后,可以通过 ipvsadm -ln 查看已经生效的集群规则,当然为了重启继续使用目前配置的规则,可以-S 进行保存。
由于VIP需要绑定在LVS的网卡上并进行ARP广播(对于外部来说,VIP对应设备就是LVS,对应的arp请求只能由LVS响应),我们添加VIP 192.168.0.100/24 到 ens33:0上。
[root@LVS ~]# yum install ipvsadm -y
[root@LVS ~]# lsmod | grep ip_vs
[root@LVS ~]#
//此时ipvsadm未启用
[root@LVS ~]# ipvsadm -A -t 192.168.0.100:80 -s rr
[root@LVS ~]# ipvsadm -a -t 192.168.0.100:80 -r 192.168.0.4 -g
[root@LVS ~]# ipvsadm -a -t 192.168.0.100:80 -r 192.168.0.5 -g
[root@LVS ~]# lsmod | grep ip_vs
ip_vs_rr 12600 1
ip_vs 145497 3 ip_vs_rr
nf_conntrack 133095 7 ip_vs,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_conntrack_ipv4,nf_conntrack_ipv6
libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack
//ipvsadm已启用
[root@LVS ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.0.100:80 rr
-> 192.168.0.4:80 Route 1 0 0
-> 192.168.0.5:80 Route 1 0 0
//ipvsadm规则生效
[root@LVS ~]# ifconfig ens33:0 192.168.0.100/32 up
RealServer 配置
首先部署好http服务,这边是采用nginx。由于接收数据包的目的IP为VIP,需要在lo上添加VIP,因为RS的VIP不是用来通讯,这里一定要设置/32位掩码!
[root@RealServer1 ~]# rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
[root@RealServer1 ~]# yum install nginx -y
[root@RealServer1 ~]# nginx
//启动nginx
[root@RealServer1 ~]# vi /usr/share/nginx/html/index.html
//改为 RealServer1 192.168.0.4
[root@RealServer1 ~]# curl 127.0.0.1
RealServer1 192.168.0.4
//至此部署好了http服务
[root@RealServer1 ~]# ifconfig lo:0 192.168.0.100/32 up
//将VIP添加到lo:0上,掩码为/32
到这里,会误以为都已配置完全、集群可以正常服务,但在Client实际测试的时候会发现ARP询问VIP时,LVS、RS1、RS2都会进行应答,导致均衡负载未生效。
[root@Client ~]# arping -I ens33 192.168.0.100
ARPING 192.168.0.100 from 192.168.0.3 ens33
Unicast reply from 192.168.0.100 [00:0C:29:AF:6B:F7] 1.778ms
Unicast reply from 192.168.0.100 [00:0C:29:AC:67:31] 1.852ms
Unicast reply from 192.168.0.100 [00:0C:29:BD:38:DA] 1.860ms
Unicast reply from 192.168.0.100 [00:0C:29:BD:38:DA] 1.860ms
Unicast reply from 192.168.0.100 [00:0C:29:BD:38:DA] 1.860ms
//会发现有三个设备响应ARP请求,最终为 00:0C:29:BD:38:DA(RS1)
[root@Client ~]# arping -I ens33 192.168.0.2
ARPING 192.168.0.2 from 192.168.0.3 ens33
Unicast reply from 192.168.0.2 [00:0C:29:AF:6B:F7] 1.500ms
[root@Client ~]# arping -I ens33 192.168.0.4
ARPING 192.168.0.4 from 192.168.0.3 ens33
Unicast reply from 192.168.0.4 [00:0C:29:BD:38:DA] 1.609ms
[root@Client ~]# arping -I ens33 192.168.0.5
ARPING 192.168.0.5 from 192.168.0.3 ens33
Unicast reply from 192.168.0.5 [00:0C:29:AC:67:31] 1.603ms
//三台设备分别为LVS、RS1、RS2
因为RS的lo上已配置VIP,由于arp_ignore
默认为0,设备默会响应VIP对应的ARP请求。配置说明参考 Linux内核参数之arp_ignore和arp_announce
-
arp_ignore
DR模式下,每个RS都要在lo上添加VIP。由于arp_ignore默认为0,各个RS都会响应VIP对应的ARP请求,此时Client无法正确获取LVS上VIP所在的网卡mac。虽然请求报文都到达其中某台RS上,RS也能进行正常响应,但由于报文绕过了LVS没有起到负载均衡的作用,业务量较大时容易出现瓶颈。
所以DR模式下要求arp_ignore
参数要求配置为1。 -
arp_announce
每个设备都会维护自己的一份ARP表,当收到一个未知IP地址的arp请求,就会再本机的arp表中新增对端的IP和MAC记录;当收到一个已知IP地址(arp表中已有记录的地址)的arp请求,则会根据arp请求中的源MAC刷新自己的arp表。
所以DR模式下要求arp_announce
参数要求配置为2。
[root@RealServer1 ~]# echo "1">/proc/sys/net/ipv4/conf/all/arp_ignore
[root@RealServer1 ~]# echo "1">/proc/sys/net/ipv4/conf/lo/arp_ignore
[root@RealServer1 ~]# echo "2">/proc/sys/net/ipv4/conf/all/arp_announce
[root@RealServer1 ~]# echo "2">/proc/sys/net/ipv4/conf/lo/arp_announce
Client 测试
配置完RealServer1、RealServer2的arp_ignore
、arp_announce
后,在Client上测试服务
[root@Client ~]# arping -I ens33 192.168.0.100
ARPING 192.168.0.100 from 192.168.0.3 ens33
Unicast reply from 192.168.0.100 [00:0C:29:AF:6B:F7] 1.301ms
Unicast reply from 192.168.0.100 [00:0C:29:AF:6B:F7] 0.827ms
Unicast reply from 192.168.0.100 [00:0C:29:AF:6B:F7] 0.887ms
Unicast reply from 192.168.0.100 [00:0C:29:AF:6B:F7] 0.801ms
//由LVS响应ARP请求
[root@Client ~]# curl 192.168.0.100
RealServer2 192.168.0.5
[root@Client ~]# curl 192.168.0.100
RealServer1 192.168.0.4
[root@Client ~]# curl 192.168.0.100
RealServer2 192.168.0.5
[root@Client ~]# curl 192.168.0.100
RealServer1 192.168.0.4
//由RealServer1、RealServer2 1:1 轮询响应请求
至此我们手动配置好了一个最基础的DR-LVS集群,但缺点也很明显:
- 配置较多,维护不易
- ipvs规则固定,如果后端RS故障仍然会分配,即没有后端检测
- 单台LVS,单点故障概率高
所以后续介绍keepalived-LVS集群来解决上述问题
参考文章
LVS 官方文档
ipvsadm命令详解
LVS的调度算法
Linux内核参数之arp_ignore和arp_announce