DR模式(直接路由)
概念
- Direct Routing,简称DR模式
- 采用半开放式的网络结构,与TUN模式的结构类似,但内网服务器并不是分散在各地,而是与调度器位于同一个物理网络
- 负载调度器与内网服务器通过本地网络连接,不需要建立专用的IP隧道
- 因为调度器只接收外网的请求,内网服务器的响应则是直接由网关路由出去,所以减轻了调度器的压力
- 针对大规模集群
忽略网关的DR模式工作原理
这里简化工作流程,忽略网关来讲解局域网内数据的转发流程
也就是说目前的场景是:内网中的交换机、后端服务器、调度器
(1)外网客户端发送请求数据包
-
- 网络层:源IP地址为客户端IP,目标IP地址为LVS的VIP(Virtual IP)地址
- 传输层:源IP的一个随机端口。VIP的80端口
- 数据链路层:源MAC地址是客户端的MAC地址,目标MAC地址是调度器的MAC地址
(2)交换机接收到数据包后
-
- 交换机收到数据包后,根据MAC地址表来转发给对应的调度器
- 交换机将下一跳的源MAC地址是交换机的MAC地址,目标MAC地址修改为调度器的MAC地址,封装成数据帧,然后传递给调度器
(3)调度器转发数据包到后端服务器
-
- 调度器将收到的数据包根据调度策略分配给选定的后端服务器
- 网络层:此时源地址还是客户端的IP地址保持不变,目标IP地址还是VIP
- 调度器不能转发数据包,而是调度,数据包内的源、目标地址不变
- 数据链路层:调度器重新封装数据帧,源MAC地址是调度器的MAC地址,目标MAC地址是后端服务器的真实MAC地址
(4)后端服务器处理请求
-
- 后端服务器收到请求后去掉帧头部信息解析,进行应答,生成响应的数据包
- 网络层:此时响应数据包的源IP地址是后端服务器虚拟子 接口绑定的VIP,目标IP地址是客户端的IP
- 数据链路层:后端服务器重新封装数据帧,源MAC地址是后端服务器的MAC地址,目标MAC地址是客户端的MAC地址
- (如果不忽略网关的话,目标MAC地址就是网关的内网接口MAC地址)
(5)交换机转发响应给外网客户端
-
- 最后,交换机将响应数据包返回给外网客户端
- 此时源MAC地址是交换机的MAC地址,目标MAC地址是客户端的MAC地址
- 如果有网关:网关重新封装数据帧,源MAC地址是网关的外网接口MAC地址,目标MAC地址是客户端的MAC地址
注意
IP地址的重要性
- 源IP地址:在整个通信过程中,源IP地址标识了数据包的发送方,即客户端的地址。这是确保服务器能够正确返回响应的关键。
- 目标IP地址:目标IP地址则标识了数据包的最终接收方,如调度器或后端服务器的地址。这确保了数据包在网络中正确路由到达目的地。
如果在传输过程中源IP地址被修改,会导致客户端不接受该数据包,从而导致通信失败或安全问题。
数据帧的重新封装
- 数据帧在每个网络设备之间传输时,会根据下一个设备的MAC地址进行重新封装。这是数据链路层的操作,确保数据能够通过物理网络正常传输。
- 每次重新封装时,会保留原始的网络层(IP层)信息,包括源和目标IP地址。这样做的目的是确保数据包在经过多个网络设备时,能够继续被正确地路由到下一个目标,直到达到最终的接收方。
DR模式中的关键问题
每个节点的VIP
在LVS-DR负载均衡群集中,负载均衡器与节点服务器都要配置相同的VIP地址
为什么VIP要在每个节点上都配置?
是为了让后端服务器生成的响应报文的源地址始终保持是VIP,客户端请求的是VIP,最后应答的也是VIP,保持一致
后端服务器真实IP接收---VIP应答
后端服务器接收请求用的是自己的真实IP接收的,但是响应请求的源地址用的却是VIP
解决方法
需要在每一个后端服务器设置路由条目
本主机内两个网卡接口的路由
本地回环增加一个子接口
当使用ens33网卡收到报文后,如果访问的是VIP的地址,就交给lo:0去处理报文封装
通过路由条目把下一跳修改为本地的另一个虚拟网卡(lo:0)
所以DR模式叫做直接路由
ARP
如果交换机和调度器是第一次通信,就需要发出ARP广播来查找调度器服务器
但是在局域网中调度器和后端服务器具有相同的VIP地址,会造成各服务器ARP通信的混乱
- 当ARP广播发送到LVS-DR集群时,因为调度器和后端服务器都是连接到相同的网络上,他们都会接收到ARP广播
- 应该设置只有前端的调度器进行响应。其他后端服务器不响应 该ARP广播
解决方法
- 对后端服务器进行处理,使其不响应针对VIP的ARP请求
- 使用虚拟接口lo:0承载VIP地址
- 设置内核参数arp_ignore=1表示系统只响应目标地址为本地真实IP的ARP请求
IP地址
当交换机第一次与调度器通信后,网关内ARP缓存表存储的是VIP对应调度器的MAC地址
但是到后端服务器发送响应报文给网关时,这个响应报文的源地址还是VIP但是MAC地址就变成了后端服务器的MAC地址
网关接收到响应以后,会发现VIP对应的MAC地址与ARP缓存表记录的信息对不上
此时如果不处理,那么下次再有外网请求转发时就会直接发送给后端服务器,而不是调度器了
解决方法
对后端服务器进行处理,设置内核参数arp_announce=2表示系统不使用IP包的源地址来设置ARP请求的源地址,而选择发送接口的IP地址
设置完参数以后,后端服务器再发送报文的IP地址就不使用VIP作为地址,而是使用自己的真实地址来发送报文,那么网关接收到了报文就不会冲突了
发送ARP请求时,Linux默认使用IP包的源IP地址(VIP)作为ARP请求包中的源IP地址,而不使用发送接口的IP地址
总结
后端服务器的VIP不参与ARP的请求和应答
案例
案例介绍
为了进一步提高网站的负载能力,现在决定扩展现有的网站平台,基于LVS构建负载均衡集群。
考虑到集群的访问效率,准备采用LVS的DR模式,共享存储设备存放在内网中
案例环境
因为本次案例主要针对Linux上的部署操作,所以与外网通信的网关就模拟存在了
|--------|-----------|----------------|---------|
| 主机 | 操作系统 | IP 地址 | 角色 |
| 服务器 | CentOS7.9 | 192.168.10.101 | 调度器 |
| 服务器 | CentOS7.9 | 192.168.10.102 | Web服务器 |
| 服务器 | CentOS7.9 | 192.168.10.103 | Web服务器 |
| 服务器 | CentOS7.9 | 192.168.10.104 | NFS共享存储 |
| 测试机 | CentOS7.9 | 172.16.16.200 | 客户端,测试机 |
实验步骤
打开五台Linux虚拟机并全部连接上XShell
基本环境设置
修改主机名
给对应的主机修改主机名,以便区分
bash
# 192.168.10.101
[root@localhost ~]# hostnamectl set-hostname LVS
[root@localhost ~]# bash
# 192.168.10.102
[root@localhost ~]# hostnamectl set-hostname Web01
[root@localhost ~]# bash
# 192.168.10.103
[root@localhost ~]# hostnamectl set-hostname Web02
[root@localhost ~]# bash
# 192.168.10.104
[root@localhost ~]# hostnamectl set-hostname nfs
[root@localhost ~]# bash
# 192.168.10.105
[root@localhost ~]# hostnamectl set-hostname client
[root@localhost ~]# bash
调度器设置
配置VIP
在101(调度器)操作
cd进入存放网卡配置文件的目录下,拷贝出一个子接口网卡配置文件,修改如下几条内容
UUID可以保留,因为这两个IP用到的都是同一个物理网卡,不冲突
bash
[root@lvs ~]# cd /etc/sysconfig/network-scripts/
[root@lvs network-scripts]# cp ifcfg-ens33 ifcfg-ens33:0
[root@lvs network-scripts]# vim ifcfg-ens33:0
IPADDR=192.168.10.172
NAME=ens33:0
DEVICE=ens33:0
保存并退出,重启网络,使用ifconfig查看子接口是否被创建出来了
bash
[root@lvs network-scripts]# systemctl restart network
[root@lvs network-scripts]# ifconfig
ens33:0:
inet 192.168.10.172 netmask 255.255.255.0
配置内核参数
调度器并不是转发报文,而是根据调度策略分配,所以在内核配置文件里设置:关闭转发功能
- net.ipv4.conf.all.send_redirects
- 是否允许系统重定向功能
- ICMP重定向消息是用来告知主机在其它子网的更佳路由信息的消息
- net.ipv4.conf.default.send_redirects
- 默认是否允许系统重定向功能
- 如果没有单独为某个接口设置不同的值,那么会使用这个默认值
- net.ipv4.conf.ens33.send_redirects
- 针对ens33网络接口的设置,它覆盖了默认值和全局设置,确保对该网络接口禁止发送重定向消息
bash
[root@lvs ~]# vim /etc/sysctl.conf
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.ens33.send_redirects=0
使用sysctl -p来不用重启系统应用内核配置
bash
[root@lvs ~]# sysctl -p
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.ens33.send_redirects = 0
配置调度策略
为了方便实验,关闭防火墙和内核安全机制,并安装LVS管理程序
bash
[root@lvs ~]# systemctl stop firewalld
[root@lvs ~]# setenforce 0
[root@lvs ~]# yum -y install ipvsadm
使用ipvsadm命令来创建集群服务负责将到达192.168.10.172:80的请求根据设定的调度策略分发到后端服务器。
然后可以使用ipvsadm -ln来查看现有的调度策略
- -g:gateway,指定为DR模式
bash
[root@lvs ~]# ipvsadm -A -t 192.168.10.172:80 -s wrr
[root@lvs ~]# ipvsadm -a -t 192.168.10.172:80 -r 192.168.10.102 -g -w 1
[root@lvs ~]# ipvsadm -a -t 192.168.10.172:80 -r 192.168.10.103 -g -w 2
[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.10.172:80 wrr
-> 192.168.10.102:80 Route 2 0 0
-> 192.168.10.103:80 Route 2 0 0
Web服务器配置
先右键XShell终端的空白处,开启会话同步
注意只开启102和103两个Web服务器的会话同步,其他根据下图关闭
在102(Web服务器①)操作
为了方便实验,关闭防火墙和内核安全机制
bash
[root@web01 ~]# systemctl stop firewalld
[root@web01 ~]# setenforce 0
绑定VIP
后端服务器要通过本地回环来绑定VIP
这里在本机回环接口上创建一个虚拟子接口,把IP设为VIP,实现封装时的需求
bash
[root@web01 ~]# cd /etc/sysconfig/network-scripts/
[root@web01 network-scripts]# cp ifcfg-lo ifcfg-lo:0
[root@web01 network-scripts]# vim ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.10.172
NETMASK=255.255.255.255
#NETWORK=127.0.0.0
#BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback
255.255.255.255(/32)
- 代表完全独立的IP,哪怕有一个相同IP和相同掩码也不会冲突
- 意味着这个IP地址不再代表一个网络或者子网的一部分,而是指定了一个具体的主机,避免与其他设备的IP地址重叠或冲突
- 32位掩码的IP通常不用于实际的通信,只用于管理,我们这里就只用于封装数据包
保存并退出,重启网络,可以使用ifconfig查看lo:0有没有创建成功
bash
[root@web01 network-scripts]# systemctl restart network
[root@web01 network-scripts]# ifconfig
lo:0:
inet 192.168.10.172 netmask 255.255.255.255
设置路由条目
如果有请求访问192.16.16.172就路由给lo:0去处理
使用route命令,指定请求的IP,再指定处理的设备为lo:0但此时只是临时生效,关机后就失效了
要永久生效的话,可以在/etc/rc.local文件末尾追加该命令,来实现开机时自动执行该命令
bash
[root@web01 ~]# route add -host 192.168.10.172 dev lo:0
[root@web01 ~]# vim /etc/rc.local
route add -host 192.168.10.172 dev lo:0
设置内核参数
针对上面概念我们提到的ARP请求的问题,需要修改内核参数,来不让VIP参与ARP的请求和应答
在内核配置文件末尾追加下方代码块中的内容,然后使用sysctl -p应用配置参数
bash
[root@web01 ~]# vim /etc/sysctl.conf
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.default.arp_announce=2
net.ipv4.conf.lo.arp_ignore=1
net.ipv4.conf.lo.arp_announce=2
[root@web01 ~]# sysctl -p
安装Web服务
还是在102(Web服务器①)操作(会话同步中)
安装Apache网站服务,启动httpd服务
bash
[root@web01 ~]# yum -y install httpd
[root@web01 ~]# systemctl start httpd
关闭全部会话同步
分别添加测试对应的网页内容
在102(Web服务器①)操作(会话同步关闭)
创建网页文件,添加以下内容
bash
[root@web01 ~]# vim /var/www/html/index.html
Test Web 01
在103(Web服务器②)操作
创建网页文件,添加以下内容
bash
[root@web02 ~]# vim /var/www/html/index.html
Test Web 02
测试
在105(外网客户端)操作
因为在设置调度策略时指定了权重值,所以调度器会把每3次请求中的2次分配给102,1次分配给103
bash
[root@client ~]# curl 192.168.10.172
Test Web 01
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 01
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 02
模拟故障
如果把102的网站服务关闭了,只留下一个103,然后让客户端再去访问
bash
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
curl: (7) Failed connect to 192.168.10.172:80; 拒绝连接
因为其中一台后端服务器故障了,而调度策略中又指定了分配请求给该服务器,但是该服务器的服务已经关闭
所以LVS的缺点就是:如果只单独使用LVS来实现负载均衡集群,那么假如有后端服务器故障了,需要手动删除调度策略,LVS不会自动更新调度策略,LVS的还需要借助其他技术手段才能实现真正的高可用
NFS共享存储
在104(共享存储服务器)操作
关闭防火墙和内核安全机制,然后安装nfs文件系统所需依赖
bash
[root@nfs ~]# systemctl stop firewalld
[root@nfs ~]# setenforce 0
[root@nfs ~]# yum -y install nfs-utils
[root@nfs ~]# vim /etc/exports
/opt/wwwroot 192.168.10.0/24(rw,sync,no_root_squash)
# 保存并退出
创建共享目录,并启动服务
bash
[root@nfs ~]# mkdir /opt/wwwroot
[root@nfs ~]# systemctl start nfs
[root@nfs ~]# systemctl start rpcbind
挂载共享目录
在102(Web服务器①)操作
安装nfs文件系统所需依赖,使用mount命令指定文件系统类型和挂载位置,再指定挂载点
最后使用df命令查看是否挂载成功
bash
[root@web01 ~]# yum -y install nfs-utils
[root@web01 ~]# mount -t nfs 192.168.10.104:/opt/wwwroot /var/www/html/
[root@web01 ~]# df
文件系统 1K-块 已用 可用 已用% 挂载点
192.168.10.104:/opt/wwwroot 204368640 1901824 202466816 1% /var/www/html
在103(Web服务器②)操作
步骤同上
bash
[root@web02 ~]# yum -y install nfs-utils
[root@web02 ~]# mount -t nfs 192.168.10.104:/opt/wwwroot /var/www/html/
[root@web02 ~]# df
文件系统 1K-块 已用 可用 已用% 挂载点
192.168.10.104:/opt/wwwroot 204368640 1901824 202466816 1% /var/www/html
因为挂载一个目录到/var/www/html目录后,会覆盖该目录原本的内容,所以这里继续在103的挂载点下创建一个测试的网页文件,添加以下内容
bash
[root@web02 html]# vim index.html
NFS Test
测试
在105(外网客户端)操作
最后在客户端测试,共享存储的功能就实现了
bash
[root@client ~]# curl 192.168.10.172
NFS Test
[root@client ~]# curl 192.168.10.172
NFS Test
[root@client ~]# curl 192.168.10.172
NFS Test
案例完成