LVS VS/DR实验

VS/DR模型的原理

(1)当负载均衡器(Director)收到访问VIP的报文的时候,它首先会把2层的数据帧拆开,得到里面3层的数据,发现目标IP是自己的,然后发往INPUT链上,由于INPUT上我们已经配置了LVS集群服务,并且是DR模式,所以LVS会重新封装一个2层帧,源MAC地址则是出栈的网卡MAC,目的MAC则是由调度算法得出来的某RIP的MAC地址,但是原包的源IP和目的IP是不会更改的,最后发回给交换机
(2)交换机收到数据帧后,根据目的MAC把数据帧发到对应的RS上,当RS收到数据帧后,拆开2层帧,查看3层内容,目的IP是VIP,在此模式下,VIP应该已经在RS上配置,所以收下来。
(3)当RS收到请求报文后,由于目的IP是VIP,而自己协议栈中是有此IP,所以发往到用户空间的HTTP程序;HTTP响应报文则直接发送到RS的网关上面,此时响应报文的源IP应该是VIP,目的IP是CIP。源MAC则是出栈的网卡MAC,目的MAC则是网关。最后客户端成功收到报文。

以上,有几个问题需要思考和注意。
1.DIP和RIP之间通信不是通过IP网络层,只是通过2层数据链路层的MAC地址通信,所以DIP跟RIP必须是同一物理网络,即连在同一交换机上。

2.由于响应报文的源IP必须是VIP,所以在RS上需要配置一个VIP。
通常我们在RS的一个回环接口上配置一个VIP,然后再配置一条静态路由,把目的为VIP的数据,都通过lo接口传入,这样在回包时,响应报文的源IP就为VIP了。

3.如果RS只有一个网卡,数据流入流出都需要经过RIP,所以RIP跟网关必须在同一子网,这样的话,那么VIP似乎都要跟RIP在同一子网囖?
~是的,如果RS只有一个出口,那么在这个情况下,VIP跟RIP都需要在同一子网中,如果在RS上配置了多张网卡,数据流出能经由其他网卡,那RIP和VIP就可以不用处于同一子网中。

4.既然后端的RS都配置了VIP,需要更多的是考虑ARP问题。

  • 一个主机加入了网络后,默认会向所有接口通告自己的IP和MAC地址,此时我们应该禁止通告VIP地址和MAC地址
  • 当网关在收到目的地址为VIP的数据包时,会发送ARP请求,请求VIP的MAC地址是什么,此时,我们应该只允许作为调度器的服务器去响应这个报文,RS不能响应此报文。

一个linux主机在加入网络后,默认会通告自己所有的IP地址给所有接口,但我们应该禁止它通告VIP给任何人。还有就是,在发起ARP请求时候,源IP不可以为VIP。可以通过内核参数:arp_announce来控制。

arp_announce简介:

arp_announce它的作用是控制系统对外发送arp请求时,如何选择请求包的源IP

arp_announce的参数

0:默认值,允许使用任意网卡上的IP地址作为arp请求的源IP,很可能会使用流出接口的IP地址和MAC地址。
1:尽量避免使用不属于该发送网卡子网的本地地址作为发送arp请求的源IP地址。
2:忽略IP数据包的源IP地址,选择该发送网卡上最合适的本地地址作为arp请求的源IP地址。

arp_announce在DR模式下的作用:

每台服务器或交换机等都有一张2层转发表,称为ARP表,该表是保存这IP与MAC地址之间的对应关系。当收到一个ARP请求时,会缓存该请求的源IP和源MAC,当收到一个已知IP地址(arp表中已有记录的地址)的arp请求,则会根据arp请求中的源MAC刷新自己的arp表。
如果arp_announce=0,也是默认值,则网卡在发送arp请求时,可能选择的源IP地址并不是该网卡自身的IP地址,如果在RS设置了arp_announce=0意味着发送ARP请求时,源IP可能会是VIP,这样会带来问题的。所以一般在DR模式下,arp_announce设置为2,这样,在发送ARP或通告ARP时候,源IP和源MAC肯定是出栈的网卡地址。而不会是VIP

以上参数,只是解决了发送的APR请求时的源IP和源MAC问题,但如果RS收到了对VIP的ARP的请求会作回应的,所以我们应该禁止此情况发生,可以使用内核参数:arp_ignore来作限制:

arp_ignore简介:

参数的作用是控制系统在收到外部的arp请求时,是否要返回arp响应
参数常用的取值
0:默认值,表示可使用本地任意接口上配置的任意地址进行响应
1:仅在请求的目标IP配置在本地主机的接收到请求报文接口上时,才给予响应;

arp_ignore在DR模式下的作用:

每个真实服务器节点都要在环回网卡上绑定虚拟服务IP。这时候,如果客户端对于虚拟服务IP的arp请求广播到了各个真实服务器节点,如果arp_ignore参数配置为0,则各个真实服务器节点都会响应该arp请求,
此时负载均衡可能失去控制。通常我们把arp_ignore设置为1,限制只请求RIP网卡的MAC地址才予以响应。

实验1:VIP/DIP/RIP处于同一子网的场景

实验拓扑:

LVS VS/DR实验_第1张图片
LVS DR.png-31.2kB
路由器IP设置:
[root@route ~]# ip a s 
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
   
2: ens33:  mtu 1500 qdisc =
    inet 192.168.30.98/24 brd 192.168.30.255 scope global =
    
3: ens36:  mtu 1500 qdisc =
    inet 172.16.1.1/24 brd 172.16.1.255 scope global =
    

    
调度器IP设置://注意,VIP配置在ens的子接口上
[root@director ~]# ip a s 
ens33: flags=4163  mtu 1500
        inet 172.16.1.98  netmask 255.255.255.0  broadcast 172.16.1.255


ens33:0: flags=4163  mtu 1500
        inet 172.16.1.99  netmask 255.255.255.255  broadcast 172.16.1.99
        ether 00:0c:29:fb:84:fb  txqueuelen 1000  (Ethernet)




RS1服务器IP:
[root@rs1 ~]# ip a s 
1: lo:  mtu 65536 qdisc noqueue state 
    inet 127.0.0.1/8 scope host lo
     
2: ens33:  mtu 1500 qdisc 
    inet 172.16.1.11/24 brd 172.16.1.255 scope global 
    
RS2服务器IP:
[root@rs2 ~]# ip a s 
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
     
2: ens33:  mtu 1500 qdisc 
    inet 172.16.1.12/24 brd 172.16.1.255 scope global 



在为各RS增加IP之前,需要对2各内核参数对ARP进行修改
也就是arp_announce和arp_ignore

对个RS的2个参数进行设置:
一般来讲,对这2类参数很多情况下用脚本实现,即通用又方便管理,而且还原也很方便。

#/bin/bash
#
#
case $1 in
#SET 
start)
        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
        ;;
#UNSET
stop)
        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
        ;;
*)
        echo "Usage $(basename $0 ) start|stop"
        exit 1
esac

配置好各RS参数后,接下来在RS的回环接口上增加一个VIP

 ~]# ifconfig lo:0 172.16.1.99 netmask 255.255.255.255 up

lo:0: flags=73  mtu 65536
        inet 172.16.1.99  netmask 255.255.255.255
        loop  txqueuelen 1000  (Local Loopback)

2台RS都配置VIP

为了保证响应报文的的源IP是VIP,所以数据入栈时,应该经由lo接口入栈,那数据出去会从lo接口出栈,由此,配置在RS上配置一条静态路由,所有访问VIP的数据都经由lo接口。

两台RS都配置:

~]# route add -host 172.16.1.99 dev lo:0

接下来,就可以在调度器上配置规则了:

[root@director ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.1.99:80 rr
  -> 172.16.1.11:80               Route   1      0          0         
  -> 172.16.1.12:80               Route   1      0          0   

配置客户端,把网关设置成充当路由器的Linux
客户端IP

[root@localhost ~]# ip a s

2: ens33:  mtu 1500 qdisc 
    inet 192.168.30.148/24 brd 192.168.30.255 scope global 
    
路由表:
[root@localhost ~]# ip route s
default via 192.168.30.98 dev ens33 proto static metric 20100 
192.168.30.0/24 dev ens33 proto kernel scope link src 192.168.30.148 metric 100 

[root@localhost ~]# for i in {1..5};do curl http://172.16.1.99/test.html;done
This Page form rs2
This Page form rs1
This Page form rs2
This Page form rs1
This Page form rs2

实验2:VIP和DIP/RIP不在同一网段的实验。

拓扑图

LVS VS/DR实验_第2张图片
VIP与DIP-RIP不在同一网段实验.png-45.2kB

虚拟机网络环境

LVS VS/DR实验_第3张图片
image_1cgh6e89p739jo8ba1jdct2q43.png-24.9kB

说明:按照拓扑图,各主机的网卡连接的网络情况如下:

  1. 充当路由器的Linux主机:
    网卡1:NAT模式,用于模拟与外网通信(地址:192.168.30.98)
    网卡2:连接到VMnet2,用于与VIP通信(地址:172.16.1.1)
    网卡3:连接到VMnet4,用于RS的网关(地址:10.1.1.1)

  2. 调度器(Director)
    网卡1:连接到VMnet2,配置VIP地址(地址:172.16.1.99)
    网卡2:连接到VMnet3,用于与RS通信(地址:192.168.10.99)

  3. RS1
    网卡1:连接到VMnet3,用于与调度器通信(地址:192.168.10.11)
    网卡2:连接到VMnet4,与网关通信(地址:10.1.1.11)
    按照拓扑图配置好全部虚拟机的IP

  4. RS2
    网卡1:连接到VMnet3,用于与调度器通信(地址:192.168.10.12)
    网卡2:连接到VMnet4,与网关通信(地址:10.1.1.12)

按照拓扑图配置好全部虚拟机的IP

路由器的IP配置
1: lo:  mtu 65536 qdisc noqueue state 
    inet 127.0.0.1/8 scope host lo
      
2: ens33:  mtu 1500 qdisc 
    inet 192.168.30.98/24 brd 192.168.30.255 scope global 
    
3: ens36:  mtu 1500 qdisc 
    inet 172.16.1.1/24 brd 172.16.1.255 scope global 
    
4: ens37:  mtu 1500 qdisc 
    inet 10.1.1.1/24 brd 10.1.1.255 scope global 
       
路由表:
[root@route ~]# ip route s 
default via 192.168.30.2 dev ens33 proto static metric 103 
10.1.1.0/24 dev ens37 proto kernel scope link src 10.1.1.1 metric 102 
172.16.1.0/24 dev ens36 proto kernel scope link src 172.16.1.1 metric 101 
192.168.30.0/24 dev ens33 proto kernel scope link src 192.168.30.98 metric 103
       
-------------------------------------------------------------
调度器的IP设置:
[root@director ~]# ip a s 
1: lo:  mtu 65536 qdisc noqueue state 
    inet 127.0.0.1/8 scope host lo
     
2: ens33:  mtu 1500 qdisc 
    inet 172.16.1.99/25 brd 172.16.1.127 scope global 
    
3: ens36:  mtu 1500 qdisc 
    inet 192.168.10.99/24 brd 192.168.10.255 scope global 
    
路由表:
[root@director ~]# ip route s 
default via 172.16.1.1 dev ens33 proto static metric 100 
172.16.1.0/25 dev ens33 proto kernel scope link src 172.16.1.99 metric 100 
192.168.10.0/24 dev ens36 proto kernel scope link src 192.168.10.99 metric 101 

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

RS1的IP设置:
1: lo:  mtu 65536 qdisc noqueue state 
    inet 127.0.0.1/8 scope host lo
     
2: ens33:  mtu 1500 qdisc 
    inet 192.168.10.11/24 brd 192.168.10.255 scope global 
    
3: ens36:  mtu 1500 qdisc 
    inet 10.1.1.11/24 brd 10.1.1.255 scope global 
    
路由表:
[root@rs1 ~]# ip route s 
default via 10.1.1.1 dev ens36 proto static metric 100 
10.1.1.0/24 dev ens36 proto kernel scope link src 10.1.1.11 metric 100 
192.168.10.0/24 dev ens33 proto kernel scope link src 192.168.10.11 metric 101 

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

RS2的IP设置:
1: lo:  mtu 65536 qdisc noqueue state 
    inet 127.0.0.1/8 scope host lo
      
2: ens33:  mtu 1500 qdisc 
    inet 192.168.10.12/24 brd 192.168.10.255 scope global  
    
3: ens36:  mtu 1500 qdisc 
    inet 10.1.1.12/24 brd 10.1.1.255 scope global 

路由表:
[root@rs2 ~]# ip route s 
default via 10.1.1.1 dev ens36 proto static metric 100 
10.1.1.0/24 dev ens36 proto kernel scope link src 10.1.1.12 metric 100 
192.168.10.0/24 dev ens33 proto kernel scope link src 192.168.10.12 metric 101 

在路由器上打开IP转发功能

充当路由器的Linux打开IP转发功能
[root@route ~]# echo 1 > /proc/sys/net/ipv4/ip_forward

配置SNAT

此外,在这个拓扑图中,充当路由器的linux主机只有一个连接外网的出口,就是NAT的那块网卡,所以对于调度器和RS主机的网关数据的流出,我使用iptables的SNAT转换源IP使数据流出。

对于172.16.1.0和10.1.1.0 我使用SNAT转换。
[root@route ~]# iptables -t nat -nvL
...
Chain POSTROUTING (policy ACCEPT 27 packets, 2043 bytes) 
 pkts bytes target     prot opt in     out     source               destination         
  138  9918 MASQUERADE  all  --  *      ens33   172.16.1.0/24        0.0.0.0/0           
   65  4821 MASQUERADE  all  --  *      ens33   10.1.1.0/24          0.0.0.0/0  
 

限制ARP

接下来,配置2台RS的内核参数,限制ARP请求。
为了方便管理,我使用脚本来实现:

[root@rs1 ~]# ./set_arp.sh start
[root@rs2 ~]# ./set_arp.sh start

脚本内容:

#/bin/bash
#
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 2 > /proc/sys/net/ipv4/conf/all/arp_announce
        echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
        ;;
stop)
        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
        ;;
*)
        echo "Usage $(basename $0) start|stop"
        exit 1
        ;;
esac

在RS上配置VIP

在各RS上的lo:0接口上配置VIP

[root@rs2 ~]# ifconfig lo:0 172.16.1.99 up
[root@rs1 ~]# ifconfig lo:0 172.16.1.99 up

在RS上配置静态路由

为了让响应包的源IP设置为VIP,所以在各RS上配置一条静态路由。

[root@rs1 ~]# route add -host 172.16.1.99 dev lo:0
[root@rs2 ~]# route add -host 172.16.1.99 dev lo:0

在RS1上查看路由表:
[root@rs1 ~]# ip route s 
default via 10.1.1.1 dev ens36 proto static metric 100 
10.1.1.0/24 dev ens36 proto kernel scope link src 10.1.1.11 metric 100 
172.16.1.99 dev lo scope link src 172.16.1.99   //转发到lo:0上处理
192.168.10.0/24 dev ens33 proto kernel scope link src 192.168.10.11 metric 101 

RS2上也一样的,所以就不贴了

配置HTTP服务

接下来,配置好NGINX服务,新建测试页,为了测试方便,所以2台RS都写不同的内容,这样看到的效果会更明显。

[root@rs1 ~]# yum install nginx 
[root@rs1 ~]# vim /usr/share/nginx/html/test.html 
This Page from RS1!
xxx

[root@rs1 ~]# systemctl start nginx 

RS2上也是一样的操作 ,所以我不贴了


测试HTTP服务

直接使用RIP访问无问题:


LVS VS/DR实验_第4张图片
image_1cggiof114jj17rm51lm55ejl9.png-22.9kB
LVS VS/DR实验_第5张图片
image_1cggj44bh1kadan15nmq3v44816.png-22.2kB

在调度器上配置调度规则

接下来,配置调度器规则。

[root@director ~]# ipvsadm -A -t 172.16.1.99:80 -s rr 
[root@director ~]# ipvsadm -a -t 172.16.1.99:80 -r 192.168.10.11 -g
[root@director ~]# ipvsadm -a -t 172.16.1.99:80 -r 192.168.10.12 -g

查看规则:
[root@director ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.1.99:80 rr
  -> 192.168.10.11:80             Route   1      0          0         
  -> 192.168.10.12:80             Route   1      0          0   

至于,配置完成,接下来还有一个非常关键的问题。
以下是借鉴骏马金龙博客(http://www.cnblogs.com/f-ck-need-u/p/8472744.html)的文章

反向追踪

如果按以上配置的话,按逻辑上,是应该可以成功负载的,但是实际上,是不能成功访问到的,因为涉及到了反向路径过滤的问题。
反向路径过滤的问题
linux内核有一个反向路径过滤的功能参数,叫rp_filter,rp_filter参数有三个值,0、1、2,Linux上默认为1。
0:不开启反向追踪
1:严格检验 (Linux默认是1)
2:松散校验

按照默认值会有2个问题发生:

问题一
拓扑图种,我的Linux充当了路由器,并且默认rp_filter=1,响应数据包从ens37网卡收到,但是根据我的路由表,该数据包出去的网卡却是ens33,这时,Linux认为这不是最佳路径,所以会把数据包丢弃。

如果设置rp_filter=2,只要Linux反向检查时能和VIP能互相通信就能满足检查条件,即使尽管检查的接口和接收RS数据包的接口不同也无所谓。换句话说,当设置为该值时,无论RIP、VIP是否同网段,数据包都会保留并转发给Client;

如果设置rp_filter=0,则完全不检查源地址,直接转发。

以上是在Linux作为Route的设置。

问题二:
在RS上也需要设置。
在RS上,收到对VIP的请求包需要转发到lo接口上,最后由ens36发出。
RIP的网卡收到后,会严格反向追踪检查,检查源地址的发出接口是不是和接受的接口是同一网卡,这样,由于请求包由ens33收到,但是发出是由ens36发出,Linux认为这是不是最佳路径,所以丢弃。

以上分析,需要对充当Route和RS这几台服务器修改一下rp_filter,一般该为2即可。

路由器上设置
[root@route ~]# echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter

RS上设置
[root@rs1 conf]# echo 2 >  /proc/sys/net/ipv4/conf/lo/rp_filter
[root@rs2 conf]# echo 2 >  /proc/sys/net/ipv4/conf/lo/rp_filter

测试

在客户端上测试:

[root@localhost ~]# for i in {1..5};do curl http://172.16.1.99/test.html;done
This Page from RS2!
This Page from RS1!
This Page from RS2!
This Page from RS1!
This Page from RS2!

已经能正常调度。

抓包分析

在路由器的ens33抓包

在拓扑图中,路由器的ens33是数据的必经之路,TCP3次握手,请求报文和响应报文都应该能捕捉到。如图:


LVS VS/DR实验_第6张图片
image_1cggq388k354v301d5q19h29m21j.png-103kB

红色方框:3次握手过程
蓝色方框:客户端的请求报文以及服务端的ACK确认报文
橙色方框:服务端的响应报文以及客户端的ACK确认报文
紫色方框:4次挥手过程,但实际上只有3次报文交互。

调度器的抓包情况

在调度器上,一定只能捕捉到客户端发给服务端的包,服务端的响应包不可能在调度器上被抓到的。


image_1cggqdporonf1q3r1q3u1o4618vo2g.png-66.7kB
image_1cggqdporonf1q3r1q3u1o4618vo2g.png-66.7kB

红色方框:TCP3次握手的报文,这里只有2个,有一个包是服务端响应给客户端的,所以在调度器是捉不到的
蓝色方框:客户端的请求报文。
橙色方框:服务端发给客户端后,客户端发送ack确认报文
紫色方框:四次挥手过程。客户端发了2个包给服务端,一个是fin断开包,还有一个是确认包,中间的包由于不经由调度器,所以不能捉到。

最后在路由器的ens37(RS的网关上的数据包)

image_1cggqptpfeu7142c1m8p136ttot2t.png-52.6kB
image_1cggqptpfeu7142c1m8p136ttot2t.png-52.6kB

红色方框:服务端发给客户端的TCP握手确认包
蓝色方框:客户端发送请求报文给服务端,服务端发回ACK确认报文
橙色方框:客户端发送的请求报文
紫色方框:挥手包。

总结
从抓包情况分析,跟LVS/DR原理实现一样,数据包的确通过调度器转发给RS服务器,RS服务器响应报文也不经由调度器,这样,调度器的吞吐效率大幅提升。

你可能感兴趣的:(LVS VS/DR实验)