供稿 | eBay Infraops Team
作者 | 梅南翔
审稿 | 杨胜辉
编辑 | 顾欣怡
本文4536字,预计阅读时间14分钟
更多干货请关注“eBay技术荟”公众号
导读
本文对负载均衡器的 DSR(Direct Server Return)模式 进行了原理分析,并以业界普遍使用的F5 LTM+CentOS为例,探究了DSR配置的关键技术点,最后借助 Linux内核分析 ,对F5提供的官方步骤提出了优化方案。希望能对读者有所启发和帮助。
一、背景
在现代企业内部, 负载均衡器 (LoadBalancer,以下简称 LB )被大量使用。负载均衡器的常用模式如下图1所示:
图1 负载均衡的常用模式(代理模式)
(点击可查看大图)
负载均衡的常用模式可概述为下(详情可见: 分享 | eBay流量管理之负载均衡及应用交付 ):
1. 客户端向负载均衡器提供的虚拟IP地址VIP发送请求 (CIP → VIP) ;
2. 负载均衡器从提前配置的多个子网IP地址中选择一个(SNAT IP),替代客户端请求的源IP,并依据负载均衡算法,选择一个服务器IP作为目的IP,发送请求 (SNIP → SIP) ;
3. 服务器处理后将响应结果发回负载均衡器 (SIP → SNIP) ;
4. 负载均衡器将最终结果返回给客户端 (VIP → CIP ) 。
但负载均衡器的这种 经典SNAT模式 ,在基础架构运维中有以下 缺点 :
1. 由于信息量的因素,网络请求的回包往往会比请求包大很多。一般达到 10倍 [1] , 20 Mbps 的请求,其回包可能达到 200 Mbps 。这样一来,由于回包也是经过LB,就会大量增加LB的带宽使用,减小LB的有效处理容量。
2. 基础架构的服务(DNS,MAIL,LDAP等)工作在TCP/UDP传输层之上,所以无法像其它工作在HTTP协议以上的应用那样,用HTTP header里边的X-Forwarded-For字段来保存客户端真实IP。 这些基础架构服务的请求包在被LB进行SNAT之后,客户端的真正IP被替换为LB的SNAT IP。 这样造成的结果就是,后端服务器无法知道真实的客户端IP是什么,给问题排查、攻击检测、运行指标统计等运维活动带来极大不便。
而DSR (Direct Server Return,服务器直接返回)技术 (其在Layer 2实现时叫Direct Routing,F5称之为nPath), 顾名思义,就是让后端服务器绕开LB直接回包给客户端 (如下图2 [2] ),从而实现节省LB带宽和获取客户端真实IP的目标。
图2 DSR数据流图
(点击可查看大图)
二、原理
那么DSR又是通过怎样的独到之处,跟LB的看家本领SNAT叫板的呢? 原来,在DSR模式下,当网络请求包到达LB时,LB并不做SNAT,而是把包的源IP地址原封不动地转发给后端服务器。 当后端服务器拿到请求包以后,由于包里边携带了客户端的源IP地址,它就可以直接将回包通过网络路由给这个源IP地址,到达客户端手中。
不过,等等,这幸福来得也太突然了吧?让我们来仔细分析一下,看看这中间的重重险阻在哪里。
设想一下,服务端如果傻傻地用[src=SIP;dst=CIP]回包,那么客户端收到这个包以后,会怎么样?——当然是丢掉。为什么?因为客户端也不傻,它知道自己请求的是VIP,所以期待的是VIP给它的回包。至于这个服务端SIP又是个什么鬼?不需要,丢弃即可。因此,为了绕过客户端这道安全防线,聪明的工程师们想到了一个绝好的办法, 就是让服务端伪装自己的IP地址为VIP,用[src=VIP;dst=CIP]回包,以期能骗过客户端,让客户端误以为是LB的VIP回复给它的。
那是不是我们直接在服务端网卡上配置VIP,让服务端通过该网卡应答就可以?答案是No,因为这样虽然确保了客户端收到的应答包是[src=VIP,dst=CIP],但带来的问题是:服务端和LB将同时应答ARP,引发IP地址冲突。所以,服务端伪装VIP可以,但一定要低调,万万不可让其他人知道—— 有一个绝好的办法,就是将VIP偷偷地配置到loopback网卡或者tunl0这些本地的网络接口上 ,既骗过了内核,让它以为真的有这个合法IP地址,又不会被外边的设备发现,一石二鸟,想想都激动。
还有一个问题,怎么样才能让服务端内核以[src=VIP,dst=CIP]的组合回包呢?由于内核是严格按照(src→dst, dst→src)的方式进行回包的,那让服务端内核如此回包的最好办法,当然是让LB转发[src=CIP,dst=VIP]的包给服务端的内核啦。但是,这听上去有点像天方夜谭,服务端的VIP是一个“偷偷摸摸”的配置,所以LB发出的[src=CIP,dst=VIP]的IP包,在路由时,一定是找到了LB上的VIP,绝无可能被路由到服务端去。怎么办?我可太“南”了…
针对上述问题,有一个办法,就是LB跳过L3三层路由,直接把[src=CIP, dst=VIP]的IP包,塞到一个目标MAC地址为服务端网卡MAC地址的L2网络包里,送达服务端网卡 (相当于将从客户端到LB的L2数据包更换一下目标MAC地址。对应于NAT,这种实现方法也被称作MAT,即MAC Address Translation [3] ,参见图3)。
图3 L2 DSR替换请求包的目标MAC地址
(点击可查看大图)
这个方法实现简单,但有一个硬伤,就是当LB和后端服务器不在同一个L2网络的时候就无能为力了。所以我们还是回到L3网络来考虑这个问题,也就是如何让LB把[src=CIP,dst=VIP]的IP包转发给服务端的内核。 如果把网络通信类比于传统信件,那我们现在的需求就是,让LB送一封“收件人”为VIP的信件,并且保证该信件是送到服务端而不是LB自己。 通过这一类比,我们不难想出一个好办法,就是让LB给服务端送一封信([dst=SIP]),然后在这封信里再嵌入一封“收件人”为VIP的信([dst=VIP]);同时在外层信封上标注——这里边装的不是TCP,也不是UDP,而是另外一封信(协议)。这样当服务端收到外边的信封以后,它继续拆开里面的信,就可以获取到[src=CIP,dst=VIP]的数据了。
事实上,这种做法就是 网络隧道(Network Tunnel) 的概念——将一种网络协议包(inner packet)作为payload嵌入外层网络协议包中,并利用外层网络协议进行寻址和传输,从而实现原本割裂的内层网络像隧道一样被打通了的效果。
最常见的网络隧道就是我们使用的VPN :当拨入VPN之后,我们就可以访问10.x.x.x这种内网地址了。很显然是10.x.x.x这种IP包被封装进了某种特殊的通道,也就是一些基于公网VPN协议的网络隧道。 类似于VPN,在DSR这种场景下,我们就是要将访问VIP的IP包通过至SIP形成的隧道进行传输。 Linux支持的IP in IP协议主要有 IPIP 和 GRE 两种,IPIP隧道不对内层IP数据进行加密 [4] ,所以它最简单,效率最高,如图4所示 。由于是内网可信网络,因此选用IPIP这种最简单高效的隧道协议。
图4 IPIP隧道协议
(点击可查看大图)
我们可以让LB生成这样的一个IPIP包[src=CIP, dst=SIP, protocol=IPIP, payload=[src=CIP, dst=VIP] ]并发出去。由于外层的IP包目标地址是服务端IP,所以外层IP包顺利到达服务端内核;服务端内核拆包一看,这里边又是一个IPIP包,于是进一步解包,发现是[src=CIP,dst=VIP]的包。 这时内核检查dst=VIP是本地一个合法的IP地址(因为本地网卡已经配置了VIP),于是欣然接受,并根据TCP/UDP的目标端口转给应用程序处理。 而应用程序处理完,就顺理成章地交由内核,按照(src→dst, dst→src)的原则,产生[src=VIP, dst=CIP]的IP包进入网络路由至客户端,问题解决!此时的数据流图参见下图5:
图5 使用IPIP隧道的DSR数据流图
(点击可查看大图)
三、探究
下面,我们以业界普遍使用的 F5负载均衡器 LTM + CentOS 7 为例,实战分析探究一下DSR配置的关键技术。
Step 1
如下所示,在LB上配置一个有2个成员的负载均衡池(pool),并创建一个VIP对应到该pool:
-
该pool指定的profile为IPIP,表示LB和该pool的成员通讯,走IPIP隧道;
-
要关闭PVA-Acceleration,因为DSR模式下,client不再直接与VIP建立TCP连接,所以用不到L4的PVA硬件加速;
-
该VIP指定translate-address disabled,表示不对请求该VIP的流量进行SNAT。
(点击可查看大图)
Step 2
此时,我们在server端先不做任何配置,直接从client去telnet VIP,并且从server端分别用VIP和CIP抓包(如表1),看有什么现象发生。
表1 分别用VIP和CIP作为条件抓包
(点击可查看大图)
从wireshark中可以看到,LB在收到[CIP,VIP]的请求后,产生一个IPIP的包[src=CIP, dst=SIP, protocol=IPIP, payload=[src=CIP, dst=VIP] ]。这时候,由于我们还没有从服务端正确地配置IPIP Tunnel和VIP, 所以这个包无法正确地被识别和处理, 导致了 3次 SYN包的重传和 1次 RST (图6中的包3,5,7和9),同时服务端以ICMP的形式告诉client,由于目标IP地址无法抵达的缘故,之前的包无法被正常传递 [5] (图中包2,4,6,8,10)。
图6 LB通过IPIP隧道发到服务端的数据包
(点击可查看大图)
Step 3
进一步分析,由于服务端的内核还没有加载IPIP模块,所以它不能识别Protocol=IPIP的数据包,无法解析出嵌入在IPIP包里的内层IP数据包。由于VIP只出现在内层IP包里,因此以VIP作为filter抓包,自然是抓不到了。 现在我们尝试让内核加载IPIP模块并再次抓包,看它能否识别并解开内层IP包。
我们重新做一次表1的telnet和tcpdump,相比于上一次的抓包,这次我们以VIP作为filter就可以抓到内层IP包了。 这说明内核加载IPIP模块后就可以识别Protocol=IPIP的数据包了。 但到这里,由于我们并没有在服务端的任何网络接口(interface)上配置VIP,所以服务端仍然未作出回包处理。
Step 4
下一步,就是将VIP配置到tunl0或者lo上,让内核识别到这是一个合法的IP地址。在F5提供的参考配置文档 [6] 中,就是将VIP配置到loopback网卡lo:1上,并在tunl0上配置SIP。但是仔细思考一下,F5官方提供的这个配置并不令人十分满意——根据我们前边的分析,我们只要在loopback或者tunl0这类本地网卡上配置VIP,让内核认为只是一个合法的地址就行了,为什么还要多此一举地往tunl0上配置SIP?
既然有这个疑问了,我们索性逐步推进,看看, 如果不在tunl0上配置SIP到底会发生什么?
Step 4.1
首先,我们在lo:1上配置VIP,并且不在tunl0上配置任何IP地址。
再次重做telnet,并用CIP作为filter抓包(语句见表1),结果如图7所示,只能抓到客户端到服务端的请求包(奇数行为eth0收到的外层包,偶数行为tunl0收到的内层包, 总共是 1 次 SYN+ 3次 SYN重传,和 1次 RST )。
图7 服务端未回包
(点击可查看大图)
可见服务端内核确实收到了[dst=VIP]的包,但既没有送给应用程序,也没有回包,那是内核将这些包丢弃了吗?此时用dmesg命令检查一下内核日志,发现在对应时间段有 5条 下述日志:
这个报错是什么意思呢?原来,网络攻击者(例如DDOS)在攻击时,都会伪装自己的IP地址(IP Address Spoofing),以绕开IP源地址检查或是防止DDOS回包回到自身。由于源地址无法路由可达(route back),这时服务端就会不断保持连接并等待,直到连接超时,造成资源耗竭无法正常提供服务。
为了应对这种攻击,Linux内核加上了一个叫做 反向路径过滤(reverse path filtering [7] )的机制,这个机制会检查,收到包的源地址是否能从收包接口(interface)路由可达,如果不可达,就会将该包丢弃,并记录 “martian source” 日志 。回到我们问题的场景,tunl0在收到内部IP包[src=CIP, dst=VIP]这个包之后,就会去尝试验证从tunl0这个接口能不能连通CIP=10.218.98.18,由于tunl0无法路由到CIP,所以出现了上述的报错。
那有什么办法,既能够保证一定程度的安全,又可以支持DSR这种场景呢?rp_filter这个参数有 3个 值 [8 ] ,如图8,其中Loose mode下,只要从任何接口可以路由到源IP地址(而不限于收包接口),就不做丢弃处理。所以, 我们可以将tunl0的rp_filter设置成 2 ,这样由于CIP可以经由eth0路由,验证应该会成功。
图8 Linux内核关于rp_filter的定义
(点击可查看大图)
Step 4.2
如下所示, 设置tunl0的rp_filter= 2 ,也就是对从tunl0进入的IP网络包,如果其源IP地址可经由机器上任意网卡(例如eth0)路由到,就认为它是一个合法的报文。
然后重新做一次telnet和tcpdump,奇怪的是,我们依旧没有看到服务端内核回包,并且内核日志仍旧报 “martian source” 的错误。这又是怎么回事呢?看来,F5官方文档让在tunl0上配置SIP的要求似乎是不能省略的。
Step 4.3
接下来我们往tunl0上配置SIP,然后重做telnet和tcpdump。不出所料,此时服务端给出了正确的DSR回包(限于篇幅,此处略去抓包结果)。
到这里,DSR误打误撞地完成了配置,但我心里还有些难以平复—— Tunl0网卡的作用在于接收IPIP隧道内的内层IP包,但是服务端内核在回包时,是直接将[src=VIP, dst=CIP]的IP包经由eth0路由出去的,根本就没有tunl0什么事。 所以tunl0上理论上不需要配置任何IP,但为什么在tunl0上配置SIP以后,就能解决"martian source"的问题呢?
怀着这个问题,我在网上找了很久的答案都没找到,最终通过eBPF对 linux 内核源码进行分析, 发现在linux的rp_filter代码中,如果网络接口(这里是tunl0)不配置任何ip(ifa_list == NULL),那么就会返回验证失败。
具体请参考github链接:
https://github.com/centurycoder/martian_source
(点击可查看大图)
Step 5
既然linux内核要求tunl0上必须配置IP地址,那是不是意味着我们必须按照F5提供的官方步骤进行配置呢?不是的,我们前面已经分析,只要是在loopback或者tunl网卡上配置VIP骗过内核就行, 那我们就索性将VIP直接配置到tunl0网卡上,这样既实现了tunl0上有IP地址的要求,又满足了VIP是一个合法目标地址的要求。
我们将第4步的配置回退后,在tunl0上配置VIP和rp_filter,如下所示:
然后按照表1重新做一次telnet和tcpdump,如图9所示,客户端和服务端通过DSR成功完成TCP的3次握手( 1 是eth0端口上抓到的外层包, 2 是tunl0上抓到的内层包,它们其实是同一个 SYN包 ,所以被wireshark标记为TCP Out-of-Order; 3 是服务端回复的 SYN/ACK包 ,它不走Tunnel,所以没有成对出现; 4 和 5 是客户端发的 ACK包 ,分别是eth0抓到的外层包和tunl0抓到的内层包,被wireshark误认为是重复的ACK)。
图9 成功的DSR通讯
(点击可查看大图)
四、总结
到这里,我们就完成了DSR的原理分享和探究,并且通过对原理以及Linux内核源码的分析,对F5官方提供的步骤进行了解析和优化。总的来说,从运用方面来看, 相比于SNAT模式,DSR在提高LB带宽容量、保持客户端真实IP等方面有很大优势。 但在选择DSR或者SNAT模式时还要考虑实际运用场景。 DSR往往更适用于LB仅用作负载均衡功能的场景 ,而如果LB还承担SSL offload、Cache、加速或者其它安全相关功能时,则只能选取经典SNAT模式 [9] 。希望本文能对各位读者理解和运用DSR技术有所帮助和启发。
参考资料:
[1]https://kemptechnologies.com/au/white-papers/what-is-direct-server-return/
[2]https://www.loadbalancer.org/blog/15-years-later-we-still-love-dsr/
[3]https://www.haproxy.com/support/technical-notes/an-0053-en-server-configuration-with-an-aloha-in-direct-server-return-mode-dsr/
[4]https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/
[5]https://tools.ietf.org/html/rfc792
[6]https://techdocs.f5.com/en-us/bigip-15-0-0/big-ip-local-traffic-manager-implementations/configuring-layer-3-npath-routing.html
[7]https://www.slashroot.in/linux-kernel-rpfilter-settings-reverse-path-filtering
[8]https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
[9]https://devcentral.f5.com/s/articles/the-disadvantages-of-dsr-direct-server-return
您可能还感兴趣:
干货 | Rheos SQL: 高效易用的实时流式 SQL 处理平台
分享 | eBay流量管理之Kubernetes网络硬核排查案例
:point_down:点击 阅读原文 ,一键投递
eBay大量优质职位,等的就是你
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 大数据平台架构设计探究
- Vue源码探究-数据绑定逻辑架构
- 《从零构建前后分离web项目》探究 - 深入聊聊前后分离架构
- 跨域不完全探究
- Spring源码探究:容器
- Flutter BuildContext 探究
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Remote
Jason Fried、David Heinemeier Hansson / Crown Business / 2013-10-29 / CAD 26.95
The “work from home” phenomenon is thoroughly explored in this illuminating new book from bestselling 37signals founders Fried and Hansson, who point to the surging trend of employees working from hom......一起来看看 《Remote》 这本书的介绍吧!