
1. 先搞清楚一件事连通性测试到底在测什么做服务器运维或者日常写代码的人应该都遇到过这种场景手里的 Linux 机器突然连不上某个服务了可能是要拉 GitHub 上的代码仓库也可能是一个外部 API 突然超时或者是想确认 HuggingFace 那边的模型下载地址通不通。这时候直接在终端里敲 curl结果光标一闪然后就是漫长的等待最后冒出来一个Could not resolve host或者Connection timed out你就知道事情没那么简单了。我第一次碰到这种问题的时候习惯性先 ping 一下对方域名能通就觉得网络没问题不能通就觉得是对方挂了。后来踩了几次坑才明白这种简单的二分法远远不够。网络连通性其实是一个分层概念一次完整的访问请求要从你的网卡出发经过路由、运营商网络、DNS 解析、TCP 握手最后才是 HTTP 数据交互任何一个环节出问题表现都可能不一样。有些时候 ping 不通但网页能开有些时候 ping 通了但接口一直超时有些时候域名解析出来的 IP 压根不对。所以命令行里做连通性测试本质上是把这条链路拆开来一层一层验证看问题到底卡在哪。这一套方法不只对那几个目标站点有效放到任何域名、任何服务器上都适用。我后面写到的所有命令和思路都是在 Ubuntu / CentOS 这类主流 Linux 发行版上跑的用到的也都是系统自带的工具或者安装起来非常容易的软件包。这篇文章更像是我自己的排查手记把常用的几板斧整理出来像 ping、dig、nc、curl、traceroute 这些命令分别解决什么问题什么场景下用什么参数都给你捋一遍。先说结论性的经验单靠一个命令判断能不能访问是不靠谱的。我的习惯是至少做三层验证。第一层看网络通不通也就是 ICMP 能不能到第二层看域名解析对不对能不能拿到正确的 IP第三层看目标端口上有没有服务在监听能不能完成 TCP 和 HTTP 握手。三关都过了才敢说这个地址从我这个 Linux 机器上访问是正常的。这套顺序看起来简单但真能帮你省掉大量瞎猜的时间。1.1 为什么要分层看问题打个比方你要去一个朋友家拜访整个过程可以拆成有没有一条路能走到那片小区、那个小区里到底有没有这栋楼、这栋楼里朋友在不在家三个问题。对应的就是路由可达性、DNS 解析、端口服务三个层面。平时我们说的打不开网站可能是路不通也可能是楼号找错了还可能是朋友当天不在家。如果不分层排查你会一直在原地打转。比如有一次我遇到的情况是 curl 报错超时第一反应是防火墙拦截结果排查半天最后发现是 DNS 解析到了一个已经废弃的旧 IP数据包全发到不知道哪里去了。这种问题用 ping 是看不出来的因为 ping 走得是域名解析后的地址你把域名的解析记录换掉之后ping 工具本身不会告诉你这件事对不对。分层排查让问题的定位边界变得非常清晰网络层的问题用 ping/traceroute 看DNS 层的问题用 dig/nslookup 看传输层的问题用 nc/telnet 看应用层的问题再看 curl 的返回码。每一层排查完能排除一部分嫌疑没准问题范围就从一个面缩小到一个点。1.2 一次完整请求经过哪些环节我简化一下这个过程。你在终端里输入curl https://example.com大概经历这么几步先是检查本地缓存有没有这个域名的记录没有就去问系统配置的 DNS 服务器得到 IP 之后系统查路由表找到出口网卡然后发出 TCP SYN 包跟目标服务器的 443 端口建立连接连接建立后再通过 TLS 握手协商加密参数最后才发送 HTTP GET 请求。每一层都有对应的超时时间和错误信息。这就是为什么同样的访问不了不同环节错误信息完全不同。ping: unknown host说明域名解析就失败了Destination Host Unreachable说明路由层有问题No route to host说明对方网络或防火墙直接把你拒了Connection refused则说明网络层通、但目标端口没有服务在监听。这些信息不用猜命令行工具全都帮你打出来了关键是你得知道它们分别代表什么。接下来几节我按照从下往上的顺序把每个环节的命令和典型输出过一遍。2. 第一板斧ping 和 ICMP 能告诉你什么2.1 ping 不只是通不通ping 是大家最熟悉的网络命令它发送 ICMP Echo 请求然后等目标回一个 Echo Reply通过往返时间来估算网络的响应速度。动手起来很简单ping -c 4 example.com这里-c 4表示只发 4 个包就停下来避免一直刷屏。输出里最重要的几个信息icmp_seq是包序号如果有丢包会看到序号跳跃ttl是数据包经过的跳数上限常见初始值是 64 或 128看它也能大概判断目标系统类型time是往返延迟稳定在几十毫秒内说明链路状态不错如果波动很大那可能中间线路质量有问题。我自己的习惯是先 ping 10 个包而不是 4 个。因为 4 个包的样本太少偶尔丢一个包说明不了什么10 个包能看出丢包率的趋势。命令是这样的ping -c 10 -i 0.2 example.com-i 0.2把发包间隔改成 0.2 秒10 个包两秒左右就测完了。如果丢包率是 100%那就是完全不通丢包率在 20% 以下可能是线路抖动丢包 50% 以上基本就是中间链路拥堵或者被限速了业务访问的体感会非常差。2.2 当 ping 不通的时候别急着下结论有个非常常见的误区是ping 不通就觉得目标站点一定挂了。实际上很多服务器出于安全考虑直接在防火墙层丢弃了所有 ICMP 请求你 ping 不通它但它的 HTTP 服务完全正常。我见过有人拿着ping 不通的结论报故障结果人家服务端所有端口都是监听的业务跑得好好的纯粹是 ICMP 被禁了。反过来也一样即使 ping 通了也不代表应用层没问题。ICMP 和 TCP 是完全不同的协议路径上的防火墙、负载均衡设备完全可能放行 ICMP 但限制特定端口。所以说 ping 的结果只能证明网络层到目标主机这一跳是通的真正的业务能不能访问还得继续往下测。另外ping 的时候如果出现Destination Host Unreachable通常说明本地路由表里没有到达目标网段的路由或者下一跳设备通知你说这个主机不在线。这时候就该用ip route看一下默认路由是不是正确ip route show我遇到过一台新装的机器网络配置文件里忘填网关结果内网 IP 能通、外网一律 unreachable查了半天才发现是默认路由缺失。这种问题纯靠 ping 目标网站是看不出来的先看路由表反而一分钟就定位了。2.3 用 traceroute 看看到底卡在哪一跳单看 ping 只能知道通或不通想知道数据包走到哪里断了得上 traceroute。它利用 ICMP 包的 TTL 逐跳递增机制让沿途每一台路由器都先给你回一个超时消息以此画出完整的路径。traceroute -n -T -p 443 example.com-n表示不做反向域名解析否则每一跳都要去解析服务器名字速度会慢很多-T表示使用 TCP SYN 包探测而不是默认的 UDP 包-p 443指定目标端口因为很多中间设备对非标准端口的 UDP 包很不友好用 TCP 443 探测能更真实地反映实际业务流量走的路径。输出里每一行就是一个跳点如果中间某个跳点一直显示* * *不代表一定断了因为很多路由器的 ICMP 响应策略就是静默丢弃只有连续多跳都超时同时最后一跳也到不了才能下结论说路径中断。我本地做测试时有个经验前面几跳延迟正常、到某一跳突然变成几百毫秒或者不再响应后面全都超时那问题大概率出在这一跳附近的链路或机房上。3. 第二板斧DNS 解析排查域名到底解析成了什么3.1 dig 和 nslookup 的基本玩法连通性测试里最容易忽略、但最容易出问题的就是 DNS 环节。很多时候你访问不了某个域名不是网络断了而是压根没解析出对的 IP。排查 DNS 我首选dig它输出详细、信息完整比 nslookup 直观得多。dig example.com输出的重点看ANSWER SECTION里的 A 记录和 CNAME 记录。A 记录就是域名对应的 IPv4 地址如果你发现它指向一个你没见过的 IP那基本就能确定解析结果有问题。另外看Query time和SERVER字段SERVER会告诉你是哪个 DNS 服务器返回的答案这对判断本地配置有没有生效很有帮助。有些发行版默认没装 dig比如精简版 CentOS 容器里经常找不到。可以用 nslookup 替代或者直接装一下Ubuntu/Debian 上安装 bind9-dnsutilsCentOS/RHEL 上安装 bind-utils# Ubuntu / Debian sudo apt install dnsutils # CentOS / Rocky / Alma sudo yum install bind-utilsnslookup 也能应付基本的查询需求nslookup example.com但如果你要追查 CNAME 链、查指定记录类型dig 会更顺手。比如我想看一个域名是不是走了 CDN用dig example.com CNAME一眼就能看出来。常见记录的查询方式都差不多dig example.com A、dig example.com AAAA、dig example.com MX把类型换成你想查的就行。3.2 解析结果异常怎么处理DNS 解析失败经常有几种表现。第一种是SERVFAIL说明上游权威服务器暂时异常第二种是NXDOMAIN域名本身不存在检查是不是拼错了第三种是查询结果正常但 IP 不是你预期的那个这种情况多半是公共 DNS 的缓存和权威服务器不一致或者本机配置了 hosts 覆盖。本机 hosts 覆盖是个隐蔽的坑。我装修过一台机器怎么查解析都觉得不对后来想起来/etc/hosts里写了一条指向内网地址的记录把所有请求都带到测试环境去了。排查的时候记得看一眼这个文件cat /etc/hosts另外也要确认系统用的 DNS 服务器是谁配置文件是/etc/resolv.confcat /etc/resolv.conf里面nameserver字段就是系统实际查询的 DNS 服务器地址。网络管理工具比如 NetworkManager可能在网络重连后重写这个文件所以如果发现配置被改别直接硬改得去 NetworkManager 或 netplan 的配置源里改。3.3 顺便验证一下 IPv4 和 IPv6 的差别现在很多域名同时有 A 和 AAAA 记录有些环境里 IPv6 路由是残缺的导致 curl 默认先尝试 IPv6卡很久超时才回退到 IPv4。这种问题光看 A 记录查不出来你得确认本地有没有可用 IPv6 地址ip -6 addr show如果这台机器根本没有 IPv6 地址但某些工具解析到了 AAAA 记录并且在尝试连接那就是浪费时间。遇到这种情况可以在 curl 里加-4参数强制走 IPv4或者检查系统是否开启了 IPv6 解析偏好。DNS 这个环节不深入我就提一句排查连通性时别把 AAAA 给忘在脑后了。4. 第三板斧TCP 端口探测服务真在听吗4.1 nc 与 /dev/tcp 两种姿势网络层通了、DNS 也没问题下一步就是验证目标服务器的指定端口是否开放。DNS 让你找到了楼栋TCP 探测才能确认你要找的那一层有没有人。这里我推荐用nc也就是 netcat。nc -zv -w 5 example.com 443各参数含义-z表示只探测端口、不发送实际数据-v输出详细信息-w 5是超时时间5 秒后还没连上就放弃。命令执行完后如果端口开放会看到类似Connection to example.com 443 port [tcp/https] succeeded!的输出如果拒绝会看到Connection refused如果超时会卡 5 秒然后报Connection timed out。有些精简系统连 nc 都没装但没关系Linux 的 bash 自带一个黑科技/dev/tcp可以临时顶上timeout 5 bash -c echo /dev/tcp/example.com/443 echo port open || echo port closed原理很简单bash 把/dev/tcp/主机名/端口这个伪设备当作一个 TCP 连接能写进去就表示连接建立成功。配合timeout命令防止无限期阻塞这也是我在最小化容器镜像里最常用的探测方式不用额外装任何东西。4.2 端口通但业务不通问题出在哪测试端口时有个让我印象很深的案例一台服务器在海外数据中心业务方说访问他的接口偶尔超时。我 ping 延迟很低TCP 443 端口也是通的但 curl 一拉就卡。后来再用 nc 反复多测几次发现连接有时候 2 秒就成功、有时候 20 秒才成功说明链路存在严重的网络抖动或者中间设备的会话处理不稳定。这就引出一个经验端口探测不能只测一次。至少要连续测 5 到 10 次观察成功率和耗时波动。用一条小循环就能完成for i in $(seq 1 10); do nc -zv -w 3 example.com 443 21 | tail -n 1; done如果失败次数高你的业务在网络层面就有隐患这时候再怎么调应用层参数都白搭。另外telnet也可以用来探测端口telnet example.com 443连上之后会停留在空界面看到Connected to开头就说明通了Ctrl ] 再输入 quit 退出交互模式。不过 telnet 客户端不是默认必装的nc 足够用了。4.3 本地先确认是不是服务没监听排查远程之前先默认怀疑本地。很多访问不了其实是本地服务根本没起来或者端口监听在 127.0.0.1 而不是 0.0.0.0。用ss能快速看监听状态ss -lntp | grep 443-l只看监听中的 socket-n不做服务名解析-t只看 TCP-p显示对应的进程名。输出里如果看到Local Address:Port是127.0.0.1:443说明服务只在回环地址上监听外部机器必然连不上得让服务监听在0.0.0.0:443才能对外提供服务。这类问题我在自测脚本的时候经常遇到写完服务以为自己监听了一查发现绑错网卡。5. 第四板斧HTTP 层面的真实握手体验5.1 curl -I 和 -w 输出前面几层都验证过最后回到用户真正关心的 HTTP 服务上。curl 是这一层的首选工具它支持 HTTP/HTTPS、跟随重定向、自定义超时、输出详细的耗时统计几乎能满足所有应用层连通性诊断需求。最基础的命令curl -I --connect-timeout 5 --max-time 10 https://example.com-I表示只发送 HEAD 请求服务器返回响应头不会下载整个页面。这个选项对你的目标是测试是否访问正常来说非常合适不需要把主页正文都拉回来。如果服务正常你会看到HTTP/2 200或者HTTP/1.1 200 OK这样的状态行。如果想把耗时数据打出来配合-w写模板curl -o /dev/null -s -w DNS解析: %{time_namelookup}s\nTCP建连: %{time_connect}s\nTLS握手: %{time_appconnect}s\n总耗时: %{time_total}s\nHTTP状态: %{http_code}\n https://example.com-o /dev/null把响应体丢弃-s静默模式不显示进度条-w输出的各项指标能精确到秒。这是我最依赖的连通性测试命令一条命令下来DNS 解析耗时、TCP 连接耗时、TLS 握手耗时、总耗时和状态码全都有了哪个环节慢一眼就能看出来。比如time_namelookup非常长说明 DNS 那边有问题time_connect长但time_namelookup短说明网络传输路径或者目标端口层面有延迟time_appconnect长说明目标机器的 HTTPS 服务和证书校验拖了后腿。5.2 超时和重试参数建议命令行测试里最容易犯的错就是不给请求设置超时。默认情况下 curl 可以一直等下去如果目标主机路由黑洞化这个命令会在终端里挂半天。我建议所有测试命令都带上--connect-timeout和--max-time前者控制 TCP 连接阶段的超时后者控制整个请求的硬性超时一般分别设成 5 秒和 10 秒就够用。重试也是连通性测试里很实用的能力。比如你怀疑网络偶发抖动想验证是不是稳定可达可以这样写curl -s -o /dev/null --connect-timeout 5 --max-time 10 --retry 3 --retry-delay 1 --retry-all-errors -w %{http_code}\n https://example.com--retry指定重试次数--retry-delay指定两次重试的间隔--retry-all-errors表示只要是错误状态都允许重试不加这个参数的话默认只有极少部分错误会触发重试逻辑。多跑几次能看到一个稳定结果就不会被一次偶发故障误导判断。5.3 返回码和证书告警的坑curl 的退出码和 HTTP 状态码是两回事这个很多人一开始容易混淆。HTTP 状态码是服务器返回的比如 200、301、404curl 的退出码是命令本身的执行结果比如 0 表示成功6 表示无法解析主机7 表示连接失败28 表示超时。写脚本判断连通性时两个都得看curl -s -o /dev/null -w %{http_code} https://example.com echo 如果追求严谨用和||组合判断退出码curl -s -o /dev/null --connect-timeout 5 https://example.com echo 请求完成 || echo curl执行出错退出码 $?HTTPS 测试时还会遇到证书告警问题。测试环境或者自签名证书的站点curl 默认会直接报SSL certificate problem并拒绝连接。这种情况我通常分两步走先验证证书链是否正常再访问。如果只是临时验证连通性可以加-k跳过证书校验但千万别在正式脚本里这么干那等于把 HTTPS 的全部意义都扔了。先说明这只是本次测试的行为永远不要因为测试方便而放松发送真实业务请求的安全标准。6. 常见问题与排查技巧实录6.1 一张速查表解决大部分问题把前面几层排查方法汇总成一张表我在工单里排查某某站点访问不了这种问题的时候基本就按这个顺序走十分钟内能定位到具体层级。现象优先排查命令可能原因下一步处理ping 报 unknown hostdig/nslookup 查域名DNS 解析失败检查 resolv.conf、hosts 文件、上游 DNS 状态ping 报 Destination Host Unreachableip route show本地缺少路由或下一跳不可达检查默认网关和网卡配置ping 长时间 100% 丢包traceroute 分段定位中间链路中断或被丢弃联系网络管理员检查中间路径DNS 能解析但 curl 卡住nc -zv -w 5 目标IP 端口网络路径不通或目标端口被限检查防火墙规则确认服务端监听地址nc 端口通但 curl 超时curl -w 输出耗时详情TLS 握手慢或应用层异常看 time_appconnect 定位 TLS 段检查服务端负载curl 报 Connection refusedss -lntp 检查服务端目标端口没有服务监听启动服务或检查服务绑定地址curl 报 SSL certificate problemopenssl s_client 查证书证书过期或不匹配更新证书或临时用 -k 验证连通性这张表不是万能的但它能把绝大多数访问不了的问题框在一个范围内。我自己写自动化检查脚本时就是按这个思路写成一系列函数的先在命令行手动跑通再固化到脚本里做定时拨测。6.2 我踩过的几个坑第一个坑是用 ping 的丢包率直接推断业务质量。有一次我测一个海外节点的延迟ping 只有 10% 的丢包觉得还行但实际跑业务时发现请求成功率只有一半。后来才明白ICMP 和 TCP 在中间网络设备上的待遇完全不同运营商可能对 ICMP 限速但对 TCP 流量走另一条路径。所以只要涉及业务访问最终结论必须用 curl 或 nc 这类真实协议去验证。第二个坑是 DNS 缓存造成的假故障。在排查某次域名切换问题时我改完 DNS 记录测试还是解析到旧 IP。折腾半天才发现本地 systemd-resolved 缓存了旧的解析结果。用下面这个命令清一下就好了sudo resolvectl flush-caches另外一些老系统用的是 nscd 缓存重启 nscd 服务也能达到同样效果。以后再看到解析不对先想缓存别急着赖 DNS 服务器。第三个坑是 IPv6 优先策略导致 curl 超时。一个看起来特别奇怪的现象浏览器打开正常curl 却卡了很久才报错后来发现是本机通过 IPv6 去连一个实际上 IPv6 路由不通的站点系统在等待 IPv6 超时后才回退到 IPv4。curl 的-4参数能快速验证这个判断确认后可以把系统的 IPv6 优先级调低或者在测试命令里固定使用 IPv4。6.3 把测试方法固化成脚本手动测试了一轮之后建议把常用的检查项整理成一个 shell 脚本下次遇到类似问题直接一把梭。我自己的脚本写得比较简单灵活核心就是把 DNS 解析、TCP 端口、HTTP 状态码三层检查串起来#!/bin/bash TARGET${1:-example.com} PORT${2:-443} echo DNS 解析检查 dig short $TARGET A echo TCP 端口检查 nc -zv -w 5 $TARGET $PORT 21 echo HTTP 请求检查 curl -s -o /dev/null --connect-timeout 5 --max-time 10 \ -w HTTP状态码: %{http_code}\nDNS耗时: %{time_namelookup}s\n连接耗时: %{time_connect}s\n总耗时: %{time_total}s\n \ https://$TARGET脚本接受一个域名作为参数默认测 443 端口。日常巡检的时候我可以同时跑好几个目标把输出重定向到文件里对比不同时间点的数据判断是持续故障还是间歇性抖动。这里有个细节脚本里的nc在不同发行版上参数有细微差异比如 OpenBSD 版 netcat 和老式 GNU netcat 略有不同如果报参数错误用nc -h看一眼帮助就行不需要死记。我个人在实际操作中的体会是排查连通性问题最怕的不是故障本身而是没有章法地乱试。你一会儿换个工具、一会儿换个目标最后试了一堆操作还是说不清问题出在哪一层。按照 DNS、网络、端口、HTTP 这个从下往上的顺序走一遍每一步的输出都是下一步的依据哪怕最后没找到根因给其他人交接的时候也能明确说出已经排查过哪些环节、剩下可疑的是哪一层协作效率会高很多。最后再分享一个小技巧命令行测试时尽量保留原始输出不要光看成功失败这两个结论。像 ping 的延迟分布、curl 的各阶段耗时、dig 的查询服务器地址这些细节才是定位问题的真正线索。以后再有人问你这个地址能不能访问你的回答就不只是能或不能而是能访问但 DNS 解析花了 2 秒TCP 连接很快TLS 握手偏慢可能是目标服务器处理器忙——这种信息量才是一次靠谱的连通性测试应该给出的交代。