探索 | 一个有趣的TCP链接问题

上网导航 2023-07-14 316 0条评论
摘要: 本文分享了最近发生的影响CAL可用性和稳定性的问题,以及CAL团队如何使用TCPDUMP和systemtap找出根本原因。...

导读

可用性和稳定性对于eBay的网络站点非常重要。

本文分享了CAL(集中式应用程序日志框架)中最近发生的一个有趣的TCP链接问题,这一问题会严重影响CAL的稳定性,进而影响eBay网络站点的良好运行,解决问题迫在眉睫。

来看看CAL团队如何使用TCPDUMP和systemtap工具,通过简单高效的四个步骤,找出问题的根本原因的。

CAL运行架构

CAL是eBay的集中式应用程序日志框架。

CAL的主要目的是集中收集应用程序服务器的本地日志,并据此给出所收集数据的报告。CAL的数据报告提供了对eBay站点重要领域的深入洞察,这对于eBay制定业务的各个方面都非常宝贵。

那么,CAL是如何运行的呢?

探索 | 一个有趣的TCP链接问题

如上图所示,在CAL的运行架构中,CAL客户端会尝试与CALVIP(虚拟IP地址)建立TCP长连接。由于CAL的流量非常巨大(每秒几十GB),单对负载均衡器(LoadBalancer)无法负载,因此有数对LB负责流量的传输,不同的LB上有不同的VIP。CAL客户端先从DNS查询中随机选择一个VIP尝试连接,如果连接超时,客户端会选择另一个VIP重试,直到成功建立连接。

问题描述

最近,CAL团队遇到了一些奇怪的问题,这让他们有些困扰。

探索 | 一个有趣的TCP链接问题

如上图NetCat输出所示,VIP会间歇性地返回连接超时,而且这一问题频繁而毫无规律地出现,这会严重影响CAL的稳定性,进而影响eBay网络站点的良好运行。

问题修复迫在眉睫,一起来看看CAL团队是如何进行故障定位的吧!

故障定位

对故障的定位与处理主要分为以下四个步骤。

Step 1.

在LB上运行TCPDUMP

明明VIP和LB的配置看起来都是正确的,为什么VIP还会连接超时?

我们首先查看TCPDUMP,试图找到连接超时的原因。

探索 | 一个有趣的TCP链接问题

如上方的Wireshark截图所示,当连接超时发生时,LB主动向客户端发送了RST包,根据F5的插件给出的原因是流量到期(Flowexpiration)。

我们把其中一个TCP流拿出来单独看。

探索 | 一个有趣的TCP链接问题

如上方截图所示,LB的SNAT(SecureNetworkAddressTranslation)IP发送了3次SYN包,但是服务器端无视了这些包。大约15秒以后,LB的SNATIP认为连接超时,主动发送了一个RST包。

Step 2.

检查SYN队列和Accept队列

为什么服务器会忽略LB发来的SYN数据包?

由于当时我们正在做CAL流量的迁移,绝大部分CAL流量正在从老版本代码向新版本迁移。因此我们猜测可能是新版本代码的性能问题。

一个合理的解释是新版本性能不够强,无法及时处理巨大的流量,导致SYN队列堆积满溢,新的SYN包无法进入队列而被丢弃。

下图解释了SYN队列以及Accept队列的工作方式。

探索 | 一个有趣的TCP链接问题

乍一看,证据似乎支持了前面的假设。

但是,我们写了一个Systemtap的探针脚本(如下图)尝试去捕捉SYN队列满溢情况,却没有得到任何输出。

探索 | 一个有趣的TCP链接问题

因此,对于新版本代码性能问题导致SYN包被丢弃的猜测被证实是错误的。

Step 3.

用netstat -s重新检查网络状态

由于之前的猜测被推翻,我们用netstat-s重新检查了网络层面的状态。

通过检测,一条新的线索浮出水面(如下图),我们发现,大部分的SYN包被丢弃的原因是时间戳(timestamp)。

探索 | 一个有趣的TCP链接问题

那么,时间戳是如何导致SYN包丢失的?

原来,‘Passive connections rejected because of time stamp'有一个专门的计数器LINUX_MIB_PAWSPASSIVEREJECTED,它在内核代码中只出现在一个地方[1]。当函数tcp_peer_is_proven(req,dst, true)返回false时,Linux内核会丢弃SYN包并记录在LINUX_MIB_PAWSPASSIVEREJECTED。

[1]https://elixir.bootlin.com/linux/v3.10/source/net/ipv4/tcp_ipv4.c#L1555

这段代码片段如下:

探索 | 一个有趣的TCP链接问题

探索 | 一个有趣的TCP链接问题

如上图所示,当tcp_tw_recycle打开时,内核记录了每个peer最后一个ACK的时间戳,当新的连接满足以下3个条件时,SYN包会被内核直接丢弃。

据此,我们怀疑,是LB SNAT与Linux内核参数net.ipv4.tcp_tw_recycle一起导致了这个问题。在验证这一猜想之前,我们简单介绍一下SNAT是如何在LB端工作的。

探索 | 一个有趣的TCP链接问题

如上图所示,在LB的内存中包含了一个连接表,它记录了Client-VIP连接和SNAT-PoolMember连接之间的映射关系。在F5的FastL4模式下,LB仅更改了src_ip,src_port,dst_ip和dst_port,然后将其发送到另一个连接端。

TSval记录了每个TCP包的时间戳,由于TSval是基于客户端CPU时间的(客户端CPU时间不同),因此来自不同客户端的不同数据包具有不同的TSval。经过LB的SNAT转发后,就有可能发生TSval较大的包先到,从而使服务器端丢弃TSval较小的包。

Step 4.

用systemtap和TCPDUMP验证问题

我们编写了一个新的systemtap脚本,同时在CAL服务器上运行TCPDUMP,得到的结果均可以验证前文的猜测。

探索 | 一个有趣的TCP链接问题

脚本运行结果如下图所示:

探索 | 一个有趣的TCP链接问题

如下方TCPDUMP运行截图所示,在CAL服务器端口1120上运行的应用程序向LBSNATIP发送了(FIN,ACK)包,然后,LB发送了TSval为517740536的ACK包,随后,连接关闭了。

探索 | 一个有趣的TCP链接问题

几十秒后,LB使用相同的SNATIP尝试建立到同一目标IP和端口的新连接。因为先前的ACK包在18s发送,而新的SYN包在60s接收,所以间隔时间是42秒,小于60s,(u32)get_seconds()-tm->tcpm_ts_stamp

如下图所示,比较tm-> tcpm_ts(517740536)和req-> ts_recent(481284815),正如systemtap脚本的输出结果所示,两者之差大于TCP_PAWS_WINDOW。因此函数tcp_peer_is_proven返回false,内核丢弃此SYN包。

探索 | 一个有趣的TCP链接问题

总结

由于TSval是基于客户端CPU时间运行的,不同客户端的CPU时间可能并不相同,因此如果流量通过负载均衡器,内核可能会意外丢弃某些连接。为了避免这一问题,应在SNAT网络中禁用net.ipv4.tcp_tw_recycle。

后续:自Linux4.1以来,该功能已在内核中完全删除。

Reference

1.Dropping of connectionswith tcp_tw_recycle

2.RFC 1323

3.[net-next,2/2] tcp:removetcp_tw_recycle

4.net.ipv4.tcp_tw_recycle hasbeen removed from Linux 4.1 - kernel git

5.Coping with the TCPTIME-WAIT state on busy Linux servers

6. SYN packet handling in the wild

7. K7820:OverviewofSNATfeatures

您可能还感兴趣:

文章版权及转载声明:

作者:上网导航本文地址:https://www.90xe.com/post/469.html发布于 2023-07-14
文章转载或复制请以超链接形式并注明出处技术导航

分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏