前言:
这篇随笔是最近处理的一起真实网络故障分析案例,特此分享给身边同行的朋友。
故障介绍:
公网这台服务器通过http协议与分支内部的一台服务器做业务交易,当公网服务器向分支这台内部服务器发起http请求做交易时,结果无响应,这也意味着是一次失败的业务交易。多次尝试,结果依然是无响应,由此展开了故障排查工作。排查的过程中客户回忆到是在某一个时刻打完网站补丁后,出的交易故障,客户建议卸载补丁试试看能不能恢复,此时服务器管理员卸载了补丁后,业务交易正常。(最后通过排查实际上并不是因为服务器补丁问题,而是网络问题导致的,打补丁只是恰巧碰到了问题。)
网络架构如下:
1、总部内部详细网络结构忽略不计,两台服务器的交互流量不经忽略的网络节点
2、此网络原本是高可靠冗余设备架构,为方便描述,在图中省略了备份设备,可忽略。
3、抗DDoS设备可当做流量透传,无业务口IP无路由,只做安全防护。
4、负载均衡设备配置公网IP、并配置有SNAT、DNAT转换。公网服务器访问到总部经过总部负载均衡时,源目IP以及源目端口都将被转换。
5、两台山石防火墙通过各自的负载均衡端口映射来建立ipsec vpn。
6、分支山石防火墙与天融信防火墙都做了地址转换与端口映射。
7、以下图片是服务器交互流量路径示意图。
故障处理过程:(以下描述中客户端侧表示公网服务器,服务器侧表示分支内网的服务器)
1、向客户了解业务故障的基础信息,由于是http协议,那么切入点直接从tcp连接是否正常开始,经确认两端tcp连接正常。这个时候基本可以判断以下几点:
负载均衡未充当代理,只做网络层IP地址和传输层端口转换:
①两台服务器的tcp连接正常,可以排除异步路由问题。
②两台服务器的tcp连接正常,可以排除到传输层的安全策略问题。
2、由于向客户了解到是ipsec vpn环境,那么接下来思考的问题应该是MTU问题,我们知道在ipsec vpn的场景中会增加链路的开销,其表现为数据经过ipsec封装以后会增加 额外的ESP头部、AH头部、UDP头部以及外层IP头部。这个时候我们应该采取手段使数据被ipsec封装以后的数据包大小小于MTU大小(1500字节)
①默认情况下,接口MTU=1500,所以两台服务器建立TCP连接的时候,TCP MSS=1460字节(1500字节-IP头部20字节-TCP头部20字节),最终TCP MSS也会协商为1460 字节。
②由于协商的TCP MSS为1460字节,那么也就意味着当服务器产生大包的时候,tcp的payload最大为1460字节,再加上常规tcp头部20字节和常规ip头部20字节,总共为1500字节。当这个数据路由到山石防火墙时,山石防火墙通过ipsec封装数据以后,那么数据包大小应接近1600字节,此时已超过接口MTU最大值1500字节,会发生丢包。
③通过以上分析,可以调节客户端侧或者服务器侧的MTU值为1400字节,建议调节客户端侧,服务器不止对这一个客户提供服务(影响较大)
④当客户端侧更改MTU为1400字节以后,业务依然无响应,此时可以排除ipsec vpn环境MTU值影响丢包。
3、通过基础的诊断和测试以后,那么最后只剩下通过抓包来一探究竟。
抓包节点选取:
①客户端侧和服务器侧,都抓取本地业务接口流量。
②总部山石防火墙上行接口流量抓取。
③分支山石防火墙和天融信防火墙不限定接口流量抓取。
④负载均衡不需要抓,因为流量经过了ipsec封装,看不到实际数据。
在进行抓包的过程中,需要考虑以下问题:
①数据的访问都经过了NAT转换,由于定义的地址池不确定接下来的数据包会转换成什么地址,这个时候定义的抓包规则最适合的也就是根据目的IP和目的端口来抓,抓取双向流量,则定义两条。
②由于此服务器不仅对接这一个客户,当访问的流量经过地址转换过后,很难确定发起者的数据包是哪一个。那么如何能够准确的找到业务发起者的数据包呢?
4、把抓包的环境都准备好后,那么紧接着就是客户端侧发包测试了。抓包结果如下:
分析思路:
由于交互的数据经过网络设备转发的时候经过了NAT转换,如果想要找到交互的流量包绝非易事。
①可以通过在NAT设备上查询NAT会话信息来确定数据包的源IP以及端口信息,因为这种方式需要在每一层NAT设备上查看会话信息才能找到数据包,而且是依靠上一个NAT会话信息来到下一个设备上再查询NAT会话,以此类推。过程繁琐且复杂(此种方式不推荐 )
②可以通过客户侧发起端的数据包来定位其他节点抓取的业务交互数据包,这样即快速又准确。
客户端侧抓包如下:避免暴露用户信息,交互的IP地址被隐
根据以上截图信息可以得到什么结果呢?
①根据标记的红色窗体数据,服务器回应的seq 918,ack 1136就可以初步判断服务器回的包有丢失现象。为什么单凭这个信息就可以判断服务器的回复包有丢失呢?
因为,根据以上红色窗体数据,客户端总共发了379+756=1135字节的数据,而服务器回复的包seq 918,ack 1136。ack这个字段没任何问题,有问题的是seq 918,因为这意味着服务器之前是有发过一个数据seq 1,ack=1136,tcp length=917的数据,但在客户端侧却未抓取到。
②接下来就要分析其他节点抓取的数据包了,看看在哪里发生了丢包。那么我们如何依靠客户端侧的抓的流量来快速准确的定位其他节点抓到的对应数据包了?
我们的网络环境并没有代理的环境,那么想找到数据包是轻而易举的。虽然数据包在传输的过程中经过了N多次地址转换和端口转换,但仅仅改变的只是IP头部中源IP和目的IP值,TCP头部中源端口和目的端口的值。这样就可以根据头部中的其他字段来定位数据包。有以下一些字段可以使用定位:
IP头部中:Identification(截图中的ID字段)
TCP头部中:seq、ack数值,tcp length长度(不是非常准确,可能会与其他客户端发的数据大小一致),以及tcp option中的等等字段
③定位到数据流以后,就直接找丢失的数据包(seq 1,ack 1136 tcp length 917)
服务器抓包信息有此丢失的数据包,天融信防火墙也有此丢失的数据包,山石防火墙上也有此丢失的数据包(并且显示进了ipsec vpn隧道),但在总部山石上未找到此丢失的数据包。这个时候就可以缩小故障节点范围了。
可能在这些节点发生丢包:分支负载均衡-分支抗DDoS-运营商-总部抗DDos-总部负载均衡
④从负载均衡上抓包几乎没有意义,数据包通过ipsec封装后,数据被加密无法判断是否有丢失的数据包经过
⑤运营商丢包的可能性极小,因为ipsec隧道中的流量仅仅只是(seq 1,ack 1136 tcp length 917)这个数据包被丢弃
⑥进而将目标转移到抗DDoS上,通过查看抗DDoS上的日志信息,竟然有丢弃ipsec使用的公网源目IP的流量,而且还很频繁。单凭这个日志信息无法确定有没有丢弃我们所关注的数据包。
⑦随后在抗DDoS上新增了一条访问控制规则,将ipsec使用的源目公网IP添加到放行规则,再观察日志丢弃情况,观察了2-3分钟,发现没有了丢弃现象。
⑧接下来让客户端侧再发起交易的流量,竟有了响应。也就说明了客户端侧与服务器的交互流量正常,未丢失。反复测了几次都正常。
⑨关于抗DDoS上的丢包日志无实际参考意义,提示的日志信息是无效的udp头部,可以肯定的是数据包的组包结构是没有问题的,数据也是正常的大小。为什么那么多数据包每次都丢(seq 1,ack 1136 tcp length 917)这个数据包呢?令人匪夷所思!!!
⑩由于测试在抗DDoS上添加的放行规则有安全风险(如果分支或总部内部主机失陷被控制的话,发出大量flood包会被抗DDoS直接放行不会拦截),最后通过升级抗DDoS的软件版本彻底解决了无脑丢弃数据包问题,也随之取消了放行规则。