阅读视图

发现新文章,点击刷新页面。
🔲 ☆

学习网络的一点经验

在网络抓包系列的最后,再来说一下网络学习的一些经验。毕竟,能通过抓包来解决问题的前提是具备网络协议的知识,不然的话 Wireshark 和 tcpdump 用得再熟练也看不懂抓到的包。

以下是我觉得一些比较好的学习方法,我从中获益良多。

和朋友讨论学到的东西

学到了一个新的知识点或者新的协议,可以尝试解释给朋友或者同事听。比如在吃饭的时候,「嘿,你知道吗?TCP 三次握手的第三个包实际上是可以携带数据的!」然后他们会想这个问题,问你「要是有些 Server 不能处理带数据的第三个包怎么办?」这样,你就要重新思考你学的知识,看它是否考虑周全。教是最好的学习方法。如果没有朋友的话,可以考虑写一个博客(像我一样?呵呵)。

认识实际的网络,也可以从公司的网络结构开始。平时总结一下自己的问题,多阅读一些内部的文档。在内部 traceroute 跑一下,看看每一个 hop 都是什么。找时间请网络团队的同事吃饭,然后问他们你的问题。

举一反三

要学会提问。网络协议的目的一部分是传输数据,更重要的,它需要处理各种异常情况,保证即使出现各种意外,也能尽最大努力工作。所以,我们在学习的时候可以经常问题自己:如果这时候出现 xx 会怎么样呢?

问自己问题,然后思考,尝试给自己解答。在思考的过程中,会产生很多解决方案,大部分可能都是有问题的,然后找到其中的问题,推翻自己的方案。比如,网络为什么要分开三层和二层?这个世界上只有 IP 层,没有链路层行不行?或者只有链路层,不要 IP 层了行不行,整个世界都是一个「大二层」,会有什么问题?

网络相关的知识常常是零碎散乱。我的经验是,不要一开始就跳到兔子洞里面去。面对一个新的概念的时候,可以这样来入门。举个例子说,比如 SOCKS5 协议:

  • 第一步是问:「这个东西是来解决什么问题的?」这个问题必须始终记在心里的,如果搞不清楚,后面会有更多的困惑。
  • 第二步,可以自己想出来一种方案来解决这个问题。方案一开始不必完美,只要解决问题即可。很多方案就是这样设计出来的,现有一个简单的方法,再想想有没有什么缺陷,然后试图优化方案来解决缺陷。
  • 如果觉得自己的方案应该没有问题了,就可以进行第三步了,去深入理解 SOCKS5 协议。可以直接去读 RFC1,不要害怕,RFC 读起来没有那么难!阅读 RFC,可以和自己的方案做对比,看看有哪些问题是还没有想到的。

其实我觉得,网络协议的设计在最开始的时候考虑并没有很周全,比如 TCP 的一些问题,HOL Blocking;比如 OSPF 协议的奇怪名字 NSSA 之类的。感觉是设计出来之后,然后发现在现实中会有问题,就会在给原来的东西打上补丁。

研究网络协议

很多网络协议设计的是很美的,我喜欢那些简单又能解决问题的协议。比如 VRRP,只有一种数据格式包。像 TCP,DHCP 这种就复杂许多,它们的魅力在于解决了复杂的问题,适应各种复杂的环境。

了解网络协议除了按照上面的方法自己来挑战设计,还可以格物致知,看协议的每一个字段,搞清楚这些字段都在解决什么问题。一般每一个字段都是为了解决某种问题或需求而存在的。

面对复杂的协议的时候,把它拆成一个一个小的部分,单独攻破。比如 BGP,状态,选路之类的太复杂了。方法就是 break down,一个一个来。

光学习 Wireshark 这种工具是不行的,工具是围绕网络协议设计出来的,网络协议设计出来是为了解决真实的问题的。所以学习网络协议,它们解决问题的方法,才是主要的。另外,只有懂网络协议才能用好工具。比如,精通 ICMP 和 IP 的 TTL 设计,才能精通 traceroute 的使用。

多读书

像 TCP 的书从协议设计到实现,有数不清的书来介绍。读一本是不够的,因为对于网络协议,不同的作者有不同的理解,有不同的比喻。读书就像和作者聊天一样,和不同的人探讨自己对一个东西的认识,有助于加深理解。

上面通过自己设计协议来理解协议的方式,就是 Computer Networking: A Top-Down Approach2 这本书作者用的,作者用从零开始设计 TCP 的方式来教授为什么 TCP 是今天这个样子的。

同一本书也可以读第二遍,所谓书读百遍,其义自见。

PS:不要看国内的大学讲课视频

如果一个视频明显是那种中国大学的讲课录屏,基本就没有必要看了。这些视频通常知识和现实脱节,讲的内容很多也在现实中见不到,照本宣科,避重就轻。除了磨灭读者的兴趣,把有趣变成枯燥,就没什么价值了。没有兴趣和热情,就学不好。


说到最后,兴趣是最好的老师,对我来说,根据自己的知识和工具拨开迷雾,解决一个一个的问题,是再有意思不过的了。每个人会在人生的一个时间,发现这个世界不是公平的。但是在计算机的世界里,是很公平的,多花一点时间,多思考一些,就会多一分收获,它与天分无关。技术会过时,自己辛苦习得的技能也可能被 AI 轻而易举取代,但是曾经在学习和进步中体会到的乐趣是真实存在的,那些经验运用到新的技术中也多少是有所帮助的。祝愿读者在自己的领域体会到平静和乐趣。


==抓包破案录==

这篇文章是抓包破案录系列文章(之前叫做《计算机网络实用技术》,后来改名了)中的一篇,这个系列正在连载中,我计划用这个系列的文章来分享一些网络抓包分析的实用技术。这些文章都是总结了我的工作经历中遇到的问题,经过精心构造和编写,每个文件附带抓包文件,通过实战来学习网络抓包与分析。

如果本文对您有帮助,欢迎扫博客右侧二维码打赏支持,正是订阅者的支持,让我公开写这个系列成为可能,感谢!

如果您正在阅读的是题目类的文章,这个目录内容正好用来隔离其他读者的评论。读完题目可以稍作暂停,进行思考,继续向下滑动,可能会被其他的读者剧透答案。

没有链接的目录还没有写完,敬请期待……

  1. 序章
  2. 抓包技术以及技巧
  3. 理解网络的分层模型
  4. 数据是如何路由的
  5. 网络问题排查的思路和技巧
  6. 不可以用路由器?答案和解析
  7. 网工闯了什么祸?答案和解析阅读加餐!
  8. 重新认识 TCP 的握手和挥手答案和解析
  9. 3.5 秒初始延迟问题答案和解析
  10. 网络断断续续……答案和解析
  11. 延迟增加了多少?答案和解析
  12. 压测的时候 QPS 为什么上不去?答案和解析
  13. TCP 下载速度为什么这么慢?答案和解析
  14. 请求为什么超时了?答案和解析
  15. 0.01% 的概率超时问题答案和解析
  16. 后记:学习网络的一点经验分享
与本博客的其他页面不同,本页面使用 署名-非商业性使用-禁止演绎 4.0 国际 协议。
  1. 如果你感兴趣的话,socks5 的 RFC 是 https://datatracker.ietf.org/doc/html/rfc1928 ↩
  2. https://www.amazon.sg/Computer-Networking-Top-Down-James-Kurose/dp/0133594149 ↩
🔲 ☆

ARP 问题诊断

这是 网络断断续续 一文的答案。

答案是,在同一个子网内,同一个 IP 地址分配到了 2 个不同的设备上。

对于这种时而正常时而异常的「幽灵问题」,在没有思路的时候,可以通过对比的方法来寻找线索。

有的时候 TCP 能够连通,有的时候无法连通。那么正常的 TCP SYN 包和异常的 TCP 包之间肯定是有什么字段是不一样的。当然,也有可能 SYN 包一模一样,问题出在了其他的网络设备上或者 TCP 的另一端。但是既然题目出给读者了,那么问题的根源肯定是隐藏在抓包文件里面。

通过对比来寻找答案

正常的 TCP 连接可以完成 TCP 的握手和挥手。

异常的 TCP 连接,发出去的 SYN 直接收到了 RST。

通过对比可以发现,两个 SYN 包的 Dst MAC 是不一样的。

通过推理得出答案

如果不通过对比的方法,顺藤摸瓜,可以用下面的思路。

首先,Src IP 和 Dst IP 分别是 10.210.151.187 和 10.210.151.90,很大概率是属于同一个 /24 子网的 IP,不过要想确认的话需要看下服务器的 IP 地址是如何配置的,子网掩码是不是 /24,这点我们从给出的信息无从得知。

假设确实是属于同一个子网,那么 TCP SYN 包不经过网关,直接发给目的地址,二层的 Dst MAC 地址应该是目的 IP 的 MAC 地址。

假设不属于同一个子网,那么 TCP SYN 包经过网关,TCP SYN 包的目的地址应该是路由器的 MAC 地址。

无论是那种情况,正常情况下发送给同一个 Dst IP 的目的 MAC 应该是唯一且稳定的。通过 Conversation 统计可以看出,通讯的 IP 对只有一对,但是 MAC 的确有 2 对,这是不对的。

Statistics > conversation

原因分析

造成这种现象的原因是,IP 分配重复了,在同一个子网内,同一个 IP 地址 10.210.151.90 被分配给了多个机器。

发送 TCP 包之前,需要知道对应的 Dst IP 地址的 Dst MAC 地址,怎么知道呢?Src 机器会在整个子网内广播 ARP 询问,持有这个 IP 的机器会回复 ARP。现在子网内有两个相同的机器是相同的 IP 地址。这两台机器的 IP 地址一样,MAC 地址不一样。如果我们现在 arping 10.210.151.90 ,会得到如下的回复:

$ arping -c 3 10.210.151.90
ARPING 10.210.151.90
42 bytes from 5a:65:98:0c:82:02 (10.210.151.90): index=0 time=944.055 usec
42 bytes from c2:10:70:f2:ae:ab (10.210.151.90): index=1 time=997.915 usec
42 bytes from 5a:65:98:0c:82:02 (10.210.151.90): index=2 time=13.799 usec
42 bytes from c2:10:70:f2:ae:ab (10.210.151.90): index=3 time=109.388 usec
42 bytes from 5a:65:98:0c:82:02 (10.210.151.90): index=4 time=6.670 usec
42 bytes from c2:10:70:f2:ae:ab (10.210.151.90): index=5 time=48.983 usec

--- 10.210.151.90 statistics ---
3 packets transmitted, 6 packets received,   0% unanswered (3 extra)
rtt min/avg/max/std-dev = 0.007/0.353/0.998/0.438 ms

可以看到,我们发出去 3 个询问,却收到 6 个回复。说明每一个询问得到了 2 个答案。(其实,在诊断和验证这个问题的过程中,最快的方式就是用 arping 来测试一下,而不是抓包来分析。但是这里我们主要讨论抓包技术,所以拿来当作一个分析的案例。)

那么 Src 收到两个 ARP 应答,会以哪一个为准呢?答案是以先收到的为准。

$ ip nei show
10.210.151.90 dev h2-eth0 lladdr 5a:65:98:0c:82:02 REACHABLE

但是 ARP 请求广播出去,这两个 ARP 应答哪一个先到是无法确定的,有的时候 5a:65:98:0c:82:02 先到,有的时候 c2:10:70:f2:ae:ab 先到,所以发送给 10.210.151.90 的包,有的时候发给了 MAC 地址为 5a:65:98:0c:82:02 的机器,有的时候发送给了 MAC 地址为 c2:10:70:f2:ae:ab 的机器。

补充一点,在实际的问题排查过程中,我们的 TCP 连接测试失败,最好的排查方法就是去对端进行抓包,看一下对端的机器是否收到了 SYN 包。以及在实际的现象中,客户端收到了 Connection refused ,通常意味着收到了 RST 报文(可能来自真实对端,也可能来自其他设备)。我们在对端抓包的过程中会发现即没有收到 SYN,也没有发出 RST,这说明包到别的地方去了。进而,我们可以发现字网内还有一个「李鬼」的问题。

那么,为什么 ping 的测试完全正常呢?

因为 ICMP 是无连接协议,,ping 的 ICMP 协议回复,是由 Kernel 负责的,所以无论 ICMP 包发送到哪一个机器上,由于它们都设置了这个 IP 地址,所以都可以做出回复。其实抓包中的回复是来自不同的机器,只不过 ping 不知道,只要是收到了回复,就认为一切正常。

可以把 Src MAC 地址添加到 Column 显示,就可以发现其实 ping 的回复来自不同的设备。

最后一个问题,为什么会有 IP 重复的问题呢?

DHCP 可以用来动态分配 IP 地址给设备,但是一般只用于客户端,比如办公网、家用网络中的终端设备,这些设备一般作为连接的发起方,不需要 listen 一个固定的 IP 地址,IP 地址的动态变化对它们影响不大。但是在 IDC 的网络中,每一个服务器的软件都需要固定的 IP 地址,一般不用 DHCP 来动态分配,而是用中心化的 IPAM 系统1追踪 IP 地址的分配情况。如果里面记录的地址不正确,比如,一个地址已经在使用中了,但是并没有在 IPAM 记录,就造成 IP 地址重复的问题。

  1. https://en.wikipedia.org/wiki/IP_address_management ↩

==抓包破案录==

这篇文章是抓包破案录系列文章(之前叫做《计算机网络实用技术》,后来改名了)中的一篇,这个系列正在连载中,我计划用这个系列的文章来分享一些网络抓包分析的实用技术。这些文章都是总结了我的工作经历中遇到的问题,经过精心构造和编写,每个文件附带抓包文件,通过实战来学习网络抓包与分析。

如果本文对您有帮助,欢迎扫博客右侧二维码打赏支持,正是订阅者的支持,让我公开写这个系列成为可能,感谢!

如果您正在阅读的是题目类的文章,这个目录内容正好用来隔离其他读者的评论。读完题目可以稍作暂停,进行思考,继续向下滑动,可能会被其他的读者剧透答案。

没有链接的目录还没有写完,敬请期待……

  1. 序章
  2. 抓包技术以及技巧
  3. 理解网络的分层模型
  4. 数据是如何路由的
  5. 网络问题排查的思路和技巧
  6. 不可以用路由器?答案和解析
  7. 网工闯了什么祸?答案和解析阅读加餐!
  8. 重新认识 TCP 的握手和挥手答案和解析
  9. 3.5 秒初始延迟问题答案和解析
  10. 网络断断续续……答案和解析
  11. 延迟增加了多少?答案和解析
  12. 压测的时候 QPS 为什么上不去?答案和解析
  13. TCP 下载速度为什么这么慢?答案和解析
  14. 请求为什么超时了?答案和解析
  15. 0.01% 的概率超时问题答案和解析
  16. 后记:学习网络的一点经验分享
与本博客的其他页面不同,本页面使用 署名-非商业性使用-禁止演绎 4.0 国际 协议。
🔲 ☆

网络抓包的技巧

虽然这个系列的文章都是聚焦于如何通过分析网络抓包文件,结合网络知识,来解决实际的问题的,但是分析之前的步骤——抓包,也是同样重要!很显然,如果不会抓包,那么网络分析去分析什么呢?

抓得一手好包也是很厉害的!笔者遇到过很多次情况,虽然我们无法直接定位根因,但是同事能够精准地捕获到问题的现象,把问题描述给相关的网络专家,传给他们抓包文件,专家一看到准确的抓包文件,就可以很快解决问题了!

可惜的是,抓包的技巧无法像网络分析那样可以通过文章来出谜题,来让读者小试牛刀。所以,这篇文章就来写一下一些常用的抓包方式和技巧,希望能补齐这一块内容。

Tcpdump

tcpdump 命令是我们最常用的抓包工具了1

tcpdump -i eth0 icmp and host 1.1.1.1

这个命令就可以抓取到所有通过 eth0 去 ping 1.1.1.1 这个地址的包。

-i eth0 的意思是抓取指定的 interface,如果不指定,tcpdump 会默认选择一个。但是推荐每次都指定好这个参数,这样就没有不确定性了。如果使用 -i any 就可以抓取所有常规端口(文档的原文是 all regular network interfaces),但是什么属于「常规端口」就取决于操作系统的实现了。所以,建议也是如果要抓取多个 interface 来分析的话,就多开几个 tcpdump 进程,这样更加稳定一些。

这个参数非常有用,比如,在定位 ARP 问题的时候,我们需要确定每一个物理接口收发 ARP 的情况,就可以开多个进程分别 dump 每一个 interface 的网络;在定位 Linux 网络栈不通的情况时2,比如有 macvlan,vlan,veth 等复杂的 driver,可以用 tcpdump 对每一个接口 dump,看下包丢在哪里。

icmp and host 1.1.1.1 这个就是包过滤的表达式了,icmp 表示只抓取 icmp 协议,host 1.1.1.1 表示只抓取 src ip 或者 dst ip 是 1.1.1.1 的包。这种包过滤表达式其实是 pcap-filter(7)3 提供的,所以要想看语法是怎么定义的,看 pcap-filter 的文档就可以了。pcap-filter 支持的语法很灵活,能做的事情很多,基本上想抓什么样的包都可以写出来。但是我们没有必要把所有的语法都记住,因为常用的抓包都是比较简单的。可以找一个 tcpdump exmaple4 看一下,基本就够用了。其次,我们一般不会直接从 tcpdump 就分析出来问题原因,所以这个语法最重要的作用是把我们想要的包抓到,然后为了抓包性能更高,抓包文件更小,我们想要对抓包定义的更精确一些。其实,多抓一些包也没有什么问题,如果不确定怎么过滤出来 TCP SYN+ACK 的包,那不妨就把所有的 SYN 包全抓到,然后再用 Wireshark 这种工具来分析吧。最后,我们现在有 AI 了,用 AI 来写 pcap-filter 也是一个不错的方法,因为这种语法难写,但是很容易验证正确性。

Tcpdump 一些常用的其他参数如下:

  • -n 不解析主机名和端口号,保留原始的数字
  • -v, -vv, -vvv v 越多表示输出的信息越详细
  • -c 5 表示抓到 5 个包之后就退出
  • -e 显示二层的 link layer header,这样就可以看到 MAC 地址了
  • -Q 可以指定抓包方向,可以选的有 in, out, inout
  • -A 可以展示包的内容,tcpdump 默认是只根据不同的协议展示 header 信息的。在线上排查问题的时候,我们往往需要通过特殊请求的关键字来定位到单个请求的情况进行排查,这样 -A 展示出来包的内容就格外有用。
通过 -A 参数来抓取特定的 HTTP 请求

这里分享一个特殊的技巧,就是发标记请求来定位问题。比如 A 通过 B 代理发请求给 C,现在网络不通,我们要定位 B 收到了请求没有,才知道是 B 的问题还是 C 的问题。但是 B 本身就有很多线上流量,怎么知道 A 发送的请求到达 B 了没有呢?我们可以在 B 进行 tcpdump:tcpdump -i eth0 tcp | grep asdf123 -A 10,然后我们从 A 发送一个请求:curl http://host-C.com/asdf123asdf123 就是我们在请求里面放上的标记,如果 B 能够正常转发,我们就可以 match 到这个请求。当然了,这种技巧只适用于 HTTP 这种明文协议。

Wireshark 离线分析

有些问题很难直接在 tcpdump 的终端分析出来问题,比如涉及 sequence number 分析的,重传分析之类的,我们需要人工对比 seq number,真是一项费眼睛的工作!所以如上所说,我们也经常在机器上用 tcpudmp 抓包保存成 .pcap 文件,下载到本地用 Wireshark 分析。Wireshark 就可以自动根据 sequence number 告诉我们重传等信息了!

Wireshark 可以展示出来 Dup ACK 和 Retransmission 等信息

具体的操作方式是,用 tcpdump -i eth0 -w file.pcap icmp 来进行抓包,-w file.pcap 表示把抓包文件保存为 file.pcap,抓包结束后,就可以把这个文件用 rsync 或者 scp 下载到本地,用 Wireshark 打开了。

.pcap 文件是一种标准的二进制抓包文件5,很多抓包分析工具都支持这种格式的解析,比如 tcpdump, wireshark, scapy 等等,如果想写代码进行更加定制化的分析,也可以用已有的库6解析,就如同用 json 库来解析 json 文件一样。

使用 wireshark 的命令行工具 tshark 可以解析二进制 pcap 文件到 json 格式

使用 -w 写入文件的时候有一个小问题,就是 tcpdump 原本的到终端的输出没有了。有两种方式可以解决,第一种是用 tcpdump 自带的 --print 功能:

tcpdump -i eth0 -w file.pcap --print

--print 会让 tcpdump 把内容输出到屏幕,即使当前使用了 -w 参数。

第二种就是用 tee,在写入文件的同时,也写入到 stdout。

tcpdump -i eth0 -U -w - | tee test.pcap | tcpdump -r -

其中,第一个 tcpdump 把抓包文件写入到 stdout(-w stdout,注意其中的 -U 表示按照 packet buffer,即来一个 packet 就输出一个到 stdout,而不是等 buffer 满了才进行输出),然后 tee 这里做了分流,把 stdin(tcpdump 的 stdout)同时输出到文件和 stdout。由于这里的 stdout 是 tcdpump 输出的二进制抓包内容,所以我们需要再用 tcpdump 解析这个二进制内容,-r - 表示从 stdin 读入。

还有一个技巧是 -s 参数,默认情况下 tcpdump 会保存所有抓到的内容,但是在分析某些问题的时候,尤其是 TCP 性能问题,我们其实不需要 TCP 传输的 payload 内容,只看 TCP 包的 header(序列号部分)就知道传输的速度了,所以可以用 -s 40 来只抓取前 40 个 bytes,有了 IP header 和 TCP header,就足够分析了。(如果担心有 TCP option 的存在,可以用 -s 54

其他的一些经验

知道包是从哪里抓到的,很重要。在排查问题的时候,拿到抓包文件,应该第一时间确认抓包的位置。否则,就可能连自己看到的问题是现象还是根因都分不清楚。建议在复杂的结构中画一个拓扑图来对照分析,在定位 Linux 网络栈的问题时,如果接口拓扑非常复杂,也建议画一个拓扑图来分析。

可以从网络的多端抓包对照分析。发送端的抓包不一定等于接受端,尤其分析 TCP 问题的时候。可以同时在发送端和接收端进行抓包,然后对照分析。

在使用 tcpdump 的时候,要尤其注意,我们抓到的包已经经过了网卡驱动的处理,网卡驱动经常会帮 CPU 做一些 offload 的工作,比如把可能因网卡的 GRO/LRO 等特性,导致多个小包在抓包时被合并为一个较大的数据包,或者网卡帮助卸载了 vlan tag 等,我们用 tcpdump 抓到的包不一定是真正在网络上传输的包7。要格外注意。

注意抓包不要抓重。比如有人很喜欢用 tcpdump -i any ... 抓全部的包回来慢慢分析。然后下载下来抓包文件就吓坏了——重传率高达 50%!

抓包抓重了的情况

在 Linux 中的网卡配置有 slave 和 master 的时候很容易发生这种情况,比如有 bonding 配置8-i any 会从 slave 抓包包,从 master 又抓到一次,然后在 Wireshark 看来,所有的包都被重传了。实际是同一个包先后经过 slave 和 master 而已。

抓包的时候最好把相关 host 的 ICMP 协议包也一起抓了。因为 ICMP 是重要的 control message,TCP 在传输的时候,不光有 TCP 协议,可能还会用 ICMP 协议来传递一些信息。比如 PMTUD9,以及之前遇到过的这个问题10,都是涉及到 ICMP 包。如果只按照 TCP 协议来抓包,那这个重要的信息就错过了。

SPAN 交换机抓包和RSPAN 远程抓包

除了我们熟悉的 Linux 抓包,其实网络设备上也可以抓包的。我们一般叫它「端口镜像」技术,故名思义,原理就是把网络设备的一个端口的流量全部复制到另一个端口,而另一个端口连接的就是我们的抓包程序。

SPAN 原理,图来自 Cisco
  1. 文档的主页:https://www.tcpdump.org/manpages/tcpdump.1.html ↩
  2. Keepalived 脑裂问题排查 ↩
  3. pcap-filter 文档在这里:https://www.tcpdump.org/manpages/pcap-filter.7.html ↩
  4. 比如这一个:https://danielmiessler.com/blog/tcpdump ↩
  5. IETF 的文件规范定义:https://www.ietf.org/archive/id/draft-gharris-opsawg-pcap-01.html ↩
  6. Python 可以使用 scapy (https://scapy.readthedocs.io/en/latest/usage.html#reading-pcap-files)读取 pcap 文件,golang 可以使用这个库进行解析:https://pkg.go.dev/github.com/google/gopacket/pcap ↩
  7. 参考 有关 MTU 和 MSS 的一切 一文中,「道理我都懂,但是我的抓的包怎么大??」 ↩
  8. 数据中心网络高可用技术之从服务器到交换机:active-backup ↩
  9. 真实世界中的 PMTUD ↩
  10. 由 ICMP Redirect 消息引起的丢包问题排查 ↩

==计算机网络实用技术 目录==

这篇文章是计算机网络实用技术系列文章中的一篇,这个系列正在连载中,我计划用这个系列的文章来分享一些网络抓包分析的实用技术。这些文章都是总结了我的工作经历中遇到的问题,经过精心构造和编写,每个文件附带抓包文件,通过实战来学习网路分析。

如果本文对您有帮助,欢迎扫博客右侧二维码打赏支持,正是订阅者的支持,让我公开写这个系列成为可能,感谢!

没有链接的目录还没有写完,敬请期待……

  1. 序章
  2. 抓包技术以及技巧
  3. 理解网络的分层模型
  4. 数据是如何路由的
  5. 网络问题排查的思路和技巧
  6. 不可以用路由器?
  7. 网工闯了什么祸?
  8. 网络中的环路和防环技术
  9. 延迟增加了多少?
  10. TCP 延迟分析
  11. 压测的时候 QPS 为什么上不去?
  12. 压测的时候 QPS 为什么上不去?答案和解析
  13. 重新认识 TCP 的握手和挥手
  14. 重新认识 TCP 的握手和挥手:答案和解析
  15. TCP 下载速度为什么这么慢?
  16. TCP 长肥管道性能分析
  17. 请求为什么超时了?
  18. 请求为什么超时了?答案和解析
  19. 后记:学习网络的一点经验分享
与本博客的其他页面不同,本页面使用 署名-非商业性使用-禁止演绎 4.0 国际 协议。
🔲 ⭐

TCP 延迟分析

本文是对《延迟增加了多少?》一文的答案和分析。

总延迟应该是 900ms 左右。

Ping 的延迟指的是 RTT, Round Trip Time. 即一个包发过去,对方发一个包回来,总延迟是 200ms。一种误解是认为 ping 测得的延迟是 200ms,所以一个请求发过去是 200ms,响应发回来是 200ms,总延迟是 400ms。如果仔细想一想的话,我们在发送端测量延迟的时候,没有办法只测量一个包从发送端达到接收端的延迟。除非是让接收端在回复的时候记录收到包的时间?但是发送端和接收端的时钟可能不一致,如果精确测量的话,协议上就要依赖不同的机器时钟对齐。直接让总时间除以 2?这也意义不大,因为包去和回的路线不一定一样,延迟也不一定是一半一半。所以我们在讨论延迟的时候,都是默认 RTT

TCP 握手的延迟是 1 个 RTT,即 200ms。这里也有很多人会有一个误解,就是认为「TCP 是三次握手,所以握手带来的延迟是 1.5 RTT」。这个误解是因为教科书的 TCP 序列图太迷惑了,看起来像是握手需要发送 3 个包,之后才能发送数据。实际上,在握手阶段,第三个包 ACK 发出之后,发送端直接开始发送数据。即,客户端发送 SYN 建立握手,收到 SYN+ACK,消耗了 1 个 RTT;发送端随即发送 ACK,然后直接进入数据发送阶段,开始发送数据。所以握手阶段第三个 ACK 包是不会带来延迟的

很多教材的 TCP 握手序列图是这样
但其实应该是这样,在第三个 ACK 发送之后直接开始发送数据

上文题目提到,请求的大小是 16KiB,这里经常出现的误解是:「一个 Frame 的 MTU 是 1500bytes,减去 20 bytes IP header 和 20 bytes TCP header,一个包携带的实际数据是 1460 bytes,所以 16KiB 请求传输完成是 16KiB/1460 bytes 个 RTT。」这也是被教科书常用的序列图迷惑了,TCP 传输中,发送端并不是发送一个包,等待 ACK,发送下一个包……而是直接传输很多包,接收端可以直接用一个 ACK 去 ACK 多个包。发送端是「一组包一组包地发送」,而不是「一个包一个包地发送」。

错误的序列图:每一个数据都等待 ACK
实际上一直发送数据,直到达到 rwnd 或者 cwnd 的瓶颈

那么一下子可以发送多少个包呢?发送端可以一下子把 16KiB 的数据都发送完吗?这里涉及到 TCP 的拥塞控制了。为了避免过载接收端和中间链路上的路由器等设备,TCP 发送端发送出去但是未确认的数据会保持在接收端窗口 (rwnd)和拥塞控制窗口之内 (cwnd)。接收端的窗口一般不是瓶颈,所以这里忽略不讨论。cwnd 在 Linux 的初始值是 10,即 TCP 连接建立之后,会一下子发送 10 个 MSS 的数据,即 1460 bytes * 10 大约是 14.6KiB 的数据。然后会等待接收端发送回来 ACK,再开始下一轮数据的发送,并且逐渐增大 cwnd。对于响应,同理,这时候服务 B 的服务器变成了发送端,也是需要发送两轮数据。更详细的解释可以阅读这篇:《TCP 拥塞控制对数据延迟的影响》。

最后,来到了四次挥手。这里的误解是 TCP 断开连接 4 次挥手需要花费 2 个 RTT。实际上,断开连接的过程是不产生耗时的,因为在 TCP 断开连接之前,应用的请求已经发送完成,响应也已经收到,kernel 已经将收到的数据送给了用户态,用户态的程序已经继续运行了。即使应用调用 close(), 也是直接返回,kernel 再慢慢处理关闭连接的过程。所以断开连接是 kernel 来做的「收尾工作」,不会贡献请求处理的延迟。

综上,总结一下,实际耗时是 900ms,其中:

  • TCP 建立连接需要 1 个 RTT;
  • 如果是 HTTP 请求很小,响应也很小,那么请求和响应需要耗费 1 个 RTT;
  • 但是 HTTP 请求很大,因为 cwnd 的限制,需要额外耗费 1 个 RTT 来传输;
  • 同理,响应也很大,也需要额外花费 1 个 RTT;
  • 服务端程序处理需要花费 100ms,保持不变;

最后是 200ms * 4 个 RTT + 100ms = 900ms;

再留一个问题给读者:你知道应该如何优化,让这个请求耗费的延迟最小吗?(分析一下最小延迟是多少,一个 RTT 用来传输数据是比不可少的,服务端的 100ms 也无法节省,所以最小延迟是 300ms,如何从 900ms 优化到 300ms 呢?)

提示

==计算机网络实用技术 目录==

这篇文章是计算机网络实用技术系列文章中的一篇,这个系列正在连载中,我计划用这个系列的文章来分享一些网络抓包分析的实用技术。这些文章都是总结了我的工作经历中遇到的问题,经过精心构造和编写,每个文件附带抓包文件,通过实战来学习网路分析。

如果本文对您有帮助,欢迎扫博客右侧二维码打赏支持,正是订阅者的支持,让我公开写这个系列成为可能,感谢!

没有链接的目录还没有写完,敬请期待……

  1. 序章
  2. 抓包技术以及技巧
  3. 理解网络的分层模型
  4. 数据是如何路由的
  5. 网络问题排查的思路和技巧
  6. 不可以用路由器?
  7. 网工闯了什么祸?
  8. 网络中的环路和防环技术
  9. 延迟增加了多少?
  10. TCP 延迟分析
  11. 重新认识 TCP 的握手和挥手
  12. 重新认识 TCP 的握手和挥手:答案和解析
  13. TCP 下载速度为什么这么慢?
  14. 后记:学习网络的一点经验分享
与本博客的其他页面不同,本页面使用 署名-非商业性使用-禁止演绎 4.0 国际 协议。
🔲 ⭐

延迟增加了多少?

小周(就是你!)所在的团队管理着一个服务 A,这个服务 A 需要访问服务 B 的 HTTP 接口。服务 A 和服务 B 部署在同一个 IDC 中,所以延迟很低,可以忽略不计。服务 B 处理请求需要花费 100ms,所以一个 HTTP 请求的总延迟大概是 100ms。

服务A在同一个 IDC 中请求服务 B

最近由于合规的要求,服务 B 需要迁移到另一个 IDC 中,物理延迟会上升。迁移之后,如果从服务 A 的 IP 去 ping 服务 B 的 IP,ping 显示延迟为 200ms

服务 B 迁移到了另一个 IDC,这时候 ping 是 200ms

在打开抓包文件分析之前,请问:如果服务 A 发送一个 HTTP 请求到服务 B,总延迟现在是多少?

注意:

  • TCP 需要重新建立连接
  • 请求的大小是 16KiB
  • 响应的大小是 20KiB

然后用 Wireshark 打开抓包文件,分析实际的延迟是多少?和自己的答案作对比。

提示:在分析延迟问题的时候,可以使用这里的方法,打开 Time Delta 列。

目录

这个系列正在连载中,没有链接的目录还没有写完,敬请期待……

  1. 序章
  2. 抓包技术以及技巧
  3. 理解网络的分层模型
  4. 数据是如何路由的
  5. 网络问题排查的思路和技巧
  6. 不可以用路由器?
  7. 网工闯了什么祸?
  8. 网络中的环路和防环技术
  9. 延迟增加了多少?
  10. TCP 延迟分析
  11. 重新认识 TCP 的握手和挥手
  12. 重新认识 TCP 的握手和挥手:答案和解析
  13. 后记:学习网络的一点经验分享
与本博客的其他页面不同,本页面使用 署名-非商业性使用-禁止演绎 4.0 国际 协议。
如果本文对您有帮助,欢迎打赏支持,正是订阅者的支持,让我公开写这个系列成为可能,感谢!
❌