ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ESXi主机未响应排障:心跳链路分析与pktcap-uw抓包实操

ESXi主机未响应排障:心跳链路分析与pktcap-uw抓包实操

ESXi 主机在管理界面里变成灰色的“Not Responding”,那种感觉做过运维的人都懂:虚拟机的业务可能还在跑,但你不知道它下一秒会不会真的挂掉,也不敢贸然重启。这个状态既不像“Disconnected”(断开)那样干脆,也不像“Inaccessible”(无法访问)那样明确,它悬在中间,逼着你去验证一件事——到底是主机真的出问题了,还是只是“心跳”没送过去。我要聊的就是这件事:ESXi 主机 not responding(未响应)的成因分层、排查路径,以及在 ESXi 上做抓包(pktcap-uw、tcpdump-uw)的具体手法。内容偏向一线排障,适合手里管着几台到几十台 ESXi 主机、被“未响应”反复折腾过的朋友,也适合刚接触虚拟化、还没弄明白心跳链路的同行。不讲空话,都是从现场记录里扒出来的东西。

1. 把“未响应”拆开看:三种状态背后是三种故障

1.1 Not Responding 与 Disconnected、Inaccessible 的差别

很多人把这三个状态当成一回事,实际差别很大,判断错方向会浪费几小时。Disconnected(断开)通常是管理端主动断开的连接,比如你手动断开、证书不匹配导致握手失败、管理端服务重启后没能重建会话,主机本身大概率是活的,只是“这个管理端不跟它讲话了”。Not Responding(未响应)的含义更偏“管理端连不上,但也没有明确证据说主机死了”,典型触发是管理代理进程响应超时、管理网络丢包、或者主机负载高到 443 端口的 TCP 会话无法在超时时间内完成握手。Inaccessible(无法访问)多见于集群环境,主机被判定为隔离或 HA 代理通信失败,往往伴随数据存储心跳异常。

这三者的处置动作完全不同:Disconnected 先去查证书和版本;Not Responding 优先查管理网络的连通性和 hostd 进程;Inaccessible 要先确认共享存储和集群心跳。我见过有人一看到灰色就重启管理代理,结果主机业务正在做批量备份,重启直接把备份任务打断了——查清状态含义,比任何命令都重要。

1.2 一台“未响应”的主机其实可能在正常跑业务

这是最容易误判的地方。管理界面显示未响应,只代表管理平面的通信出了问题,不代表数据平面停了。虚拟机的网络转发由虚拟交换机承担,跟 hostd 进程、跟管理 vmkernel 接口没有强依赖关系。所以第一反应不该是重启,而是从另一个入口确认主机还活着:带外管理口(就是那个独立的管理网口/IPMI 类接口)看电源和风扇状态、看物理交换机对应端口的指示灯、从同网段另一台机器 ping 管理地址、或者直接登录带外控制台。

我个人的习惯是先做三件事,顺序固定:ping 管理 IP(判断链路层和网络层通不通)、ping 默认网关(判断是不是本机路由或上游问题)、从另一台同网段主机 telnet 管理 IP 的 443 和 902 端口(判断 hostd 是否还活着)。这三步两分钟内能出结果。如果 ping 通、443 不通,基本锁定主机侧进程或防火墙;如果 ping 不通但带外控制台能进,那就是网络或网卡的问题,可以直接往抓包方向走。

提示:不要在没有带外访问手段的情况下重启一台“未响应”的主机。你无法确认它是否正在写数据,一次硬重启可能带来比故障本身更大的损失。

2. 心跳链路逐层拆解:为什么总是管理网络出问题

2.1 从管理端到 hostd 的那条会话

管理端和 ESXi 之间的“心跳”,本质上是几条长期存在的 TCP 会话加上周期性的状态上报。管理端通过 443 端口与主机的 hostd 通信,拉取配置、性能计数器、事件;虚拟机的远程控制台走 902 端口;集群环境里主机之间还有一层独立的心跳,走管理网络,同时共享存储上还有数据存储心跳文件做兜底。理解这个结构很关键:管理网络一旦出现间歇性丢包,最先表现异常的就是这些长连接。

长连接的脆弱点在于握手和保活。TCP 会话在中间设备(防火墙、负载均衡、NAT 设备)上都有会话老化时间,如果空闲一段时间没有流量,中间设备把会话表项清掉,而两端还认为连接存在,下一次发包就会石沉大海,直到上层超时才报“未响应”。这类问题有个很典型的特征:规律性,每隔固定时长(比如 5 分钟、15 分钟)出现一次未响应,过一会儿自己恢复。看到这种周期性症状,先怀疑中间设备的老化策略,而不是主机硬件。

2.2 五个高频故障域,从光模块一路查到 ARP 表

我把实际遇到过的原因归成五层,从上往下查比乱猜高效得多。

层级典型现象优先验证手段
物理层端口 up/down 抖动、错包计数上涨交换机端口计数器、esxcli network nic stats get -n vmnicX
链路层双工/速率协商不一致、聚合配置不匹配两端协商结果对比、LACP 状态
网络层跨网段不通、MTU 不一致、ARP 异常vmkping、esxcli network ip neighbor list
传输层443/902 端口被拦、会话老化端口探测、抓包看 SYN 与重传
应用层hostd 卡死、证书过期、时间漂移/var/log/hostd.log、时间同步状态

物理层的坑最隐蔽。有一次一台主机每两天未响应一次,交换机端口计数器里的 CRC 错包在缓慢增长,速率不高,容易被忽略。换了一根跳线后再没复现。错包计数只要在涨,就不是“正常波动”,别被“占比很小”说服。

链路层的经典问题是聚合配置:主机侧做了基于 IP 哈希的静态聚合,交换机侧配了 LACP 动态聚合,两边都不报错,但流量分布异常,某些会话直接丢。这种故障抓包看特别明显——同一个源目对的包出现大量乱序和重传。

网络层的代表是 MTU。管理网络一般 1500,vMotion 或存储网络可能配了 9000,如果这两类流量共用一块物理网卡或者经过同一条上行链路,而中间某台交换机端口没放大 MTU,就会出现“小包通、大包丢”的诡异现象,表现为管理端偶尔失联,尤其在做大批量操作时。

3. 抓包之前必须做的信息采集

3.1 控制台里先跑完这几条命令

抓包是最后手段,不是第一步。上机后我固定跑这几条,把现场状态先固定下来,避免重启或改动后证据丢失。

# 1. 管理接口与路由 esxcli network ip interface ipv4 get esxcli network ip route ipv4 list # 2. 物理网卡状态与错包 esxcli network nic list esxcli network nic stats get -n vmnic0 # 3. 虚拟交换机与上行 esxcli network vswitch standard list esxcli network vswitch standard uplink list # 4. 防火墙规则集(确认 443/902 没被拦) esxcli network firewall ruleset list | grep -i -E "vSphereClient|vmConsole" # 5. 当前连接,看 hostd 是否还在监听 esxcli network ip connection list | grep -E ":443|:902" # 6. ARP 表,看网关和邻居是否正常解析 esxcli network ip neighbor list # 7. 关键日志尾部 tail -n 200 /var/log/hostd.log tail -n 200 /var/log/vmkernel.log

其中第 2 条最容易被跳过,但价值最高。nic stats里的Dropped、Errors、CRC、Overruns四个数只要有一个在持续增长,就说明问题在物理层或驱动层,这时候抓上层协议的包意义不大。第 6 条能快速暴露 IP 冲突和网关 ARP 老化:如果网关条目状态反复在 REACHABLE 和 STALE 之间跳,同网段八成存在地址冲突。

日志方面,hostd.log里搜“Timeout”“Connection reset”“SSL”能定位应用层;vmkernel.log里搜“vmnic”“link down”“NAPI”能定位驱动层。建议先把日志打包走,用vm-support生成支持包,这个动作不改变现场状态,但会在事后救你一命。

3.2 抓哪个点:vmk、uplink、switchport 的取舍

ESXi 的抓包位置有三个层次,选错了要么抓不到包,要么抓到重复包。

抓 vmkernel 接口(--vmk vmk0):看到的是主机协议栈视角的流量,适合判断“主机有没有发出包”“上层有没有收到应答”。如果这里看不到 SYN,说明主机的路由或防火墙在丢弃;如果看到 SYN 但看不到 SYN-ACK,问题在外侧。

抓物理上行(--uplink vmnic0):看到的是离开/进入网卡的原始帧,适合判断“包到底有没有上网线”。这个位置最接近物理层,能暴露 VLAN 标签、MTU 截断、上行选择错误的问题。

抓虚拟端口(--switchport <portID>):适合定位某台虚拟机或某个 vmkernel 接口与虚拟交换机之间的交互,端口 ID 用net-stats -l或esxcli network vm list查。

选择逻辑很简单:先怀疑主机内部,就抓 vmk;先怀疑外部网络,就抓 uplink;要确认虚拟交换机有没有正确转发,就抓 switchport。拿不准的时候,两个点同时抓,通过时间戳对齐做比对,这招我用了很多次,几乎是判断“丢在哪一段”的最快方式。

抓包前必须估算容量,否则容易把本地盘写满。计算方式:文件大小 ≈ 包数 × (96 字节截断 + 16 字节文件头 + 16 字节记录头) ≈ 包数 × 128 字节。管理网络平时心跳流量很低,几百 pps 量级;8 小时按 300 pps 算就是 864 万包,约 1.1 GB,本地盘能扛住。但如果遇到广播风暴,pps 可能上万,一小时就是 4 GB 以上。所以一定要先设截断长度和包数上限,宁可少抓一点,也不能把盘写满——盘满了会连带影响日志写入和虚拟机快照。

注意:抓包文件不要写在正被诊断的存储或管理网络上,优先放在本地磁盘的独立目录,或者干脆写到内存盘/tmp。/tmp容量小但速度快,适合抓短时间的突发流量,缺点是重启即丢。

4. 实操:从零完成一次管理网络抓包

4.1 环境准备与前置检查

假设场景是这样的:某公司机房一台 ESXi 主机每天凌晨定时任务期间变成未响应,十来分钟后自己恢复,白天一切正常。管理网络是 192.0.2.0/24(文档示例网段),管理 vmkernel 是 vmk0,物理上行是 vmnic0,网关 192.0.2.1,管理端在 192.0.2.50。

动手前先确认三件事:SSH 或本地控制台的 Shell 已开启、本地磁盘剩余空间足够、确认当前没有重要任务在跑。开启 SSH 这件事本身有安全成本,用完立刻关掉,这是纪律不是建议。

# 确认本地存储挂载点与剩余空间 df -h | grep -E "vmfs|tmp" # 建一个专门放抓包文件的目录 mkdir -p /vmfs/volumes/datastore1/capture

进入 4.2 之前,先看帮助确认本机版本支持的参数,这个动作能避免一半的语法错误:

pktcap-uw -h

不同版本在参数命名上略有差异,尤其是文件轮转和捕获点相关的选项,以本机帮助输出为准,不要照抄别人的博客。这是个很实在的经验:同一套命令在 6.7 和 8.x 上不一定完全通用。

4.2 命令落地:三个位置同时开抓

针对这个场景,我一般开三个抓包任务,分别对应“主机内部视角”“物理上行视角”“目标端视角”。

# A. 抓管理 vmkernel 接口,双向,过滤 443,截断 128 字节 pktcap-uw --vmk vmk0 --dir 0 --snaplen 128 \ --proto 6 --dstport 443 \ --outfile /vmfs/volumes/datastore1/capture/vmk0-443.pcap & # B. 抓物理上行,只看与网关的交互,覆盖整个管理网段的动静 pktcap-uw --uplink vmnic0 --dir 0 --snaplen 128 \ --outfile /vmfs/volumes/datastore1/capture/vmnic0-all.pcap & # C. 抓 902 端口,排除控制台通道的干扰 pktcap-uw --vmk vmk0 --dir 0 --snaplen 128 \ --proto 6 --dstport 902 \ --outfile /vmfs/volumes/datastore1/capture/vmk0-902.pcap &

参数解释一下。--dir 0是双向,1是入向(从外部进入主机),2是出向;--proto 6表示 TCP;--snaplen 128把每个包截断到 128 字节,够看 TCP 头和部分负载,能显著降低文件体积。为什么是 128 而不是 96?因为要完整保留 TCP 选项字段(时间戳、窗口缩放),排重传和 RTT 时这些字段很关键;如果只关心有没有握手,96 就够。这个取舍值得说清楚,很多人抄了-s 0(全包),结果一小时写好几百 G。

如果目标版本支持捕获丢弃点,加一条能看到被丢弃的包及原因,对定位虚拟交换机丢包特别有用:

# 需确认本机支持 --capture 参数 pktcap-uw --uplink vmnic0 --capture Drop --dir 1 --snaplen 128 \ --outfile /vmfs/volumes/datastore1/capture/vmnic0-drop.pcap &

抓完后记得按 PID 停掉后台任务,别让它们一直跑:

pktcap-uw --list 2>/dev/null || true # 部分版本可列活动会话 ps | grep pktcap kill <PID>

另一种工具是tcpdump-uw,语法接近通用 tcpdump,适合习惯这个工具链的人,也支持按大小轮转:

tcpdump-uw -i vmk0 -s 128 -w /vmfs/volumes/datastore1/capture/gw.pcap \ -C 200 -W 5 host 192.0.2.50 and port 443

-C 200表示单文件 200 MB 轮转,-W 5表示最多保留 5 个文件,这套组合是环缓冲,跑一整天也不会撑爆盘。如果你只打算记住一个抓包命令,就记这条,它对长时间守株待兔最友好。

4.3 把 pcap 捞出来看:先看四样东西

文件在 ESXi 上,通过 SCP 传到分析机就行。分析时不用一上来就全量打开几百万包,按这个顺序看效率最高。

第一步看 TCP 重传率和 RTT 分布。统计里如果重传超过 1%,管理网络的“偶尔失联”就有解释了。重传集中在某个时间窗口,就把时间点记下来,跟系统日志、备份任务时间表做比对。

第二步看握手是否完成。过滤tcp.flags.syn == 1,看 SYN 有没有对应的 SYN-ACK。只见 SYN 不见 SYN-ACK,说明对端没回或者被中间设备拦了;同时抓到多个 SYN 但没有 ACK(SYN 重传),基本就是丢包或者目标端口无监听。

第三步看是否有 ARP 异常。过滤arp,观察是否有“同 IP 不同 MAC”的应答,或者网关 ARP 请求长时间无应答。这一条能抓出地址冲突和网关老化,很多“未响应”其实是主机不知道网关 MAC 了。

第四步对时间线。把 pcap 的时间戳和hostd.log里第一条 Timeout 的时间对上去,误差应在几秒之内。如果日志说超时的时间点,抓包里那个时刻的链路是干净的(没有重传、没有丢包、握手正常),那问题就往上走,去查 hostd 自身和存储 I/O。

回到这个案例:三个抓包文件对比后发现,uplink 侧在凌晨有大量来自管理网段的 ARP 广播,同时 443 会话出现周期性重传,重传间隔与定时任务的启动时间吻合;而 vmk0 侧的包发出后迟迟等不到应答。最终定位是上游一台接入交换机端口开启了某种泛洪抑制,突发广播触发抑制后短暂阻断转发。交换机侧调整参数后,未响应再没出现。这个结论完全靠“三个点同时抓包 + 时间戳比对”得出,单点抓包根本看不出这个因果。

5. 三个真实场景复盘:别把所有锅都甩给网络

5.1 案例一:错包计数在涨,但涨得很慢

某实验室一台主机每周未响应一到两次,每次持续几分钟。网络侧排查一圈无果,最后是nic stats里那个不起眼的 CRC 错包数字暴露了问题——每周几十个,占比极低,几乎被忽略。换了光模块和跳线后清零,故障随之消失。

这个案例的教训是:管理网络的“间歇性”故障,优先看物理层计数,哪怕数字很小。判断标准不是绝对值大小,而是“是否持续增长”。我的做法是间隔 10 分钟连查两次,两次数值相同才算稳定,一次性采样没什么参考价值。

5.2 案例二:MTU 不一致导致大包默默消失

某公司把 vMotion 和存储流量放在同一对物理网卡上,MTU 配了 9000,管理网络也复用了这对上行。现象是平时正常,一做批量迁移管理端就失联。抓包显示小的控制包正常收发,一旦有大包就断,且没有 ICMP 的“需要分片”报文回来——中间设备直接静默丢弃了。

验证方法很直接,用不分片的 ping 逐级试探:

# 验证 9000 MTU:8972 + 8 字节 ICMP 头 + 20 字节 IP 头 = 9000 vmkping -d -s 8972 -I vmk1 192.0.2.20 # 验证 1500 MTU:1472 + 28 = 1500 vmkping -d -s 1472 -I vmk0 192.0.2.1

-d是不分片,-s是负载长度。这个加减法很多人算错,记住“MTU = 负载 + 8 + 20”,IPv4 场景下 1500 MTU 对应 1472,9000 对应 8972。如果 1472 能通、1473 不通,说明路径 MTU 就是 1500;如果 8972 不通而 1472 通,说明中间某一段没放开大帧。把管理网络和存储网络彻底分开走不同上行,是根治办法。

5.3 案例三:时间漂移把网络问题“造”了出来

一台主机反复显示未响应,抓包一切正常,重传率几乎为零,RTT 稳定。最后在日志里发现证书校验失败的记录,原因是主机 BIOS 电池失效,硬件时钟跑偏,时间同步又因为管理端不可达而失败,形成死循环。

这类问题的识别特征很明显:抓包干净但应用层报错。判断方法是对比主机时间和一台可靠的时间源,偏差超过 5 分钟就该警惕。修复动作是先手动校准时间、修好时间同步源,再重建管理端连接。从此我上机第一件事就是date -u看一眼,比什么都快。

6. 常见问题速查与踩坑清单

6.1 问题速查表

现象最可能原因快速验证处置动作
规律性失联,几分钟自愈中间设备会话老化对比失联间隔是否固定调整保活或会话老化时间
批量任务期间失联MTU 不一致 / 上行拥塞vmkping -d -s 8972统一 MTU,拆分流量
抓包无重传但应用报错证书、时间、进程卡死date -u、查 hostd 日志校准时间,重启管理代理
同网段 ICMP 双应答IP 地址冲突抓arp看 MAC 变化排查冲突设备
443 端口探测不通但 ping 通防火墙或 hostd 停止查规则集与进程放行规则,重启服务
交换机端口计数器错包增长光模块、跳线、协商间隔取两次计数对比换线换模块,固定速率
抓包文件写不进去目标路径空间不足或只读df -h看挂载点换本地盘或/tmp

6.2 十条踩坑经验

第一条,别在未确认主机状态前重启。带外控制台先看一眼,能省掉很多麻烦。

第二条,抓包前先跑pktcap-uw -h。版本差异导致参数不通用,照抄会浪费大量时间。

第三条,永远设--snaplen。全包抓取在管理网络这种流量下也没有意义,128 字节足够做九成的判断。

第四条,长时间观察用环缓冲,-C加-W的组合比单文件更安全,不会把盘写满。

第五条,抓包文件别放在被诊断的路径上。存储链路有问题时,你连文件都取不出来。

第六条,多点同时抓,靠时间戳对齐。单点抓包只能证明“这里有没有包”,证明不了“包丢在哪一段”。

第七条,错包计数的判断标准是趋势不是绝对值。间隔采样两次对比,别信一次性快照。

第八条,MTU 验证用不分片 ping,记住 1472 和 8972 两个数。这个小技巧能省下几小时的抓包时间。

第九条,先看日志再看包。日志里往往已经写明了方向,抓包是验证不是探索。

第十条,抓完立刻关 SSH、清临时文件。临时目录和抓包文件本身就是风险面。

我个人在实际操作中的体会是,“未响应”这个状态最坑的地方不是技术难度,而是它给你一种“必须马上做点什么”的压迫感。真正有效的动作往往是反直觉的——先不动,先把现场状态固定下来,先把三个抓包点开起来,让证据自己说话。我手里那套排障脚本,核心其实就三行:查计数、查日志、开抓包,剩下全是等待和比对。慢一点,反而快。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进