ABC of IPVS | IPVS负载均衡基础
这篇博客需要你理解网络的基本结构,并且对比较底层的网络协议有一些理解。没有学过也没有关系,下面会一点点提出来
Why we need LVS | 我们为什么需要一个LVS
Long long ago
从前网站都很简单,一个页面一个html文件,最多加上一些简单的javascript,就足够了。
随着网络的发展,业务的多样化,各个网站的规模扩大,一个个的静态页面远不能满足网站的需求,一个web服务也复杂到需要把各个部分拆分开,单个服务器也不足以支撑所有的业务。
所以后来我们有了动态页面,有了处理动态页面的语言、服务器,我们把网站的逻辑、缓存、存储、网络拆分成很多不同的软件服务,我们把这些服务都放在不同的服务器上。最后我们一个服务器跑一个很小的服务也不够用了,怎么办?
我们希望在多台机器上跑一样的服务,然后把不同次的请求发送到不同的服务器上,以此分担一个服务器上的负载。
负载均衡器
于是我们有了负载均衡器。负载均衡器就是相对的前端服务器,处理请求的就是相对的后端服务器。
负载均衡器一般来说会按照OSI模型,来区分负载均衡器的类型。比如说4层负载均衡,就是TCP这一层,以连接为单位把请求发到不同的后端服务器上,或者说7层,就是解析某种应用层的协议以后,按照一定规则分发到不同层的后端服务器上。
七层最典型的就是web服务,负载均衡器需要解析http请求,得到host(比如说blog.jeffthecoder.xyz)和path(比如说/lvs/或者/assets/built/screen.css?v=c8cb5445f7)以后,按照不同的规则,把请求分发到不同的服务器上。当然我们也有其他协议的负载均衡器,比如说MariaDB的mysql-proxy。
我们平时常用的主要是七层的负载均衡器,尤其是web服务,一般的Web服务器都有负载均衡器的能力,不论是微软的IIS,还是开源的Apache2和Nginx。当然我们也有haproxy这种专注于代理和负载均衡的软件。
oooooops,负载均衡器的负载满了
上面提到的负载均衡器,都是在受到请求后,再主动发送一个请求,自己做这两个请求之间的传话人。所以在有负载的情况下会产生很高的网络负载。而七层代理甚至还需要解密SSL请求、解析http请求、解压Gzip正文,还会产生很高的运算和io负载。所以负载均衡器本身就变成一个负载很高的应用了。更别提很多负载均衡器还可以跑脚本,比如说haproxy和nginx。这类负载均衡器适合在逻辑复杂、负载有限的情况下运作。
有个办法是我们在负载均衡器的前端再加一层负载均衡器。但是如果加的还是应用层负载均衡器,就会有很多数据包和请求被重复的解析,导致大量的计算资源被浪费。即使是加一个4层代理,网络负载也还是很重。
lvs
LVS是内置于内核的一个三层/四层负载均衡器。有两部分实现,一部分是三层负载均衡,叫ipvs,一部分是4/7层负载均衡,叫ktcpvs,这部分已经很久不更新,所以也很少被人提起了。我们现在用的也主要是ipvs。
ipvs有两种模式:NAT和DR。不管哪种模式我们都区分director(负载均衡的节点)和real server(处理请求的节点)。
nat就是用我们比较常见的nat的方式把请求传递过去。请求和回复的流量也都还是经过director转发出去,和其他四层代理区别只是ipvs是在内核里面的。
另一种DR模式就很有意思了。
LVS/DR
DR表示的是Direct Routing。那什么是LVS/DR。我们从网络协议开始说起吧。这些都是TCP/IP详解(卷一)里面会讲的东西。我的理解有可能会和书有出入,以书为准。
从ARP到TCP
一般来说请求从发出去到被接受经历这么几个阶段:
-
- 在不同子网间路由
-
- 在同一个子网内找主机
-
- 把数据包发给主机
-
- 主机接收数据包并解析
不同子网间路由路由不提了。不在lvs讨论的范围内。lvs考虑的主要是在一个子网内把请求负载均衡到不同的服务上。
我们稍微回忆一下我们学过的课本上,网络内不同的设备是怎么数据包送到主机上的。
网络通信全靠协议。初始状态下机器之间是不知道互相谁是谁的。我们从这里开始
ARP:谁是张全蛋
人和人通信靠名字,主机间通信我们也一般会用IP。没有多少人天天叫别人“那个脸上全是皱纹的女人”,或者也不会天天叫别人“娃娃脸”。
但是人和人之间名字只是个可以改变的代号,最终我们还是希望我们和特定的一个人沟通。计算机也是希望和某个不会变的MAC地址通信
但是我们很多时候到新环境,第一次按照名册叫别人张全蛋的时候,我们是不知道谁是张全蛋的。那我们要怎么办呢?
吼一嗓子。
我们完全可以在一个教室里面吼一嗓子:“谁是张全蛋!”然后我们以后记住这个人的特征,就知道了张全蛋是谁。
网络主机间也是这样的。主机在第一次向一个IP发送IP数据包前,会先向子网内广播ARP请求,询问:“谁有xxx IP,请告诉有aaa MAC地址的yyy IP“。等有主机回复了说“回复MAC地址为aaa的yyy主机,xxx IP在bbb MAC上”,主机就会记住,xxx在bbb上,以后再要给xxxIP发数据包,就会直接注明:“to dear bbb,这里有一个数据包发给xxx”
ethernet到TCP:把快递可靠有序地送到张全蛋家
这部分感觉没啥可说的。
ethernet和IP的关系类似于房子和住户,ethernet一般不变,IP可以换。每次接收数据实际上我们都会先检查MAC地址(ethernet),收件地址不是我这里就直接忽略,然后检查IP地址(IP),住在这里的不是这个IP也会忽略。
最后TCP区分了不同的端口不同的应用,同时保证了数据包到达的可靠性和顺序。
LVS/DR:我只是把数据包传出去
之前说前面的所有负载均衡器都是自己中转所有流量,所以网络IO的负载会比较重。
换句话说,这些代理差不多就是一个快递中转站:
- 先把快递寄给中转站
- 4层代理就是把快递改一下收发件地址然后传递出去
- 7层代理则是先拆了快递、再打包装好然后按照快递里面的内容发出去
- 收到快递的人看到的发件地址都是中转站
- 收件人把回信发给中转站
- 中转站把回信发给发件人
你要顾及两头,所以很累。
而LVS/DR是这样:
- 别人问实验室(IP)是哪里
- 中转站回答实验室在中转站(中转站的MAC地址)。(需要实验室保持沉默)
- 然后别人会先把快递发到中转站
- 中转站拿到一个要寄给实验室的快递
- 中转站填上实验室其中一个真实的地址(实验室的MAC地址)
- 把快递发往真实的实验室地址
- 实验室直接把回信发给发件人
LVS/DR只是维持TCP请求的状态,给数据包填上真实的MAC地址然后再发出去,只中转请求的流量。这样就可以减轻许多网络负载。
这样就解决了负载均衡器负载过重的问题。