系列一文章简述了 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 集群来解决上述问题