我们都知道LVS有LVS-DR,LVS-NAT,LVS-TUN三种模式,其中DR模式意为Direct Routing(直接路由),是调度器与实际服务器都有一块网卡连在同一物理网段上的情况。本文主要对LVS/DR模式原理进行了阐述,另外还有一篇FAQs,给有相关疑问的朋友们做个参考。
LVS-DR工作原理详解
为了阐述方便,我根据官方原理图另外制作了一幅图,如下图所示:VS/DR的体系结构:
LVS-DR工作原理_集群
我将结合这幅原理图及具体的实例来讲解一下LVS-DR的原理,包括数据包、数据帧的走向和转换过程。
官方的原理说明:Director接收用户的请求,然后根据负载均衡算法选取一台realserver,将包转发过去,最后由realserver直接回复给用户。
实例场景设备清单:
LVS-DR工作原理_lvs_02
说明:我这里为了方便,client是与vip同一网段的机器。如果是外部的用户访问,将client替换成gateway即可,因为IP包头是不变的,变的只是源mac地址。
① client向目标vip发出请求,Director接收。此时IP包头及数据帧头信息如下:
LVS-DR工作原理_休闲_03
② VS根据负载均衡算法选择一台active的realserver(假设是192.168.57.122),将此RIP所在网卡的mac地址作为目标mac地址,发送到局域网里。此时IP包头及数据帧头信息如下:
LVS-DR工作原理_集群_04
③ realserver(192.168.57.122)在局域网中收到这个帧,拆开后发现目标IP(VIP)与本地匹配,于是处理这个报文。随后重新封装报文,发送到局域网。此时IP包头及数据帧头信息如下:
LVS-DR工作原理_lvs_05
④ 如果client与VS同一网段,那么client(192.168.57.135)将收到这个回复报文。如果跨了网段,那么报文通过gateway/路由器经由Internet返回给用户。
作者简介:戴海军(daihaijun@gmail.com),现就职于51.com,应用运维工程师。目前关注LVS/Nginx/Keepalived负载均衡和高可用技术。
==================================================================================
 
1. LVS/DR如何处理请求报文的,会修改IP包内容吗?
1.1 vs/dr本身不会关心IP层以上的信息,即使是端口号也是tcp/ip协议栈去判断是否正确,vs/dr本身主要做这么几个事:
1)接收client的请求,根据你设定的负载均衡算法选取一台realserver的ip;
2)以选取的这个ip对应的mac地址作为目标mac,然后重新将IP包封装成帧转发给这台RS;
3)在hash table中记录连接信息。
vs/dr做的事情很少,也很简单,所以它的效率很高,不比硬件负载均衡设备差多少。
数据包、数据帧的大致流向是这样的:client --> VS --> RS --> client
1.2 前面已作了回答,vs/dr不会修改IP包的内容.
2. RealServer为什么要在lo接口上配置VIP?在出口网卡上配置VIP可以吗?
2.1 既然要让RS能够处理目标地址为vip的IP包,首先必须要让RS能接收到这个包。
在lo上配置vip能够完成接收包并将结果返回client。
2.2 答案是不可以将VIP设置在出口网卡上,否则会响应客户端的arp request,造成client/gateway arp table紊乱,以至于整个load balance都不能正常工作。
3. RealServer为什么要抑制arp帧?
这个问题在上一问题中已经作了说明,这里结合实施命令进一步阐述。我们在具体实施部署的时候都会作如下调整:
       echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
       echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
       echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
       echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
我相信很多人都不会弄懂它们的作用是什么,只知道一定得有。我这里也不打算拿出来详细讨论,只是作几点说明,就当是补充吧。
3.1
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
这两条是可以不用的,因为arp对逻辑接口没有意义。
3.2 如果你的RS的外部网络接口是eth0,那么
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
其实真正要执行的是:
echo "1" >/proc/sys/net/ipv4/conf/eth0/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/eth0/arp_announce
所以我个人建议把上面两条也加到你的脚本里去,因为万一系统里上面两条默认的值不是0,那有可能是会出问题滴。
4. LVS/DR load balancer(director)与RS为什么要在同一网段中?
从第一个问题中大家应该明白vs/dr是如何将请求转发给RS的了吧?它是在数据链路层来实现的,所以director必须和RS在同一网段里面。
5. 为什么director上eth0接口除了VIP另外还要配一个ip(即DIP)?
5.1 如果是用了keepalived等工具做HA或者Load Balance,则在健康检查时需要用到DIP。
5.2 没有健康检查机制的HA或者Load Balance则没有存在的实际意义。
6. LVS/DR ip_forward需要开启吗?
不需要。因为director跟realserver是同一个网段,无需开启转发。
7. director的vip的netmask一定要是255.255.255.255吗?
lvs/dr里,director的vip的netmask 没必要设置为255.255.255.255,也不需要再去
route add -host $VIP dev eth0:0
director的vip本来就是要像正常的ip地址一样对外通告的,不要搞得这么特殊.
=====================================================================
在网上流传的很多文章中,LVS-DR模式都要求VIP和RIP在同一网段,很少有在不同网段配置成功的案例。但章文嵩博士已经在官网上明
确回答了是可以在不同网段的(见http://zh.linuxvirtualserver.org/node/155),负载调度器只要有一个网口和真实服务器是通过不分
段的网络连接起来就可以,真实服务器可以通过自己的路由器将响应报文发送给客户。也就是说Director至少要有两个网口才满足VIP和RIP
不在同一网段。
LVS-HOWTO(http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.LVS-DR.html)也说明了LVS-DR的要求。
从realserver到client路由,可以是另外的,也可能通过director,但要使用director做路由必须对director的内核打forward_shared
补丁,不然director不会转发源IP是自已的包(见http://zh.linuxvirtualserver.org/node/249#comment-352)。
如果使用另外的路由,则只要求能从realserver到client就行了,不需要得到client的响应,因此realserver可以放在防火墙后面。
 
 
请教,LVS/DR中是否要求VIP(虚拟服务器地址)和RIP(真实服务器地址)必须在同一个网段内?
未必是这样的。VIP和RIP不一定是一个网段的。
我们可以手册中的通过直接路由实现虚拟服务器(VS/DR)的图片。负载调度器只要有一个网口和真实服务器是通过不分段的网络连接起来就可以。真实服务器可以通过自己的路由器将响应报文发送给客户。
 
 
 
另一个问题,很多人都遇到过,为了节约服务器,keepalived主备上都有realserver, 最后发现主备两台lvs不正常,负载很高
下面来分析一下为什么.
由于keepalived 的ipvsadm 主备都运行的,只不过备没有得到vip
问题来了,如果一个用户到主的vip上被分到备上的realserver ,因为备上的ipvsadm也在工作,如果备上的这个用户又被备的keepalievd 分到主上的realserver上,这样会引起死循环.
 
以下是网上找的,另一个网友分析的:
 
 
配置的输出如下,可以见到有一个地方不一样,就是显示有个地方是 Local。
#  ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  6 rr
  -> 192.168.1.233:3306           Local   1      0          0
  -> 192.168.1.213:3306           Route   1      0          0
二台机器上的配置都是这样(^-^上面其实有小修改),在这种架构中,我只要停止我的备份的 keepalived ,就能正常的工作,不然一定有其中一台数据库连接到最后就中断停止在那个地方不动了。通过抓包,大量包被不断的转发来转发去。
 详细分析:
   客户端发送连接的请求到  VIP 的指定的端口
    当前的 director 会选择二个 realserver 来转发请求,会传送数据给 localnode 的本机网卡或者备份的机器上指定的那个 MAC 的 eth0  (同时他也做为 realserver) . 正常的 LVS ,这些数据包会被监听这个 VIP 的程序接收。
    如果数据包是发送给备份的 director 服务器的 eth0 接口。它会不能正常的被监听指定端口的程序所接收,因为数据包会首先先经过 ip_vs()。
    这时,有 50% 的机会,这个包被转发给 。这时会生成标准的回应数据包给客户端。因为能正常的回应客户端,这时 LVS 的功能是正常的。我们想所有的包都直接给监听程序来处理。并不想直接通过 ip_vs() 来转发。
    这时还有 50% 的数据包会直接在次转给主 LVS 的 eth0/VIP。
    我们不想数据包从备份的 LVS 在次转回去给主 LVS 这样会形成 。
    所以我们要让 eth0 上发到给 VIP 的包, 只要不是其它 LVS 发的,才使用 ip_vs() 来处理。
简单来讲:当客户端发送数据包给 VIP 。比如我们的 Director1 (Master 主)这个接口正在工作,这时 LVS 能接收到这个包,然后根据 keepalived 的配置进行 load balance 。这时 Director1 会使用 LVS-DR 的功能给包路由给自己或者 Director2 (Backup)。
这时有个问题,在这个例子中因为我们使用了 keepalived 。这时 Director2 这台是一台 VIP 的备份服务器。这时 keepalived 默认会立即启动使用 ipvsadm 的规则来配置这台服务器怎么样做备份的处理.来使得更快的故障转移。所以这时这些规则这台备份的 Director2 主机都会存在。
这就有问题了。当从 Director1 (Master 主),比如使用 rr 。会转发大约 50% 的包从 Director1 到  Director2 (Backup)的 3306 的端口。这时因为 Director2 因为这些 LVS-DR 的配置规则会接着给这些包,在做一次 load balance 。又发回去给 Director1,这时会产生一个死的循环。
随着时间的推移,不但不能正常的处理连接,您的服务器也会崩溃,在他们中间或后端不断的反复连接。
解决方案:给进入 eth0 的包打包 mark 的标记,当数据包是发给 VIP:80  并且 MAC 不其它 LVS 服务器的话. 才做个 mark ,这样才会对指定的 fwmark 进行 loadbalance 放入到 LVS 中处理。只要数据包是从任意其它的 MAC 地址(非 LVS 的转发)会被发往 VIP:port, 会不在进行 loadbalanced 而是直接转给后面监听的  demon 程序进行应用的处理。实际就是我们使用 iptables 来对进入的流量设置 MARK.然后配置 keepalived 只处理有 MARK 过的流量。不在使用以前绑定 VIP 和端口。
iptables 的配置如下:
同时服务于 LVS-DR,又要做为数据库的后端。所以我们要注意,只接收一个 director 的数据包。
这时我们在 Director1 中设置($MAC_Director2 是指我在  Director1 上所能见到从  Director2 发过来包的 MAC 地址) :
iptables -t mangle -I PREROUTING -d $VIP -p tcp -m tcp --dport $VPORT -m mac  ! --mac-source $MAC_Director2 -j MARK --set-mark 0x3
并在备份的 keepalived 的服务器 Director2 中设置:
iptables -t mangle -I PREROUTING -d $VIP -p tcp -m tcp --dport $VPORT -m mac  ! --mac-source $MAC_Director1 -j MARK --set-mark 0x4
 接着在 keepalived 中分别配置这二个。
Director1: virtual_server fwmark 3 {
Director2: virtual_server fwmark 4 {
其实这个的完整配置象如下:
keepalived 来根据 MARK 来配置的方法