LVS三种负载均衡方式

LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器。这是一个由章文嵩博士发起的一个开源项目,它的官方网站是http://www.linuxvirtualserver.org/.现在LVS已经是Linux内核标准的一部分。

使用LVS可以达到的技术目标是:通过LVS达到的负载均衡技术和Linux操作系统实现一个高性能高可用的Linux服务器群集,它具有良好的可靠性,可拓展性和可操作性,从而以低廉的成本实现最优的性能。

为什么Tomcat承受的并发少?因为Tomcat是工作在OSI参考模型的第7层,也就是应用层的软件,是整个网络通信过程中最末端的层次。而且Tomcat是Java开发的,它跑在JVM上,还要进行用户态内核态的切换,这样就更慢了。

现在我们从通信的角度考虑,如果有一个负载均衡服务器设备,可以实现根本不需要和客户端进行三次握手,收到数据包就直接转发出去,这样性能就会大大的提高,这就是一种数据包级别的四层负载均衡技术。

我们得到下面这样的拓扑模型,可以解决负载均衡的问题。

首先我们统一一下命名:

  • CIP:客户端的client IP地址。
  • VIP:负载均衡服务器对外的虚拟virtual IP。
  • DIP:用于分发的dispacher IP。
  • RIP:真实服务器的real IP。

LVS三种负载均衡方式NAT、DR、NAT_lvs

NAT网路地址转换

NAT:Network Address Translation,网络地址转换协议。

S-NAT源地址转换

假设你和你女朋友在家都要访问百度,你的IP:port是192.168.1.8:12121,你女朋友的IP:port是192.168.1.6:12121,如果不进行地址转换的话,你的数据包都不会出现在公网上,因为私有地址不会出现在互联网上,所有的路由器都会直接丢弃。

为了能让数据包发送出去,只需要把源IP地址为192.168.1.0网段的ip替换为路由器对应的外网IP地址6.6.6.6即可。

只改IP又会带来新的问题,百度返回报文中IP:port为6.6.6.6:12121,那么这个报文又对应内网的哪个主机呢?

为了解决这个问题,路由器自己需要维护一张转换表,生成一个自己的端口对应内网的一个IP:port,例如6.6.6.6:123对应192.168.1.8:12121,6.6.6.6::321对应192.168.1.6:12121,用不同的端口发送给百度,收到返回的数据包后,再按照自己记录的转换表,把网络包发送回给对应的主机。

LVS三种负载均衡方式NAT、DR、NAT_lvs_02

D-NAT目标地址转换

将上面的S-NAT进行反转,客户端发来的请求到负载均衡服务器,负载均衡服务器将请求分发到后面的服务器上,服务器将响应返回给负载均衡服务器,最后由负载均衡器返回给客户端。

可以用下图这种方式实现负载均衡:

LVS三种负载均衡方式NAT、DR、NAT_ipvsadm_03

上图中,负载均衡服务器中同样需要维护一张转换表,记录某个端口的请求转发给哪些服务器,当然这个转发过程中还会涉及到负载均衡的算法,后面会介绍。

既然要查看端口,必然要将数据包解析到第四层网络层,所以LVS是基于第四层的负载均衡器,但是只是在网络层偷窥一下端口号,而不是真正的建立连接。

负载均衡服务器想要将数据分发给Real Server,只需要将目标IP地址替换为具体提供服务的服务器IP即可。

而数据包想要正确的返回给客户的,首先需要配置Real Server的默认网关为负载均衡服务器,这样数据包就能到达负载均衡服务器,然后由负载均衡服务器将源IP地址替换为VIP,最后返回给客户端。

弊端:

  • 非对称:客户端给服务端发送的请求数据量是很小的,但是服务端给客户端返回的数据量很大。下行的数据使服务器带宽成为瓶颈。早期的ADSL可以达到6M的全速单一方向,如果平分的话,上下行都是3M。所以运营商做了手脚进行了调整,将下行的带宽调的很大,将上传的带宽调的比较小。
  • 消耗算力,返回给客户端的数据都要经过负载均衡服务器器。

怎么解决上述弊端?如果能够让Real Server返回的数据不经过负载均衡服务器,而是直接返回给客户端就好了,这就引出下面的模式-DR。

DR直接路由模式

于是我们想啊,如果有这么一种技术:每一个Real Server都能够配一个VIP,但是由于IP不能重复,所以这个VIP必须对外隐藏,只对内可见(其实是对ARP协议进行配置)。所有的Real Server共同在负载均衡服务器上对外暴露同一个VIP,别人请求只能请求到这台负载均衡服务器上来,负载均衡服务器在转发数据包的时候,只需要将封装的目标mac地址修改为Real Server的mac地址,这样数据就能从客户端到达Real Server,由于Real Server本身有VIP,所以可以直接向客户端返回数据包,而不需要走负载均衡服务器了。

LVS三种负载均衡方式NAT、DR、NAT_dr_04

mac地址是点到点的,代表的是一跳的距离,要保证负载均衡服务器与你的Real Server在同一个局域网中,不能让下一跳跳到别的网络去。这种修改mac地址的模式是基于2层链路层的,没有修改3层网络层,缺点是不能跨网络。

优势:速度快,成本低。

TUN隧道模式

假设我们有好多好多的Real Server,现在这些Real Server和负载均衡服务器不在同一个机房了,怎么解决这个问题?使用隧道技术。

CIP->VIP外面包裹一层DIP->RIP地址,这样数据包就可以顺利的从负载均衡服务器被发送到Real Server,Real Server收到这个数据包之后,把外层的DIP->RIP撕掉,就能看到真正的CIP->VIP,自己处理之后,根据CIP->VIP直接返回给客户端。

LVS三种负载均衡方式NAT、DR、NAT_ipvsadm_05

我们以往用到的PPPOE协议、VPN、翻墙就是这种技术。

DR模式实验

服务器IP及部署角色如下:

  • node01:192.168.252.10,负载均衡器。
  • node02:192.168.252.11,Real Server,上面部署httpd,对外提供服务。
  • node03:192.168.252.12,Real Server,上面部署httpd,对外提供服务。

部署图如下:

LVS三种负载均衡方式NAT、DR、NAT_nat_06

具体部署步骤如下:

  1. node02、node03分别安装httpd,并在浏览器测试能正常访问页面。

安装:yum install -y httpd

启动http:systemctl start httpd

编辑首页,正常情况下,两个节点配置的页面应该一样,这里为了能看到效果才配置页面内容不一致:

// node02
# echo node02 > /var/www/html/index.html

// node03
# echo node03 > /var/www/html/index.html

浏览器分别访问:http://192.168.252.11http://192.168.252.12

注意虚拟机需要关闭防火墙才能访问systemctl stop firewalld

  1. node02、node03分别修改ARP协议,使得后面配置的VIP能够实现对外隐藏,只对内可见,这一步一定要在配置VIP之前,否则VIP就暴露出去了。

node02、node03分别执行如下命令:

# echo 1 > /proc/sys/net/ipv4/conf/ens32/arp_ignore
# echo 2 > /proc/sys/net/ipv4/conf/ens32/arp_announce
# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

arp_ignore参数表示接收到ARP请求时的响应级别,其取值如下:

  • 0:响应任意网卡上接收到的对本机IP地址的arp请求(包括环回网卡上的地址),而不管该目的IP是否在接收网卡上。
  • 1:只响应目的IP地址为接收网卡上的本地地址的arp请求。
  • 2:只响应目的IP地址为接收网卡上的本地地址的arp请求,并且arp请求的源IP必须和接收网卡同网段。

arp_announce参数表示将自己地址向外通告时的通告级别,其取值如下:

  • 0:允许使用任意网卡上的IP地址作为arp请求的源IP,通常就是使用数据包a的源IP。
  • 1:尽量避免使用不属于该发送网卡子网的本地地址作为发送arp请求的源IP地址。
  • 2:忽略IP数据包的源IP地址,选择该发送网卡上最合适的本地地址作为arp请求的源IP地址。
  1. node02、node03分别配置VIPifconfig lo:1 192.168.252.100 netmask 255.255.255.255

注意这里的子网掩码是4个255,不是3个255,配置成3个255,虚拟机都会连接不上了,因为192.168.252.0网段的数据都会优先发送到lo:1这个网卡上,会造成死循环,数据无法返回。lo这个网卡是内核虚拟出来的,距离内核最近,所以会数据优先会发送到lo上。这样配置的另一个原因是因为这里的VIP要对外隐藏,对内可见,根本就不会有数据直接发送到这个lo:1网卡上,配置一个VIP只是为了能让计算机接收目标IP为192.168.252.100的数据而已,数据发送出去还是会走真实的网卡ens32

  1. node01上安装ipvsadm,yum install -y ipvsadm

lvs已经被内核内置了,无需安装,这里需要安装的是ipvsadm,用来管理lvs,相当于lvs的一个客户端。

配置路由:

# ipvsadm -A -t 192.168.252.100:80 -s rr
# ipvsadm -a -t 192.168.252.100:80 -r 192.168.252.11
# ipvsadm -a -t 192.168.252.100:80 -r 192.168.252.12

到这里,lvs的DR模式已经配置完成,可以去客户端的浏览器访问http://192.168.252.100,可以观测到结果了。

查看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.252.100:80 rr
  -> 192.168.252.11:80            Route   1      0          0         
  -> 192.168.252.12:80            Route   1      0          0

负载均衡调度方法

四种静态调度方法:

  • RR:轮询调度(Round-Robin Scheduling)。
  • WRR:加权轮询调度(Weighted Round-Robin Scheduling)。
  • DH:目标地址散列调度(Destination Hashing Scheduling)。
  • SH:源地址散列调度(Source Hashing Scheduling)。

动态调度方法:

  • LC:最小连接调度(Least-Connection Scheduling)。
  • WLC:加权最小连接调度(Weighted Least-Connection Scheduling)。
  • LBLC: 基于局部性的最少链接(Locality-Based Least Connections Scheduling)。
  • LBLCR:带复制的基于局部性最少链接(Locality-Based Least Connections with Replication Scheduling)
  • SED: 最短期望延迟(Shortest Expected Delay)。
  • NQ: 最少队列调度(Never Queue)。

疑问:lvs是一个基于四层的负载均衡器,没有与客户端建立连接,而动态调度算法中都需要统计连接数,那么它是怎么统计的呢?答案还是偷窥,在网络层中偷窥到三次握手中的SYN_RECV包,那么连接数就加1,偷窥到FIN_WAIT包,那么连接数就减1,这点在lvs的连接记录中可以看到:

# ipvsadm -lnc
IPVS connection entries
pro expire state       source             virtual            destination
TCP 00:07  FIN_WAIT    192.168.252.1:9276 192.168.252.100:80 192.168.252.12:80

由于时间较短,正常情况下看不到SYN_RECV的记录,一旦看到了那么三次握手就卡住了,后边网络层可能出现了问题。

ipvsadm的使用

管理集群服务:ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine] [-b sched-flags]

  • -A:添加。
  • -t:TCP协议的集群。
  • -u:UDP协议的集群。
  • -f:防火墙标记。
  • service-address:IP:PORT。
  • -s:负载均衡的算法,后面会介绍。
  • -E:修改。
  • -D:删除。
  • -C:清空ipvs规则,删除所有集群服务。
  • -S:保存规则,例子:ipvsadm -S > /path/to/somefile
  • -R:载入此前的规则,例子:ipvsadm -R < /path/form/somefile

管理集群服务中的Real Server:ipvsadm -a|e -t|u|f service-address -r server-address [options]

  • -a:添加。
  • -t|u|f:与上面管理集群服务配置的含义一致。
  • service-address:IP:PORT。
  • -r:Real Server的IP。
  • [-g|i|m]: LVS的工作模式,-g: DR,-i: TUN,-m: NAT。
  • [-w weight]:定义服务器权重
  • -e:修改。
  • -d:删除。