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。
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,用不同的端口发送给百度,收到返回的数据包后,再按照自己记录的转换表,把网络包发送回给对应的主机。
D-NAT目标地址转换
将上面的S-NAT进行反转,客户端发来的请求到负载均衡服务器,负载均衡服务器将请求分发到后面的服务器上,服务器将响应返回给负载均衡服务器,最后由负载均衡器返回给客户端。
可以用下图这种方式实现负载均衡:
上图中,负载均衡服务器中同样需要维护一张转换表,记录某个端口的请求转发给哪些服务器,当然这个转发过程中还会涉及到负载均衡的算法,后面会介绍。
既然要查看端口,必然要将数据包解析到第四层网络层,所以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,所以可以直接向客户端返回数据包,而不需要走负载均衡服务器了。
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
直接返回给客户端。
我们以往用到的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,对外提供服务。
部署图如下:
具体部署步骤如下:
- 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.11
,http://192.168.252.12
。
注意虚拟机需要关闭防火墙才能访问systemctl stop firewalld
。
- 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地址。
- node02、node03分别配置VIP
ifconfig 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
。
- 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:删除。