LVS那些你不知道的秘密


【编者的话】这篇文章我们主要把思想讲清楚,具体的LVS的搭建流程,我们在后面的文章中会讲。

LVS简介

什么是LVS?

LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。目前LVS已经被集成到Linux内核模块中。

LVS能做什么?

LVS主要用于多服务器的负载均衡。
  • 它工作在网络层,可以实现高性能,高可用的服务器集群技术。
  • 它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。
  • 它易用,配置非常简单,且有多种负载均衡的方法。
  • 它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。
  • 可扩展性也非常好。
  • 性能几乎可以和F5相媲美(个人意见)。


LVS的负载均衡结构图

LVS的负载均衡结构图,大概的使用场景是这样的,关于高可用的地方,我们后面会进行介绍,别着急哦!
01.png

LVS的核心组件和专业术语

核心组件

LVS的管理工具和内核模块 Ipvsadm/IPVS:
  • Ipvsadm:用于空间的命令行工具,用于管理集群服务及集群服务上的RS等
  • IPVS:工作于内核上的程序,可根据用户定义的集群实现请求转发


专业术语

  • VS:Virtual Server,虚拟服务
  • Director:负载均衡器,图1的LVS调度器
  • Balancer:分发器,图1的LVS调度器
  • RS:Real Server,后端请求处理服务器,图1的Web服务
  • CIP:Client IP,客户端IP
  • VIP:Director Virtural IP,负载均衡虚拟IP,应该出现在图1的LVS调度器上
  • DIP:Director IP负载均衡器IP
  • RIP:Real Server IP,后端请求处理服务器IP


LVS的常用几种模式

LVS的DR模式(最常用)

LVS的DR模式最最稳定,是使用最多的一种模式。

什么是ARP广播?

在了解LVS的DR模式之前,我们需要先了解一下ARP广播,要不然我在讲后面内容的时候会用到这个,已经是大佬的同学跳过吧,小白请认真读完。

ARP广播:根据IP地址找MAC地址。

主机A的IP地址为192.168.1.1,MAC地址为0A-11-22-33-44-01;

主机B的IP地址为192.168.1.2,MAC地址为0A-11-22-33-44-02;

当主机A要与主机B通信时:

第1步:根据主机A上的路由表内容,IP确定用于访问主机B的转发IP地址是192.168.1.2。然后A主机在自己的本地ARP缓存中检查主机B的匹配MAC地址。

第2步:如果主机A在ARP缓存中没有找到映射,它将询问192.168.1.2的硬件地址,从而将ARP请求帧广播到本地网络上的所有主机。源主机A的IP地址和MAC地址都包括在ARP请求中。本地网络上的每台主机都接收到ARP请求并且检查是否与自己的IP地址匹配。如果主机发现请求的IP地址与自己的IP地址不匹配,它将丢弃ARP请求。

第3步:主机B确定ARP请求中的IP地址与自己的IP地址匹配,则将主机A的IP地址和MAC地址映射添加到本地ARP缓存中。

第4步:主机B将包含其MAC地址的ARP回复消息直接发送回主机A。

第5步:当主机A收到从主机B发来的ARP回复消息时,会用主机B的IP和MAC地址映射更新ARP缓存。本机缓存是有生存期的,生存期结束后,将再次重复上面的过程。主机B的MAC地址一旦确定,主机A就能向主机B发送IP通信了。

LVS的DR模式的请求流程图

申明:首先我们先来申明一下, 举个例子:我们在请求一个域名如:https://www.naixuejiaoyu.com/, 我们首先会访问的是DNS,DNS会根据我们的域名给我们解析VIP地址(一般情况是一个VIP,也有一种情况是一个域名对应对个VIP或者IP),我们为了简单,下图就是画的一般情况。

注意:前提是我们的VIP地址都是配置在LO上的。
02.png

提问一:三个VIP,为什么DNS会把请求打到LVS上,而没有打到RS上呢?

带着这个问题我们来思考,可能才更好的帮助我们来理解LVS的DR模式,要解决这个问题,我们就需要提到我们刚开始提到的ARP请求了,我们需要在LVS,RS1,RS2上都需要绑定三个VIP,但是需要在RS1和RS2上需要额外的做一些工作,那就是禁止ARP请求。

我们在RS上需要执行以下的操作,更改Linux的内核参数,如下:
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

为了帮助大家更好的理解三个VIP之间的关系,我们举个例子来说:LVS服务器是正常的,当DNS在请求的时候会解析出来VIP的地址,但是并不知道,具体的MAC地址是哪一个,那LVS服务器会通过ARP请求,告知别人自己的MAC地址,别人就缓存下来了,反之,我们的RS是禁止ARP请求的,其实他就是一个哑巴,让他不能说话的,别人就不知道他的MAC地址,即使他有VIP地址,所以DNS只会把请求转发到LVS上,而不能转发到RS上。

既然RS禁止了ARP请求,那LVS如何把请求转发给RS呢?

解决了上面的问题,那新的问题又来了,既然我们说RS禁止了ARP请求,那LVS是如何把请求转发给RS的呢?其实我告诉你,是通过修改MAC地址,进行转发的,这个是DR模式的核心,那LVS又是如何知道RS的MAC地址呢,其实是通过ARP请求获知的,那有些人就会问我,你这个不是自相矛盾吗?别担心,接着看。

首先我们看一下,我们的VIP都是绑定在lo上的,我们要理解上面我提出的这个问题,就要深入的了解一下Linux内核参数的配置信息了。

有关arp_ignore的相关介绍:


arp_ignore - INTEGER Define different modes for sending replies in response to received ARP requests that resolve local target IP addresses:
0 - (default): reply for any local target IP address, configured on any interface
1 - reply only if the target IP address is local address configured on the incoming interface
2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface
3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied
4-7 - reserved
8 - do not reply for all local addresses

The max value from conf/{all,interface}/arp_ignore is used when ARP request is received on the {interface}
看不懂没关系,既然要解决,我们肯定是要深入剖析的,下面我们来简单的翻译一下:

arp_ignore:定义对目标地址为本地IP的ARP询问不同的应答模式

0 - (默认值):回应任何网络接口上对任何本地IP地址的ARP查询请求

1 - 只回答目标IP地址是来访网络接口本地地址的ARP查询请求

2 -只回答目标IP地址是来访网络接口本地地址的ARP查询请求,且来访IP必须在该网络接口的子网段内

3 - 不回应该网络界面的ARP请求,而只对设置的唯一和连接地址做出回应

4-7 - 保留未使用

8 -不回应所有(本地地址)的ARP查询

好了我们设置的arp_ignore内核参数是1,就是只回答目标IP地址是来访网络接口本地地址的ARP查询请求,即:只回答本地网卡eth0上的ARP请求。

我们就拿上面的图举例:

  • LVS服务器:
    • DIP:绑定的网卡eth0:192.168.1.110
    • VIP:绑定的网卡是lo:0:192.168.147.150

  • RS服务器:
    • RIP:绑定的网卡是eth0:192.168.1.111
    • VIP:绑定的网卡lo:0:192.168.147.150


其实客户端在发送ARP请求的时候,询问的是VIP的MAC地址,LVS服务器进行了正确的ARP请求回应,而当循环RS服务器的MAC地址的时候,这个时候,我们网卡的IP地址是:192.168.1.111/112,RS是做过阉割的,所以不给与回应。

当LVS服务器发起ARP请求的时候,循环192.168.1.111或者192.168.1.112的MAC地址,这个时候,RS本地的网卡地址,就是LVS需要访问的IP地址,就进行ARP请求的回应,所有LVS服务器就缓存了RS服务器的MAC地址。

上面的问题是不是都迎刃而解了,快来给我疯狂打call吧!

RS是如何做到,直接返回给客户端的呢?

这个问题太好,我们一般接收的请求,应该都是哪里来,哪里回,那RS是如何做到直接返回个客户端的呢?

好的,既然我们前面提到了在RS上进行设计Linux内核参数的更改,分别是arp_ignore和arp_announce两个内核参数,既然arp_ignore是禁止ARP请求的,我们上面已经介绍过了,arp_announce内核参数是做什么的呢?我们下面就来讲解一下这个参数的作用吧。

既然存在,那就是有意义的,arp_announce这个内核参数,其实就是让RS可直接返回给客户端。

有关arp_announce的相关介绍:


arp_announce - INTEGER Define different restriction levels for announcing the local source IP address from IP packets in ARP requests sent on interface: 0 - (default) Use any local address, configured on any interface 1 - Try to avoid local addresses that are not in the target's subnet for this interface. This mode is useful when target hosts reachable via this interface require the source IP address in ARP requests to be part of their logical network configured on the receiving interface. When we generate the request we will check all our subnets that include the target IP and will preserve the source address if it is from such subnet. If there is no such subnet we select source address according to the rules for level 2.
2 - Always use the best local address for this target. In this mode we ignore the source address in the IP packet and try to select local address that we prefer for talks with the target host. Such local address is selected by looking for primary IP addresses on all our subnets on the outgoing interface that include the target IP address. If no suitable local address is found we select the first local address we have on the outgoing interface or on all other interfaces, with the hope we will receive reply for our request and even sometimes no matter the source IP address we announce.

The max value from conf/{all,interface}/arp_announce is used.

Increasing the restriction level gives more chance for receiving answer from the resolved target while decreasing the level announces more valid sender's information.
arp_announce:对网络接口上,本地IP地址的发出的,ARP回应,作出相应级别的限制,确定不同程度的限制,宣布对来自本地源IP地址发出ARP请求的接口。

0 - (默认)在任意网络接口(eth0,eth1,lo)上的任何本地地址

1 - 尽量避免不在该网络接口子网段的本地地址做出ARP回应。当发起ARP请求的源IP地址是被设置应该经由路由达到此网络接口的时候很有用,此时会检查来访IP是否为所有接口上的子网段内IP之一,如果该来访IP不属于各个网络接口上的子网段内,那么将采用级别2的方式来进行处理。

2 - 对查询目标使用最适当的本地地址,在此模式下将忽略这个IP数据包的源地址并尝试选择与能与该地址通信的本地地址。首要是选择所有的网络接口的子网中外出访问子网中包含该目标IP地址的本地地址,如果没有合适的地址被发现,将选择当前的发送网络接口或其他的有可能接受到该ARP回应的网络接口来进行发送。

其实我们RS可以直接返回给客户端,就是arp_announce设置为2起到的作用,他会自主的选择一个地址,即VIP地址,返回给我们的客户端,其实就是利用了一个欺骗的技术,让客户端不会把我们返回的请求丢弃掉,让他以为RS返回的请求是正常的。

LVS的DR模式请求IP地址追踪

Client在发起请求之前,会发一个ARP广播的包,在网络中找“谁是VIP”,由于所有的服务器,LVS和RES都有VIP,为了让Client的请求送到LVS上,所以必须让RS不能响应Client发出的ARP请求,(这也是为什么要禁止RES上ARP的请求和响应)下面就是LVS转发的事情了:

Client向目标VIP发送请求,LVS接收;此时IP包和数据信息如下:
src mac ---->       a1:b2:c3:d4:e5:f6(Client的MAC地址(我假设的))

dst mac ----> 1a:2b:3c:4d:5e:6f(LVS的MAC地址(我假设的))

src_ip ---->   192.168.147.1

dst_ip ----> 192.168.147.150

LVS根据负载均衡的算法,选择一台RS,然后把RS1的MAC地址作为目的MAC地址,发送到局域网中。
src mac ---->       1a:2b:3c:4d:5e:6f(LVS的MAC地址(我假设的))

dst mac ----> 11:22:33:44:55:66(RS1的MAC地址(我假设的))

src_ip ---->   192.168.147.1

dst_ip ----> 192.168.147.150

是的,你没有看错,src_ip地址和dst_ip是不发生变化的,我们前面说到,DR模式是通过修改MAC地址进行转发的,IP地址的请求是不发生变化的,这个和后面的NAT模式有很大的区别。

RS1在局域网中收到这个请求以后,发现目的IP和本地匹配,于是进行处理,处理完成以后,直接把源IP和目的IP直接对调,然后经过网关直接返回给用户。
src mac ---->       11:22:33:44:55:66(RS1的MAC地址(我假设的))

dst mac ----> a1:b2:c3:d4:e5:f6(Client的MAC地址(我假设的))

src_ip ---->   192.168.147.150

dst_ip ----> 192.168.147.1

在RS上,是可以直接返回给客户端的。

LVS的NAT模式

LVS的NAT模式,类似于iptables的DNAT,但是支持多目标的转发。

注意:自己在本机做实验的时候,客户端不能和RS在同一网段,不然直接响应,不走网关。

优点
  • 配置简单,通用性强
  • 支持映射(NAT映射表)
  • RIP可以是私网IP,用于LVS与RS之间通讯


缺点
  • LVS和RS必须在一个VLAN中(RS将LVS配置为网关,如果不在一个子网回包会经过路由器网关直接路由走,LVS没机会修改数据包)
  • 进出流量都需要LVS进行处理,LVS容易成为集群瓶颈
  • 需要将LVS配置为RS的网关


LVS的NAT模式的请求流程图
03.png

LVS的NAT模式请求流程图
  1. 客户端发起请求到LVS机器上。
  2. LVS服务器根据LVS的算法,转发给RS服务器(改变目的IP为RS1或者RS2),并记录连接信息,只改变目的IP,源IP不变。
  3. RS收到request请求包之后,发现目的IP是自己的IP处理请求,然后走网关,经过LVS,RS设置的官网为LVS的eth0。
  4. LVS收到reply包后,修改reply包的源IP地址为VIP,发给客户端。
  5. 客户端接收到请求,校验IP请求的包是否符合要求,符合则接收,不符合就丢弃。


抓包分析包请求流程

1、客户端发起请求:
source     192.168.147.1
dest   192.168.147.150:80

在LVS服务器上,eth0网卡抓取的包如下:
04.png

2、LVS处理请求:

在LVS服务器上抓包,在eth0网卡抓包。
source192.168.147.1:59334
dst192.168.1.112/111:80

05.png

3、LVS的eth0作为RS的网关地址,需要经过LVS周转。
source             192.168.1.112              
dst    192.168.147.1

4、返回客户端

包经过eth0返回VIP服务器,然后经过VIP返回给客户端,源IP改成VIP,目的IP不变。
source192.168.147.150          
dst       192.168.147.1

06.jpeg

LVS的TUN模式(隧道模式)不常用

什么IP隧道技术?

简单来说IP隧道技术就是将 【IP数据包】 的上面再封装一层【IP数据包】, 然后路由器根据最外层的IP地址路由到目的地服务器,目的地服务器拆掉最外层的IP数据包,拿到里面的IP数据包进行处理。
07.png

原理

用户请求负载均衡服务器,当IP数据包到达负载均衡服务器后,根据算法选择一台真实的服务器,然后通过IP隧道技术将数据包原封不动再次封装,并发送给真实服务器,当这个数据包到达真实服务器以后,真实服务器进行拆包(拆掉第一层的IP包)拿到里面的IP数据包进行处理,然后将结果直接返回给客户端。

Tunnel原理流程图
08.png

LVS的FullNat模式

FullNat模式听名字也是NAT模式的一种,那Full是什么意思呢?就是全部的NAT模式,NAT模式中,我们是需要设置RS的网关地址为LVS的内网服务器地址,那FullNat模式,就是我们最通常容易理解的类型,我们通过下面的图来了解吧,主要是就包的请求地址改变有不同。

NAT模式:
09.png

FullNat:
10.png

LVS负载均衡调度算法

根据前面的介绍,我们了解了LVS的三种工作模式,但不管实际环境中采用的是哪种模式,调度算法进行调度的策略与算法都是LVS的核心技术,LVS在内核中主要实现了一下十种调度算法。

1. 轮询调度

轮询调度(Round Robin,简称'RR')算法就是按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点就是实现简单。轮询算法假设所有的服务器处理请求的能力都一样的,调度器会将所有的请求平均分配给每个真实服务器。

2. 加权轮询调度

加权轮询(Weight Round Robin,简称'WRR')算法主要是对轮询算法的一种优化与补充,LVS会考虑每台服务器的性能,并给每台服务器添加一个权值,如果服务器A的权值为1,服务器B的权值为2,则调度器调度到服务器B的请求会是服务器A的两倍。权值越高的服务器,处理的请求越多。

3. 最小连接调度

最小连接调度(Least Connections,简称'LC')算法是把新的连接请求分配到当前连接数最小的服务器。最小连接调度是一种动态的调度算法,它通过服务器当前活跃的连接数来估计服务器的情况。调度器需要记录各个服务器已建立连接的数目,当一个请求被调度到某台服务器,其连接数加1;当连接中断或者超时,其连接数减1。(集群系统的真实服务器具有相近的系统性能,采用最小连接调度算法可以比较好地均衡负载。)

4. 加权最小连接调度

加权最少连接(Weight Least Connections,简称'WLC')算法是最小连接调度的超集,各个服务器相应的权值表示其处理性能。服务器的缺省权值为1,系统管理员可以动态地设置服务器的权值。加权最小连接调度在调度新连接时尽可能使服务器的已建立连接数和其权值成比例。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。

5. 基于局部的最少连接

基于局部的最少连接调度(Locality-Based Least Connections,简称'LBLC')算法是针对请求报文的目标IP地址的 负载均衡调度,目前主要用于Cache集群系统,因为在Cache集群客户请求报文的目标IP地址是变化的。这里假设任何后端服务器都可以处理任一请求,算法的设计目标是在服务器的负载基本平衡情况下,将相同目标IP地址的请求调度到同一台服务器,来提高各台服务器的访问局部性和Cache命中率,从而提升整个集群系统的处理能力。LBLC调度算法先根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则使用'最少连接'的原则选出一个可用的服务器,将请求发送到服务器。

6. 带复制的基于局部性的最少连接

带复制的基于局部性的最少连接(Locality-Based Least Connections with Replication,简称'LBLCR')算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统,它与LBLC算法不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。按'最小连接'原则从该服务器组中选出一一台服务器,若服务器没有超载,将请求发送到该服务器;若服务器超载,则按'最小连接'原则从整个集群中选出一台服务器,将该服务器加入到这个服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。

7. 目标地址散列调度

目标地址散列调度(Destination Hashing,简称'DH')算法先根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且并未超载,将请求发送到该服务器,否则返回空。

8. 源地址散列调度U

源地址散列调度(Source Hashing,简称'SH')算法先根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且并未超载,将请求发送到该服务器,否则返回空。它采用的散列函数与目标地址散列调度算法的相同,它的算法流程与目标地址散列调度算法的基本相似。

9. 最短的期望的延迟

最短的期望的延迟调度(Shortest Expected Delay,简称'SED')算法基于WLC算法。举个例子吧,ABC三台服务器的权重分别为1、2、3 。那么如果使用WLC算法的话一个新请求进入时它可能会分给ABC中的任意一个。使用SED算法后会进行一个运算

A:(1+1)/1=2,B:(1+2)/2=3/2,C:(1+3)/3=4/3,就把请求交给得出运算结果最小的服务器。

10. 最少队列调度

最少队列调度(Never Queue,简称'NQ')算法,无需队列。如果有realserver的连接数等于0就直接分配过去,不需要在进行SED运算。

作者:凌晶,生活中的段子手,目前就职于一家地产公司做DevOps相关工作,曾在大型互联网公司做高级运维工程师,熟悉Linux运维,Python运维开发,Java开发,DevOps常用开发组件等,个人公众号:stromling。

原文链接:https://mp.weixin.qq.com/s/VZh0_BOrPhOnEAHRjen-bQ

0 个评论

要回复文章请先登录注册