提示
X
本案例来自tskb,请前往tskb修改源内容:立即前往
'>

【AD】AD节点监视器时间戳导致节点池故障、业务异常

|

问题描述



1、虚拟服务(10.65.161.90:6180)发布两台认证服务器(10.65.161.82/83:6180)的业务;
2、Client和业务A正常访问虚拟服务(10.65.161.90:6180);
3、业务B访问虚拟服务(10.65.161.90:6180),前2次访问均正常,然后逐步出现节点池故障,业务B无法调用虚拟服务;
4、Client与虚拟服务之间服务异常;
5、业务B跳过AD访问认证服务器(10.65.161.82/83:6180),业务始终正常;

告警信息

节点日志中查看,connect_tcp健康检查报错。

有效排查步骤

场景1业务情况
前后端TCP会话分离,AD作为业务B和认证服务器中间的会话代理设备,分别与业务B、认证服务器节点建立会话。



数据分析
1、健康检查:监视器发包源IP90地址,并且没有携带时间戳(没有配置系统时间戳),监视器与认证服务器四层报文交互正常



2、L7 TCP会话建立:



(1) 10.65.248.24先跟虚拟服务vip 10.65.161.90在前端建立TCP会话(图中第176-178报文,前端3次握手);
(2) SNAT地址10.65.161.90(自动SNAT)与10.65.161.82在后端建立TCP会话(图中第179-181报文,后端3次握手);
(3) SYN报文(第176号报文和179号报文)可以看出,业务BAD之间的交互携带了时间戳,而AD与认证服务器之间并没有携带时间戳;

小结
L7 TCP发布虚拟服务,分离了前后端的TCP会话连接,后端使用10.65.161.90跟节点池进行健康检查或业务转发都不带时间戳,那么认证服务器就不会进行时间戳校验,业务的流量转发和节点池心跳探测都正常。

场景2业务情况
虚拟服务使用L4 TCP类型,使用10.65.161.90:6180发布虚拟服务,SNAT地址使用10.65.161.91。前端业务B10.65.161.90建立TCP会话,后端10.65.161.91与节点池建立连接。
业务B访问虚拟服务正常,但省厅客户端tcping业务异常。




数据分析
1、健康检查:监视器发包源IP90地址,并且没有携带时间戳(没有配置系统时间戳),监视器正常



2、业务转换手动SNAT地址是10.65.161.91,业务层面发包是时间戳改写(TCP四层优化策略),也就是对于服务器来说,10.65.161.91IP过来的数据有时间戳并且是有序的,业务正常



(1) 先找到一个业务正常的流量,通过端口来筛选;
(2) 场景2在业务层面配置了seq序列号修改;
(3) 场景2在业务层面配置了时间戳修改,可以看出数据包的时间戳是有序的(10.65.161.91 -> 10.65.161.82的数据包,TSval=2251581309,回包的时候Tsecr=2251581309):



小结
健康检查使用10.65.161.90不带时间戳与节点池进行心跳检查;虚拟服务后端使用10.65.161.91与节点池进行TCP会话连接,时间戳按照前端数据包进行改写,认证服务器只校验业务报文的时间戳。
场景2中,健康检查的会话与业务流量的会话本身是隔离的,所以认证服务器只对业务流量进行时间戳校验,并且时间戳有序,节点池健康,业务正常。

场景3业务情况




数据分析
1、筛选SYN报文,找到10.65.161.90发送到10.65.161.83的报文时间戳乱序(乱序的位置分别是第15号报文和第26号报文、第110号报文和第121号报文、第161号报文和第172号报文)



2、TCP四层优化策略,进行业务层面的seq和时间戳改写,即经过SNAT转发后的报文改写时间戳(注意:但监视器使用的是系统层面的时间戳,导致了同样通过10.65.161.90进行数据包发送,但是时间戳的参照不同,会存在偏移量)。

小结
其实对比场景3(上图)的第26号报文和第121号报文可以看出(监视器默认5s发送一次检查包),负载系统层面发出的报文时间戳是递增的;业务层面转发的业务报文(非重传的那些报文),时间戳也是递增的。但是由于时间戳参照不同,导致发送到认证服务器进行时间戳校验时,发现健康检查的报文是旧数据包,被认证服务器丢弃,导致节点健康检查失败,随即故障状态。

根因

业务B来访问虚拟服务的时候默认是携带时间戳的,然后负载L4 TCP默认自动SNAT并做纯转发,然后认证服务器启用了时间戳校验,导致跟10.65.161.90去做健康检查的SYN报文冲突了(健康检查的报文默认不带时间戳),这样就造成一种时间戳乱序的状态,认证服务器认为健康检查的报文是旧报文(健康检查的报文时间戳比业务报文的时间戳小),所以健康检查的报文全部被丢弃了,导致了访问几次后出现的节点故障现象。

解决方案

方案一:AD - 7.0.8R3
使用L7 TCP,前后端TCP会话分离,将监视器IPSNAT IP分开。监视器IP与节点之间交互无时间戳,SNAT有无时间戳都无所谓,不会造成后端时间戳乱序。

注意:
7.0.8R3版本监视器使用系统层面的时间戳参照,WEB控制台【网络参数】-【系统时间戳】可以进行开启,默认监视器不带时间戳。
②节点(Linux)需要开启net.ipv4.timestampsnet.ipv4.recyclenet.ipv4.reuse这三个选项。

方案二:AD - 7.0.8R4及以上配置



系统时间戳:启用后,设备自身发包(例如节点监视器发包)将会在TCP可选项中携带时间戳字段;禁用后,不会携带时间戳字段。
SNAT时自动调整时间戳/序列号启用后,系统将自动调整做了SNAT的数据包的时间戳和序列号信息,此时TCP策略和转发包策略中的时间戳/序列号调整配置将会失效;如果数据包没有做SNAT,则TCP策略和转发包策略中的对应配置生效。

方案三:节点(Linux) - 关闭时间戳校验
节点关闭时间戳校验,即net.ipv4.tcp_timestamps=0

操作影响范围

单个虚拟服务

建议与总结

1、时间戳(Timestamp
TCP报头中的可选字段(TCP Options),时间戳选项占10个字节= kind(1字节) length(1字节) + info (8字节),其中kind=8length=10infotimestamp valuetimestamp echo reply两个值组成,各4个字节的长度。



发送方在发送报文段时把当前时钟的时间值放入时间戳字段timestamp value,接收方在确认该报文段时把时间戳字段值复制到时间戳回复响应字段timestamp echo reply)。

下面我们以一个例子理解timestamp valuetimestamp echo reply字段中存放的内容:假设a主机和b主机之间通信,a主机向b主机发送一个报文,那么:
1timestamp value字段中存放的内容:a主机向b主机发送报文r1,在r1报文中timestamp value存放的是a主机发送r1时的内核时刻t1
2)timestamp echo reply字段中存放的内容:b主机收到r1报文并向a主机发送含有确认ACK的报文r2,在r2报文中,timestamp valueb主机此时的内核时刻t2,而timestamp echo reply字段为从r1报文中解析出的t1

时间戳功能:
1)计算往返时延RTTRTT = t2 - t1RTT为正数。
2)防止回绕的序列号:TCP报文的序列号只有32位,而增加2^32个序列号后就会重复使用原来用过的序列号。在高带宽的情况下,序列号很快就会出现重复的情况,这样TCP传输带来混乱。采用时间戳选项,可以很容易的分辨出相同序列号的数据报文,哪个是新的报文,哪个是旧的报文

2、Time_wait



处于Time_wait状态的一端只会存在于四次挥手中主动发起挥手FIN的一端(同时发起,则两端都进入Time_wait状态)。
在短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上(Time_wait保持状态不会再发起与之前源端口相同的数据包,而是随机匹配到其他的端口,这样在NAT场景下,会大量占用某个/IP的源端口,导致源地址或者源端口数不够);

3、Time_wait和时间戳
TCP规范中规定的处于TIME_WAITTCP连接必须等待2MSLMaximum Segment Lifetime)时间。
但在Linux中,如果开启了tcp_tw_recycleTIME_WAITTCP连接就不会等待2MSL时间,从而达到快速回收和重用(配合tcp_tw_reuse)处于TIME_WAIT状态的TCP连接的目的,这就可能导致收到之前连接的数据(服务器端释放了,但是请求客户端还可能继续发数据包)。
为此,linux在打开tcp_tw_recycle的情况下,会记录下TIME_WAIT连接的对端(peer)信息,包括IP地址、时间戳等。这样,当内核收到同一个IPSYN包时,就会去比较时间戳,检查SYN包的时间戳是否滞后(新旧程度),以保证自己接收到的不是之前连接的数据;如果滞后,就将其丢掉(认为是旧连接的数据)。这在绝大部分情况下是没有问题的,但是对于我们实际的C/S服务,访问我们虚拟服务的用户一般都会被SNAT处理,如果SNAT之后有多个用户访问同一个服务,就有可能因为时间戳滞后的连接被丢掉(服务器开启时间戳校验,无序的时间戳数据包会被服务器判别为滞后)。

排查内容

net.ipv4.tcp_timestamps:默认开启,开启后,如果收到syn的包包含时间戳选项,就会应答时间戳选项,同时配合下面的几个参数校验收到包的时间戳



2、net.ipv4.tcp_tw_recycle:默认关闭,开启后,timewait状态的连接会快速释放,Time_wait状态的连接会占用系统资源,如果并发太多,可能导致系统资源不足,此时就可以开启快速释放。(很多生产场景中,都不建议在NAT场景下启用该参数
3、net.ipv4.tcp_tw_reuse:默认关闭,开启后,Time_wait连接可以实现快速复用,前提是收到的SYN包时间戳大于之前的时间戳(主要一般跟tcp_tw_recycle参数共同使用,快速释放之后实现快速复用
4、net.ipv4.tcp_rfc1337:默认关闭,Time_wait连接收到RST后会快速释放;如果启用,那么收到RSTTime_wait也不会释放(配合负载TCP七层优化策略中强制关闭连接来使用,配置当客户端与节点四次挥手关闭连接后是否发送RST关闭与客户端的连接或与服务端的连接,使客户端或节点不用等待2MSLTIME_WAIT即可快速释放连接回收资源)。



我要分享
文档编号: 210111
作者: admin
更新时间: 2023-04-06 16:23
适用版本: