深入浅出 LVS 负载均衡系列(一):NAT、FULLNAT 模型原理
LVS(Linux Virtual Server)是一个虚拟服务器集群系统。工作在 OSI 模型的传输层,即四层负载均衡。LVS 本身实现了 NAT、DR、TUN 模型,这些模型仅做数据包的转发,而不会与客户端建立连接,成本低效率高。FULLNAT 基于 NAT 实现,LVS 本身不支持,需要额外对内核打补丁后才能使用。
本系列按照负载均衡器对数据包的处理方式分类,从计算机间通信的角度出发,浅谈 NAT、FULLNAT、DR、TUN 模型的实现原理。
两台计算机如何在互联网中通信
在了解 LVS 负载均衡之前,先要搞清楚两台计算机如何在互联网中通信。茫茫互联网中,两台计算机如何才能找到对方?
我们先来看看,快递是如何被快递小哥完美地送到你手上的。根据你填写的地址,快递先送到你所在的省市区,接着在当前省市区找到你的门牌号,最后根据门牌号和姓名,再亲手把快递交给你。
两台计算机在互联网中的通信也是如此。首先需要知道双方的 IP 地址,即省市区,其次需要知道双方的 MAC 地址,即门牌号。MAC 地址标志着唯一的计算机。在同一台计算机上,可能有多个不同的服务,如何能像快递小哥按照姓名找到你一样,在计算机上找到对应的服务呢?没错,就是按照端口号。
这样,通信中每台计算机需要提供的信息就很清晰了,即 IP 地址、MAC 地址、端口号。总结一下,计算机之间通信必需的六个要素就是,源 IP 地址、端口号、源 MAC 地址,目标 IP 地址、端口号、目标 MAC 地址。
假设计算机 A 和计算机 B 在上述的网络拓扑图(不在同一局域网)中。可以很清晰地看到 计算机 A 和 计算机 B 通信需要五个步骤,其中 ①② 和 ④⑤ 的原理相同。现在我们来看看具体的每个步骤在计算机的世界中是如何实现的。
首先 A 和 B 的 IP 地址和端口号是已知的,即一个数据包从哪来要发往哪去。所以现在的问题是:A 如何能知道 B 的 MAC 地址?
最简单的方式就是 A 保存网络中全部设备的 MAC 地址,在发送时查询一下,这样就能得到 B 的 MAC 地址。但是网络中的设备有几十亿个,还在不断地增长,显然这种方式是不可取的。如果按照快递发送过程中,在每个驿站之间进行转移,这样只需要知道该发往的下一目的地在哪里,最终也能将快递成功地交到你的手上。在实际网络中发送数据包也是这样,现在的目标就是确定 “下一个目的地” 的 MAC 地址。
步骤 ①②:发送数据包至网关
A 不知道 B 的 MAC 地址,且 A 和 B 也不在同一个局域网中。这时 A 会根据 ARP 协议先发出一个广播包,即目标 MAC 地址是 FF:FF:FF:FF:FF:FF 的数据包。当 交换机 1 收到这个广播包之后,会将这个数据包转发给其他端口,并且记录 A 的 MAC 地址和交换机端口之间的映射关系,后续再看到这个 MAC 地址,就知道该从哪个端口转发出去。当 路由器 1 收到广播包后,会将自己的 MAC 地址返回。A 接收到返回后,就知道 “下一个目的地” 的 MAC 地址了。A 重新发送数据包,将目标 MAC 地址填写为 路由器 1 的 MAC 地址,并在本地的缓存表中记录返回的 MAC 地址。
查看当前设备缓存表里已存的 MAC 地址:arp -a
ARP 协议的目的就是找到“下一个目的地”的 MAC 地址,即 IP 地址和 MAC 地址之间的映射关系。当两台设备同处于一个局域网时,“下一个目的地” 就是目标设备的 MAC 地址,当两台设备不处于同一个局域网时,“下一个目的地” 就是网关的 MAC 地址。
步骤 ③:网关间跳转
经过步骤 ①②,此时 路由器 1 收到的数据包为 { A_IP、PORT、A_MAC } ➡ { B_IP、PORT、路由器 1_MAC } 。收到数据包后,路由器 1 查看自己的路由表,如下图所示。
查看当前设备设置的路由表:route -n
路由器 1 会将 B_IP 与 路由表中每条记录的子网掩码(Genmask)做按位与运算。如果得到的结果和目的网络(Destination)相同,那么 “下一个目的地“ 的 MAC 地址,就是配置的网关(Gateway)的 MAC 地址,这种找到相邻网络的方式叫做 “下一跳机制”。如果网关的地址为 0.0.0.0,说明可以在局域网中直接通信,不需要 “下一跳”。至此,再次找到了 “下一个目的地” 的 MAC 地址,即 路由器 2 的 MAC 地址。此时 路由器 2 收到的数据包为 { A_IP、PORT、路由器 1_MAC } ➡ { B_IP、PORT、路由器 2_MAC } 。步骤 ④⑤ 和 ①② 的原理相同,在这里就不赘述了。
下一跳的目的就是找到“下一个目的地”,即下一步该到达哪里,侧重 “路线” 的选择,并由此获取到对应的 MAC 地址,继续传送数据包。
总结一下:
1.使用 ARP 协议找到网关出口或同一局域网内设备的 MAC 地址
2.按照路由表的每条规则和 目标 IP 地址做按位与运算,找到相邻网关入口的 MAC 地址
3.“下一个目的地” 和当前地址都仅仅相邻一步,且每次 “跳跃” 后的源 MAC 地址 和 目标 MAC 地址都会发生对应的替换
4.数据包中,IP 地址指明起点终点,MAC 地址指明跳跃的节点,端口号指明对应的应用服务
当然,光是找到对方还不够,还需要一个约定的交流方式,平时我们所熟知的各种协议,都是计算机「约定的交流方式」。
LVS 负载均衡
随着使用互联网的设备不断增长,服务端对应接收到的 HTTP 请求更是呈指数型的增长。当一台服务器无法承载非常大的请求量时,使用多台服务器来分摊请求。将请求分摊给多台服务器的行为,就称之为负载均衡。
ULB(UCloud Load Balancer)是 UCloud 提供的负载均衡服务,能够为多个主机或其它服务实例提供基于网络报文或代理方式的流量分发功能。在高并发服务环境下,通过 ULB 构建由多个服务节点组成的服务集群。服务集群能够扩展服务的处理及容错能力,并自动消除由于单一服务节点故障对服务整体的影响,提高服务的可用性。ULB 针对七层协议支持 HTTP、HTTPS 协议(类 Nginx 或 HAPproxy);四层协议支持 TCP 协议及 UDP 协议(类 LVS)。
从网络中计算机通信的角度,而非使用更上层的应用(如 Nginx)出发,搭建四层负载均衡器后,数据包的发送链路为:CIP ➡ VIP ➡ DIP ➡ RIP,即 客户端 IP ➡ 虚拟 IP ➡ 分发 IP ➡ 真实服务器 IP。对于客户端来说,只需要知道请求到达的地址是 VIP,不需要考虑负载,即 CIP ➡ VIP 是固定的。
所以负载均衡器要做的事情,就是将 CIP 发送到 VIP 的数据包,经由 DIP 转发给 RIP,服务响应后再将响应的数据包返回给 CIP。
NAT 模式
红色表示发出的数据包,绿色表示返回的数据包,黄色表示负载均衡器修改的内容 ,虚线表示经过 N 个下一跳,即可以不在同一局域网内,实线表示只能 “跳跃一次”,即必须在同一局域网内。
1.当计算机发出一个请求的数据包到达负载均衡器后,负载均衡器将发送数据包的 { 目标 IP 地址、端口号、目标 MAC 地址 } 转换为 { 某台真实服务器的 IP 地址、真实服务的端口号、真实服务器的 MAC 地址 } ,其余信息不变。这种只转换数据包的目标设备信息,而不修改数据包的源设备信息,称之为 DNAT,即目标网络地址转换。
2.真实服务器收到请求的数据包,返回响应的数据包:{ 某台真实服务器的 IP 地址、真实服务的端口号、真实服务器的 MAC 地址 } ➡️ { 原始请求的 IP 地址、端口号、跳跃的 MAC 地址 } 。所以此时在服务器上查看 TCP 连接为:CIP ➡️ RIP。
3.真实服务器返回的数据包的 “下一个目的地” 必须是负载均衡器。如果返回数据包直接返回给客户端,客户端发现返回数据包的源设备信息和发出数据包的目标设备信息不一致,将会丢弃返回数据包。所以真实服务器的默认网关必须是 DIP,保证返回数据包的 “下一个目的地” 是负载均衡器。
4.当返回的数据包到达负载均衡器后,负载均衡器将返回数据包的 { 原始请求的 IP 地址、端口号、跳跃的 MAC 地址 } 转换为原始请求的 { 目标 IP 地址、端口号、目标 MAC 地址 } 。这种只转换数据包的源设备信息,而不修改数据包的目标设备信息,称之为 SNAT,即源网络地址转换。
5.负载均衡器返回数据包给客户端。
总结一下 NAT 模式的特点:
1.修改数据包的「源 IP 地址」或 「目标 IP 地址」,可以对端口进行转发
2.真实服务器的默认网关必须是负载均衡器,所以真实服务器和负载均衡器必须在同一个局域网内
3.所有的请求数据包、响应数据包都要经过负载均衡器
FULLNAT 模式
NAT 模式中,负载均衡器和真实服务器必须在同一局域网内,但在实际的开发过程中,真实服务器可能分布在不同的网段,甚至不同的城市。如何能将 NAT 模式应用在真实服务器分布在不同网段的场景下?
红色表示发出的数据包,绿色表示返回的数据包,黄色表示负载均衡器修改的内容 ,虚线表示经过 N 个下一跳,即可以不在同一局域网内,实线表示只能 “跳跃一次”,即必须在同一局域网。
1.当计算机发出一个请求的数据包到达负载均衡器后,负载均衡器会对请求数据包同时做 SNAT 和 DNAT,将请求数据包修改为:{ 均衡出口 IP 地址、端口号、负载均衡器的 MAC 地址 } ➡️ { 某台真实服务器的 IP 地址、真实服务的端口号、真实服务器的 MAC 地址 }。
2.这样负载均衡器就可以独立的和真实服务器进行数据包的传送。
3.真实服务器收到请求的数据包,返回响应的数据包:{ 某台真实服务器的 IP 地址、真实服务的端口号、真实服务器的 MAC 地址 } ➡️ { 负载均衡器的 IP 地址、端口号、负载均衡器的 MAC 地址 } 。此时在真实服务器上查看 TCP 连接为:DIP ➡️ RIP。
4.当返回的数据包到达负载均衡器后,负载均衡器将返回数据包再次同时做 DNAT 和 SNAT。
5.负载均衡器返回数据包给客户端。
总结一下 FULL NAT 模式的特点:
1.同时修改数据包的「源 IP 地址」和「目标 IP 地址」,可以对端口进行转发
2.负载均衡器不需要以网关的形式存在,即负载均衡器可以和真实服务器在不同的网络中
3.真实服务器最终建立的连接是 DIP ➡️ RIP,无法获取真实客户端的 IP 地址
4.所有的请求数据包、响应数据包都要经过负载均衡器
LVS 本身不支持 FULLNAT 模式,需要额外对内核打补丁后才能使用。
可以看到在 NAT 和 FULLNAT 模式中,不管是请求数据包还是响应数据包,都要经过负载均衡器。但是响应数据包一般要比请求数据包大很多,这可能会成为系统的瓶颈。如果能够将请求数据包转发到真实服务器之后,响应数据包由真实服务器直接返回,这样对负载均衡器的压力就小很多。这种模式又该如何实现?
下篇继续~
版权声明: 本文为 InfoQ 作者【UCloud技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/471f96624008cfc79149783a9】。文章转载请联系作者。
评论