恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Linux抓包实战:tcpdump、BPF过滤与丢包排查
首页
资讯中心
/
Linux抓包实战:tcpdump、BPF过滤与丢包排查
Linux抓包实战:tcpdump、BPF过滤与丢包排查
发布时间:2026/10/1 23:29:15
在运维和后端排查问题的现场捕获数据包几乎是最后一招也是最见效的一招。接口返回慢、连接莫名断、偶发超时、三方回调收不到这些在日志里看不出所以然的问题一旦把链路上的原始报文摊开来看往往几分钟就能定位。它不是只有安全方向才用得上的技能做服务端、做数据库、做网关、做嵌入式联网设备的人早晚都要碰。这篇内容我按自己在生产环境里的操作顺序来写先讲清楚抓包在操作系统里到底发生了什么再讲工具选型和权限怎么配然后是过滤器怎么写、文件怎么滚动落盘、命令行怎么快速出结论最后把丢包、时间戳不准、文件爆炸这几个最容易踩的坑摊开说。只要你能在测试机或者自有环境里动手跟着走一遍就能上手不需要提前懂协议细节。1. 抓包这件事到底在抓什么从网卡到文件的完整链路1.1 一个数据包在操作系统里要走的几道门很多人对抓包的理解停留在软件把网线上的电信号读出来其实不是。现代网卡收到帧之后DMA 把数据写进内核的接收环形缓冲区触发硬中断然后走 NAPI 轮询机制进入协议栈依次经过链路层、网络层、传输层最后交给 socket 对应的进程。抓包程序要做的事情是在这条路径上插一个旁路分支把报文复制一份出来。Linux 上这个旁路分支的入口是AF_PACKET这个协议族。抓包程序创建一个AF_PACKET类型的 socket绑定到具体网卡内核在协议栈的特定钩子点把 skbsocket buffer复制一份投递给这个 socket。复制发生在离开驱动之后、进入上层协议之前所以你能看到完整的二层帧包括 MAC 头和可能存在的 VLAN 标签。这里有个关键点值得记住复制是有成本的而且默认情况下每个包都要复制。所以在高流量网卡上抓包本身就是一种负载。我在一台跑 8Gbps 转发的小机器上试过不加过滤器全量抓CPU 的 softirq 直接飙到 90% 以上业务延迟肉眼可见地涨。这也是后面要反复强调过滤器重要性的原因。另一个容易忽略的事实是抓包程序看到的包和你用curl请求时看到的包可能不是同一份。如果你的程序走的是回环接口流量根本不经过物理网卡如果走了隧道或者 overlay 网络外层还有一层封装。定位问题时先搞清楚流量到底走哪张网卡这一步比什么都重要。1.2 混杂模式到底改变了什么新手最常问的问题是为什么我抓不到别人的包答案跟混杂模式promiscuous mode有关。网卡在默认状态下只接收两类帧目的 MAC 是自己的以及广播/组播。这叫正常模式。开启混杂模式后网卡会把线上所有帧都交给内核不再做 MAC 地址过滤。抓包工具里加-p参数就是明确禁用混杂模式不加则默认尝试开启。这里有个常见的误解以为开了混杂模式就能抓到整个局域网所有人的流量。在早年的共享式集线器时代确实可以因为那时所有帧物理上会广播到每个端口。但现在的接入设备是交换机交换机会根据 MAC 地址表做定向转发A 端口的帧根本不会送到 B 端口。所以在交换机环境下你开了混杂模式也只看得到本机相关的流量、广播流量以及交换机的泛洪流量。注意这条特性决定了抓别人的包在正常情况下是做不到的也不应该去做。真要看全链路流量标准做法是在你自己的网络设备上配置端口镜像或者串接一个网络分流器前提是这台设备和上面的流量你有管理权限。生产环境里动镜像口之前先确认镜像会话不会把核心链路打满我见过因为镜像口配错导致交换机 CPU 被打爆的案例。混杂模式还有一个副作用常被忽略在某些虚拟化平台和无线网卡上开启它会显著增加 CPU 占用因为内核要处理大量本来会被网卡丢弃的帧。所以当你的目标很明确时比如只看本机到某个服务的流量加-p反而是更好的选择。1.3 工具选型命令行的抓、图形界面的看、脚本的算工具这块不用纠结按抓和看两个阶段分开选就行。抓的阶段首推tcpdump理由很简单它是几乎所有 Linux 发行版都能一条命令装上的基础工具依赖极少跑在最小化安装的生产机上没有负担而且过滤器语法和pcap文件格式是整个生态的事实标准。dumpcap是 Wireshark 套件里专门负责抓包的组件它的优势是内置了多线程写盘和更细的缓冲区控制在高速率场景下比tcpdump更抗丢包。tshark则是 Wireshark 的命令行版本抓和分析都能干适合写进自动化脚本。看的阶段桌面环境直接上 Wireshark它的跟随 TCP 流、专家信息、IO 图表这些功能是命令行工具短期内追不上的。服务器上没有图形界面就退回tshark配合-z系列统计选项和-T fields提取字段能覆盖八成以上的分析需求。选型的核心判断依据是在哪里抓、抓多久、谁来看这三件事。生产机上临时抓五分钟定位问题tcpdump足够要在边缘节点常驻抓包做回溯就得考虑dumpcap加环形缓冲要把分析结果沉淀成报表只有tshark加脚本这条路。至于图形化工具永远不要在你不完全掌控的业务机上装它的依赖链会带来一堆你不想维护的东西。2. 开工前的环境准备与权限配置2.1 Linux 下权限怎么给才既安全又够用抓包需要CAP_NET_RAW能力开混杂模式还需要CAP_NET_ADMIN。直接用 root 跑是最省事的做法但在生产机上是坏习惯——一个带缓冲区溢出风险的解析器跑在 root 下等于把整台机器交出去。推荐的做法是给二进制文件打上能力标签sudo setcap cap_net_raw,cap_net_admineip /usr/sbin/tcpdump打完标签后普通用户执行tcpdump就不再需要sudo。用getcap可以验证是否生效getcap /usr/sbin/tcpdump # 期望输出/usr/sbin/tcpdump cap_net_admin,cap_net_raweip注意setcap的结果会在软件包升级时被覆盖。Debian 系升级tcpdump之后大概率要重新打一次标签。如果你的环境用配置管理工具记得把这条命令写进包管理的 post-hook 里否则某次自动升级之后定时抓包任务会静默失败而日志里只有一句权限不足。Wireshark 在桌面发行版上有个更规范的做法安装时选择允许非 root 用户抓包它会创建一个wireshark用户组并把dumpcap的能力限制好把需要用的账号加进这个组即可。这个机制比sudo wireshark安全得多因为图形界面本身跑在普通用户权限下只有底层抓包组件持有能力。如果环境不允许改二进制能力比如只读文件系统或者合规要求退而求其次用sudo加白名单把tcpdump的绝对路径写进 sudoers禁止通配符参数。这样至少能防止有人借抓包工具的写文件参数覆盖系统文件。2.2 抓之前先看三样东西网卡、缓冲区、时钟动手之前花三十秒做三个检查能省掉后面半小时的困惑。第一确认网卡名和状态。ip -br link一眼看清所有接口和 UP/DOWN 状态。别想当然地写eth0现在服务器上动辄ens192、eno1、bond0容器里更是vethxxxx一堆。抓错网卡是最低级的浪费时间。第二看内核缓冲区上限。抓包 socket 的接收缓冲默认值往往偏小高速率下不够用就会丢包sysctl net.core.rmem_max net.core.rmem_default如果rmem_max只有 200KB 左右而你要抓的业务峰值在 1Gbps 以上那基本注定要丢。可以临时调大sudo sysctl -w net.core.rmem_max67108864这个值是字节64MB 对绝大多数场景够用了。抓包工具的-B参数单位是 KB两者要对上比如-B 65536对应 64MB 左右。第三看时间。抓包的时间戳来自系统时钟如果机器没做时间同步你拿着抓包文件和另一台机器的日志对时间会得出完全错误的结论。timedatectl status看同步状态chronyc tracking看偏差量。分布式排障场景下各节点时钟偏差控制在毫秒级是底线。还有个容易被忽略的检查项磁盘剩余空间和写入速度。抓包文件写的是顺序 IO但如果你指定的目录正好在忙的机械盘上写盘速度可能成为丢包的原因。放到独立的数据盘或者 tmpfs 上是更稳的选择代价是重启丢数据这个权衡自己判断。2.3 抓包点选在哪里本机、容器、还是上游设备这个问题决定了你能看到什么比工具选型重要得多。本机抓是最简单的直接抓业务网卡。局限是只能看到这台机器收发的流量看不到它上游设备之间的交互。如果问题是请求发出去了但对方说没收到本机抓只能证明你发出去了证明不了对方收到没有。容器里抓要分情况。容器共享宿主机内核网络命名空间是独立的。在宿主机上抓veth对的一端能看到该容器的进出流量如果想在容器内部视角抓用nsenter进入它的网络命名空间# 先拿到容器主进程 PID CONTAINER_PID$(docker inspect -f {{.State.Pid}} my_container) # 进入网络命名空间执行抓包 sudo nsenter -t $CONTAINER_PID -n tcpdump -i eth0 -nn -c 100-n是不做主机名解析、-nn是连端口也不做服务名解析。这两个参数强烈建议常开否则 DNS 查询会污染你的抓包结果还会拖慢输出。我在一次排查里就吃过亏没加-n抓包文件里混进了大量 DNS 查询包把原本想看的业务流量淹了。上游设备抓指的是交换机镜像口或者串接分流器能看到多台机器之间的完整交互。这条路的前提是设备在你管理范围内、有权限配置、并且经过评估不会影响转发性能。跨机器的问题如果在本机抓不到答案就该往这个方向走而不是反复在同一台机器上换工具。3. BPF 过滤器把噪音砍掉九成3.1 过滤器语法的三层结构BPF 过滤器的语法看着杂其实就三层维度在组合类型type、方向dir、协议proto。理解了这三层剩下的就是排列组合。类型指的是匹配什么对象常用的是host主机、net网段、port端口、portrange端口范围。方向是src、dst以及它们的组合不写就是双向。协议是tcp、udp、icmp、arp、ip、ip6这些。组合规则很简单省略的部分自动取默认值。写port 443等价于tcp or udp两种协议、两个方向、端口 443。写src host 10.0.0.8就是源地址是 10.0.0.8 的所有协议报文。多个条件之间用and、or、not连接优先级是not高于and高于or拿不准就加括号。这个优先级规则坑过不少人host a or host b and port 80实际是host a or (host b and port 80)如果本意是两个主机都要限定 80 端口必须写成(host a or host b) and port 80。提示过滤器是在内核里执行的不匹配的包连复制都不会发生所以它对性能的改善是数量级的而不是线性的。写一个好的过滤器等于把抓包对业务的影响从明显降到可忽略。3.2 我在现场最常用的几组过滤器配方下面这张表是我这些年反复用到的组合基本都是可以直接抄的。排查目标过滤器写法说明只看某台机器的全部流量host 10.0.0.8双向host不带方向即双向只看某个端口的会话port 5432数据库、中间件排查的起手式限定 TCP 且排除抓包自身连接tcp and not port 22防止 SSH 流量自我放大只看建立连接的握手包tcp[tcpflags] tcp-syn ! 0快速统计新建连接数只看重置包tcp[tcpflags] tcp-rst ! 0连接被谁断的一目了然只看某个网段net 192.168.10.0/24注意掩码要写全只看大包可疑分片greater 1400排查 MTU 问题的利器只看 ICMPicmp排查丢包和路径可达性精确组合host 10.0.0.8 and tcp port 443 and not port 22生产环境最常用的形态关于排除抓包自身连接这一条值得展开说。你通过 SSH 登录到目标机器上抓包SSH 会话本身的流量也会被抓到而tcpdump的输出又会通过 SSH 传回来形成正反馈。在带宽紧张或者包量大的场景下这个循环能把链路压死。所以只要是在远程会话里抓第一件事就是not port 22或者你实际用的端口。3.3 过滤器写错了有多贵两个真实验证方法过滤器写错有两种后果写得太严抓不到想要的包白跑一趟写得太松文件爆炸分析时找不到重点还可能把业务拖慢。所以写完之后一定要验证。第一种验证方式是先计数不落盘。用-c限定包数或者直接看输出跑十秒钟按 CtrlC 看统计sudo tcpdump -i ens192 -nn -p tcp port 443 and host 10.0.0.8 -c 20如果能迅速打出 20 个包说明过滤器命中了目标流量如果跑半分钟一个都没有要么过滤器写错了要么流量确实不存在——这两种情况需要区分别急着改过滤器。第二种验证方式是用-w落盘后立即统计协议分布确认抓到的内容符合预期sudo tcpdump -i ens192 -nn -p -w /tmp/check.pcap -c 2000 tcp port 443 tshark -r /tmp/check.pcap -q -z io,phs-z io,phs会输出协议分层统计一眼就能看出抓到的包里 TCP 占多少、有没有混进 ARP 和 DNS。如果发现八成都是 ARP说明过滤器太松或者抓错了网卡。这个两分钟的自检流程比我见过的任何事后补救都便宜。4. 实操一次完整的抓包与落盘分析流程4.1 环形缓冲区让抓包文件不撑爆磁盘生产环境常驻抓包最大的风险是磁盘被写满。解决办法是环形缓冲区限定单个文件大小和文件数量写满一个就滚动到下一个超过数量上限就覆盖最旧的。sudo tcpdump -i ens192 -nn -p -s 0 \ -C 100 -W 20 \ -w /data/capture/edge_$(hostname).pcap \ tcp and not port 22 这里每个参数都有讲究。-C 100表示单个文件 100MB-W 20表示最多保留 20 个文件那么总占用上限就是 100MB × 20 2000MB也就是 2GB。这个容量规划要按最长需要回溯多长时间来倒推如果业务峰值是 20Mbps2GB 大概能存 13 分钟左右2000MB × 8 ÷ 20Mbps ≈ 800 秒够不够用来抓偶发问题自己判断。-s 0表示抓完整包长度。早期版本的tcpdump默认snaplen是 96 字节只抓头部如果只想看握手和头部信息用-s 96能大幅减小文件体积代价是看不到应用层负载。排查 TLS 握手或者 HTTP 内容时必须-s 0抓全否则载荷被截断分析工具会报包被截断。后台运行时记得记录 PID方便之后优雅停止echo $! /var/run/capture.pid # 停止时 sudo kill -TERM $(cat /var/run/capture.pid)用SIGTERM而不是SIGKILL因为tcpdump收到SIGTERM会正常关闭文件并写入统计信息包括丢包计数——这个计数是后面排查的关键依据用-9强杀就丢了。4.2 时间戳、快照长度与文件格式的取舍这几个参数看起来是细节但它们直接决定了你事后能不能分析出结论。时间戳精度默认是微秒级在高频交易或者高精度性能分析场景下不够用可以开启纳秒精度。但要注意纳秒精度需要网卡和驱动支持硬件时间戳否则内核算出来的纳秒位是不可信的。查看方式是在输出里看小数点后的位数以及和系统时间对比。时间戳显示格式-tttt输出人的可读日期时间-tt输出 Unix 时间戳不指定则是相对时间从第一个包开始算。跨设备对比日志时必须用绝对时间用相对时间等于给自己挖坑。文件格式默认是pcap通用性最好。数据量特别大的场景可以考虑pcapng它支持多接口、注释和更丰富的元数据但兼容性稍差老版本的解析库可能读不了。除非有明确需求我一般还是用pcap省得给后面的分析工具找麻烦。写入缓冲-U参数让每个包到达就立刻写盘不缓冲。这么做的好处是实时性高程序崩溃时已经抓到的数据不会丢坏处是写盘次数暴增在高包量下会明显增加 CPU 和 IO 压力。判断标准很简单如果抓包是用来实时监控告警的加-U如果是事后回溯分析不加让内核做批量写。4.3 从抓包文件到结论命令行里最有效的几条命令抓完包才是真正的工作开始。Wireshark 图形界面适合精细分析但在服务器上我用得最多的是下面这几条tshark命令。先看整体画像确认抓到的流量构成是否正常tshark -r trace.pcap -q -z io,phs再看会话排行找出流量最大的那几对通信tshark -r trace.pcap -q -z conv,tcp排查重传和乱序这两个指标基本能反映链路质量# 统计重传包数量 tshark -r trace.pcap -Y tcp.analysis.retransmission 2/dev/null | wc -l # 统计乱序包数量 tshark -r trace.pcap -Y tcp.analysis.out_of_order 2/dev/null | wc -l想快速看某个连接的时间线把关键字段提出来排成表tshark -r trace.pcap -Y tcp.port 443 \ -T fields \ -e frame.time_relative \ -e ip.src -e tcp.srcport \ -e ip.dst -e tcp.dstport \ -e tcp.flags.str -e tcp.len \ -E headery -E separator, /tmp/flow.csv导出的 CSV 直接丢进表格工具做透视比在几百兆的pcap里肉眼翻要快得多。这套命令行提取字段 → 表格分析的路子是我处理大文件时的标准打法。如果流量是加密的你拿不到应用层内容但元数据依然能说明很多问题握手阶段的 SNI 字段能告诉你访问的是哪个域名证书有效期能告诉你服务端配置有没有过期风险包长分布和时序能反映是否存在重传密集或者响应被拆成小包。很多时候问题不在内容而在时序加密反而无所谓。5. 抓包丢包、时间不准、文件过大三个高频坑的排查5.1 丢包怎么判断先看内核计数再定位原因抓包丢包是最隐蔽的问题因为丢掉的包不会出现在文件里你会以为这个包根本没发出来从而得出完全错误的结论。判断方法很直接tcpdump在正常退出时会打印一行统计形如N packets captured、M packets received by filter、K packets dropped by kernel。这三个数字的关系是内核收到的M中有一部分因为缓冲区满被丢弃K最终成功处理并写出的N通常等于 M 减去 K 和其他过滤损耗。只要K不为零就必须警惕。看到一个真实的数字感受一下一次抓包结束显示500000 packets captured, 512300 packets received by filter, 12300 packets dropped by kernel。丢包率约 2.4%。如果一个 TCP 会话恰好丢在了关键的重传时刻你的分析结论可能完全反过来。丢包的常见原因和对应处置我整理成表现象可能原因处置方向丢包率随流量上升内核接收缓冲不足调大rmem_max抓包时加-B丢包集中在突发时刻写盘速度跟不上换更快的盘或先缩小snaplen丢包率稳定偏高但流量不大过滤器过于复杂简化过滤条件减少内核判定开销只有混杂模式下丢包网卡/驱动处理能力不足加-p关闭混杂模式虚拟机上频繁丢包vCPU 抢占或中断绑定问题检查中断亲和性与宿主机负载提示如果无论如何都丢而你又必须抓到每一帧那就该换技术路子了——用交换机镜像口配合独立抓包设备让抓包这件事彻底离开业务机。在业务机上死磕丢包率性价比很低。5.2 时间戳不准分布式排障里最容易被冤枉的环节跨机器分析时时间戳对不上会带来非常离谱的结论。比如 A 机器日志显示 10:00:00.100 发出请求B 机器抓包显示 10:00:00.050 才收到请求你会以为时钟倒流了其实只是两台机器的时钟差了 100 毫秒左右。处理这个问题的顺序是先确认同步服务状态再看偏差幅度最后决定要不要修正时间戳再做分析。timedatectl status chronyc tracking # 或者 ntpq -p取决于用的同步方案chronyc tracking输出里的System time一项就是本机相对于参考源的偏差单位是秒。偏差在毫秒级以内跨机分析基本可以直接用原始时间戳偏差到了几十毫秒以上就必须做修正或者在分析时明确记录这个偏移量。另一个常见坑是时区。抓包文件的时间戳默认是 UTC而你的应用日志大概率是本地时间。用-tttt显示出来的时间是本地时间但用工具解析pcap时拿到的往往是 UTC。我曾经在这个问题上绕了半小时以为请求延迟了八小时其实是时区换算没对齐。稳妥做法是所有分析环节统一用 UTC只在最后呈现给业务方时转本地时间。5.3 文件过大从抓的时候就该想好怎么分析抓一个几 GB 的文件很容易分析它才是折磨。控制文件体积的手段有三层按优先级排第一层是过滤器这是效果最好的前面已经详细说过。把无关流量挡在内核外面文件能小一到两个数量级。第二层是快照长度。如果只关心连接行为和时序不关心应用层内容-s 128就够覆盖以太网头、IP 头、TCP 头和一部分选项。这样单个包最多存 128 字节对比 1500 字节的完整包文件体积能压到十分之一以下。但要注意snaplen太小会导致 TCP 选项被截断某些分析功能会失效实践中 96 到 128 是常见的平衡点。第三层是边抓边切分和分析。不要指望抓完之后一次性加载用editcap或者tshark按时间片或连接切分# 按每 100 万包切分 editcap -c 1000000 big.pcap /tmp/split.pcap # 只提取某个 IP 相关的包 tshark -r big.pcap -Y ip.addr 10.0.0.8 -w /tmp/filtered.pcap预处理之后再分析内存占用和等待时间都会舒服很多。我在处理一个 12GB 的抓包文件时先按主机提取出目标的 300MB再用图形工具打开从打不开变成秒开。6. 常见问题速查表与实操心得这一节把前面散落的问题集中成速查表方便动手时直接对照。问题现象最可能的原因快速验证方式处置一个包都抓不到网卡选错或流量走回环ip -br link确认接口换-i lo或正确网卡名只抓到本机发出抓不到回复镜像/抓包点位置不对对比收发方向计数换抓包点或检查镜像配置端口解析出奇怪的服务名未加-nn输出里出现服务名而非数字加-nn关闭解析文件快速膨胀过滤器过松或无过滤看文件增长速率收紧过滤器缩小snaplen分析时报包被截断snaplen设置过小工具提示truncated重新抓用-s 0停止抓包后文件损坏用了kill -9文件无法被解析始终用SIGTERM优雅停止时间线对不上时钟未同步或时区不一致chronyc tracking统一 UTC必要时修正偏移关于实操心得有几条是我踩过坑之后才真正记住的。第一条抓包文件是敏感数据比你想的更敏感。即使流量是加密的元数据里也包含内网拓扑、服务地址、访问频率这些信息未加密的协议更是直接把凭据和业务数据明晃晃写在里面。抓下来的文件要有明确的保留期限排查完之后该删就删需要长期留存的做脱敏处理。共享给别人之前先用editcap裁剪掉无关会话别整个文件甩过去。第二条不要在问题发生之后才开始抓。偶发问题的特点就是抓不住。真正有效的做法是在关键节点上常驻低成本的环形缓冲抓包平时默默滚动出问题时把时间窗口内的文件捞出来回溯。这个方案的成本是一个进程加 2GB 磁盘收益是从复现不了变成随时可查。第三条先用统计数据形成假设再针对性看包。新手容易一上来就在几千个包里从头翻翻到眼睛发花还没结论。正确的顺序是先看会话统计和重传统计判断问题出在哪个连接、哪个方向然后过滤出那个连接看时间线。工具是用来验证假设的不是用来帮你产生假设的。第四条把常用的抓包和分析命令存成脚本。我给团队维护过一个小工具集把按主机提取、统计重传、导出关键字段这几步封装成带参数的命令。出问题时一条命令就能拿到初步画像不用每次重新想参数怎么拼。这种投入一次、复用多年的东西收益比想象中高。第五条记录抓包的环境信息。光有一个pcap文件过两周之后你根本想不起来是在哪台机器、哪个网卡、什么时间段抓的。我习惯在同目录下放一个同名的说明文件记录主机名、网卡、过滤器、开始时间和当时的业务现象。这个习惯帮我省过不止一次返工。最后说一个容易被忽略的细节抓包时顺手看一眼系统的软中断分布。用mpstat -P ALL 1观察如果某一个 CPU 核的%soft明显高于其他核说明网卡中断集中在那一个核上抓包会放大这个问题。把中断亲和性分散开往往能同时改善业务延迟和抓包丢包率一举两得。这个操作的成本很低但收益经常超出预期尤其是在虚拟化环境里。