网络、磁盘与性能排查

这台机器连不连得通、端口有没有在听、磁盘还剩多少、卡在 CPU 还是 I/O——这一节按「先看接口和路由,再看端口和连接,最后看磁盘和性能」的顺序排列,每一条都可以直接复制执行。

共 49 条命令 · 最近更新

网卡、IP 与路由

iproute2 已经完全取代 ifconfig / route / arp 这一套;下面全部用 ip 命令。

ip addr

查看网卡与 IP 地址。-br 输出简洁表格(brief),show dev 只看某张网卡,-4 / -6 只看对应协议族。

ip -br addr
ip addr show dev eth0
ip -4 -br addr

想临时加一个地址用 ip addr add 10.0.0.5/24 dev eth0,重启即失效;要持久化请改发行版的网络配置或 NetworkManager。

ip link

查看二层接口状态(是否 UP、MTU、MAC 地址)。ip link set eth0 up / down 启停网卡,set mtu 1500 调整 MTU。

ip -br link
sudo ip link set eth0 up
sudo ip link set eth0 mtu 1400

网卡显示 DOWN 但配置都在,先确认是不是虚拟机网线没插上、或者云主机没绑定弹性 IP。

ip route

查看路由表。默认网关是 default via ... 那一行;ip route get 目标IP 会直接告诉你「去这个地址会走哪张网卡、哪个下一跳」。

ip route
ip route get 1.1.1.1
ip -6 route show

traffic to a 目标不在路由表里会立刻报 Network is unreachable,而不是超时——这两种报错的含义完全不同。

ip neigh

查看 ARP / 邻居表,确认同网段主机的 MAC 解析是否正常。incomplete 或 FAILED 表示二层解析失败。

ip neigh
ip neigh show dev eth0
sudo ip neigh flush dev eth0

ethtool

查看网卡驱动的详细状态:Speed / Duplex 协商结果、Link detected、驱动版本、各队列统计。-S 输出详细的收发包计数与错误计数。

sudo ethtool eth0
sudo ethtool -S eth0 | grep -i -E 'err|drop|discard'

Speed 显示 100Mb/s 而交换机口是千兆,多半是网线或水晶头的问题;errors/dropped 持续增长说明物理链路或对端有拥塞。

nmcli

NetworkManager 的命令行接口,适合查看和修改持久化的网络配置。device status 看设备,connection show 看连接配置,modify 改属性后要 up 生效。

nmcli device status
nmcli connection show
sudo nmcli connection modify eth0 ipv4.dns '223.5.5.5 119.29.29.29'
sudo nmcli connection up eth0

resolvectl status

查看 systemd-resolved 的 DNS 配置与当前生效的 DNS 服务器。Ubuntu 18.04 之后的桌面/服务器版常用它管理 DNS,/etc/resolv.conf 往往只是指向 stub 的软链接。

resolvectl status
resolvectl query example.com

连通性、DNS 与 HTTP 调试

分层验证:先 ping(ICMP),再 nc(TCP),再 curl(应用层),最后 dig(DNS)。哪一层断就很清楚了。

ping

发送 ICMP 回显请求测连通性与延迟。-c 指定次数(脚本里必加,否则不会停),-i 间隔,-W 超时,-s 指定包大小(用来验证 MTU / 分片问题)。

ping -c 4 223.5.5.5
ping -c 4 -s 1472 example.com
ping -6 -c 4 2400:3200::1

ping 不通不等价于服务不可用——很多主机和云安全组直接禁用 ICMP。判断端口通不通要用 nc 或 curl。

nc(netcat)

测试 TCP/UDP 端口是否可达。-z 只扫描不发送数据,-v 输出详情,-w 设置超时。这是「端口通不通」最直接的判据。

nc -zv 10.0.0.8 3306
nc -zv -w 3 10.0.0.8 80 443
nc -zuv 10.0.0.8 53

有些发行版的 nc 是 ncat 或 netcat-openbsd,选项略有差异;用法不确定时先看 nc -h。连接被拒绝说明端口没在听,超时说明被防火墙或安全组挡住了。

curl

通用 HTTP 客户端。-I 只看响应头,-i 头+体,-L 跟随跳转,-s 静默,-S 静默但显示错误,-o /dev/null 丢弃正文,-w 输出自定义统计,-x 走代理,-k 跳过证书校验(仅测试用),--resolve 绕过 DNS 直接指定 IP。

curl -sS -I https://floash.top
curl -s -o /dev/null -w '%{http_code} %{time_total}s\n' https://floash.top
curl -sS -L -o /tmp/page.html https://example.com
curl -sS --resolve example.com:443:10.0.0.8 https://example.com
curl -sS -X POST -H 'Content-Type: application/json' -d '{"a":1}' https://api.example.com/v1/ping

-w 的 %{time_total} 里 % 在 shell 中不需要转义;但写进 cron 的 crontab 文件时必须写成 \%。

wget

下载文件。--spider 只检查链接是否有效不下载,-O 指定输出文件名,-c 断点续传,--limit-rate 限速。

wget -c https://example.com/big.iso
wget --spider -S https://floash.top/
wget -r -np -k https://example.com/docs/

dig

DNS 查询工具。+short 只输出结果,+trace 从根域开始追踪解析过程,@服务器 指定 DNS,-x 做反向解析,ANY / MX / TXT / CNAME 指定记录类型。

dig +short floash.top
dig +short MX floash.top
dig @223.5.5.5 +short floash.top
dig -x 8.8.8.8 +short
dig +trace floash.top

本机解析结果和公共 DNS 不一致,多半是本机 /etc/hosts 或 resolv.conf 里的内网 DNS 在起作用,用 @223.5.5.5 对比一下就知道。

host / nslookup

比 dig 更简短的 DNS 查询工具。host 输出最干净,nslookup 交互模式适合连续查询。dig 功能最全,脚本解析优先用 dig +short。

host floash.top
host 8.8.8.8
nslookup floash.top

traceroute / mtr

traceroute 显示到目标经过的每一跳及其延迟;mtr 把 ping 和 traceroute 结合起来持续统计每一跳的丢包率,定位「哪一段网络有问题」更准。

traceroute -n -T -p 443 example.com
mtr -n -c 20 --report example.com
mtr -T -P 443 example.com

中间某几跳显示 * 是正常的(路由器不回复 ICMP),只要后面能到就不算故障;要看的是最后几跳的持续丢包。

ab / wrk

简单的 HTTP 压测工具。ab -n 请求数 -c 并发数;wrk 性能更好,支持多线程与 Lua 脚本。只在自己有权限的服务上使用。

ab -n 1000 -c 50 https://example.com/
wrk -t4 -c100 -d30s https://example.com/

压测本机服务时,客户端本身可能先成为瓶颈(端口耗尽、CPU 打满),记得同时看客户端的 CPU 和 ss -s。

端口、连接与流量

「端口被占用」和「连接数暴涨」这两类问题,ss 一个命令就能看清大半。

ss

查看 socket 统计,是 netstat 的现代替代品,速度快得多。-t TCP、-u UDP、-l 只看监听、-n 不解析名字(更快更准)、-p 显示进程(需 root 看别人的)、-a 全部、-s 汇总统计。

ss -tulnp
ss -tnp state established
ss -s
ss -tn state time-wait | wc -l

-tulnp 是排查端口占用最常用的一条:TCP + UDP + 监听 + 不解析名字 + 显示进程。

ss 按地址与状态过滤

src / dst 可以带 IP 或端口过滤;state 支持 established、syn-sent、time-wait、close-wait 等。CLOSE-WAIT 大量堆积通常意味着应用程序没有正确关闭连接。

ss -tn dst :3306
ss -tn state close-wait | head -20
ss -tn 'sport = :443' | wc -l

lsof -i

用进程视角看网络连接。-i :端口 查谁占着端口,-i @IP 按远端地址过滤,-i -sTCP:LISTEN 只看监听,-nP 不解析名字和端口号。

sudo lsof -i :8080
sudo lsof -i -sTCP:LISTEN -nP
sudo lsof -i @10.0.0.8:5432

ss -tulnp 只能看到监听进程,lsof 还能看到哪个进程持有某个已建立的连接,用于确认「到底是谁在连着数据库」。

iftop / nload / nethogs

实时流量工具:iftop 按连接显示带宽,nload 按网卡显示曲线,nethogs 按进程显示流量(找出「谁在偷跑带宽」最直接)。都需要 root 和单独安装。

sudo iftop -nNP -i eth0
sudo nethogs eth0
nload eth0

/proc/net 与网卡计数

/proc/net/dev 给出每张网卡的收发字节与丢包计数;/proc/net/tcp 是十六进制形式的连接表。排查丢包时也可以直接看 ip -s link 的统计。

cat /proc/net/dev
ip -s link show eth0
awk 'NR>2 {print $1, $3, $4}' /proc/net/dev

sar -n DEV

查看历史网络流量(sysstat 包,默认每 10 分钟采集一次)。sar -n DEV 1 5 是实时采样 5 次,-f /var/log/sysstat/sa19 可以回看指定日期。

sar -n DEV 1 5
sar -n TCP,ETCP 1 5
sar -f /var/log/sysstat/sa19 -n DEV | tail -20

sar 的价值在于「事后回溯」:线上故障已经过去了,仍然能查到当时的 CPU、内存、I/O、网络数据。

抓包与防火墙

抓包回答「包到底有没有到、有没有回」,防火墙回答「该不该放行」。

tcpdump

命令行抓包。-i any 抓所有网卡,-nn 不解析主机名和端口名,-c 抓够多少包就停,-w 写文件(配合 Wireshark 分析),-A / -X 直接看内容,-s 0 抓完整包。

sudo tcpdump -i any -nn port 80 -c 50
sudo tcpdump -i eth0 -nn host 10.0.0.8 and port 3306
sudo tcpdump -i any -nn -w /tmp/cap.pcap 'tcp[tcpflags] & tcp-syn != 0'
sudo tcpdump -i any -nn -A port 80 | grep -i host

只看到 SYN 没有 SYN-ACK,说明包到了对端但被丢弃或对端没监听;看到大量重复 SYN 说明在重传,通常是链路或对端过载。

nftables(nft)

危险

现代 Linux 的包过滤框架,取代 iptables 成为默认前端。nft list ruleset 查看全部规则,add rule 添加,flush ruleset 清空(危险)。规则按表(table)→ 链(chain)→ 规则(rule)组织。

sudo nft list ruleset
sudo nft list table inet filter
sudo nft add rule inet filter input tcp dport 8080 accept
sudo nft add table inet filter

nft flush ruleset 会一次性清空所有规则,远程操作时可能把自己锁在外面;执行前先确认有带外访问手段或已有的放行规则。

iptables

危险

经典防火墙工具。在多数新发行版上它是 iptables-nft 的兼容前端,规则最终仍由 nftables 执行。-L -n -v 查看(-v 显示匹配计数),-A 追加规则,-I 插入到最前,-D 删除。-t nat 看地址转换。

sudo iptables -L -n -v --line-numbers
sudo iptables -t nat -L -n -v
sudo iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
sudo iptables-save > /root/iptables.bak

iptables -F 会清空规则但并不改变默认策略;如果默认策略是 DROP,清空之后所有流量都会被丢弃。改规则前先 iptables-save 备份。

ufw

危险

Ubuntu / Debian 上的简化防火墙前端。allow / deny / limit 添加规则,status verbose 查看,--dry-run 只预览不执行。加完规则不需要 reload。

sudo ufw status verbose
sudo ufw allow 80/tcp
sudo ufw allow from 10.0.0.0/24 to any port 3306
sudo ufw delete allow 80/tcp

启用 ufw 之前必须先放行 SSH 端口,否则会立刻断开远程连接:sudo ufw allow 22/tcp 再 sudo ufw enable。

firewall-cmd

firewalld(RHEL / CentOS / Fedora 系)的命令行前端。--permanent 才写入持久配置,之后需要 --reload 生效;--add-port 放行端口,--add-service 放行预定义服务。

sudo firewall-cmd --state
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-port=8080/tcp && sudo firewall-cmd --reload
sudo firewall-cmd --permanent --add-service=https

忘记 --reload 或忘记 --permanent 是 firewalld 上最常见的两个失误:前者是规则没生效,后者是重启后规则消失。

sysctl 网络参数

内核网络参数位于 net.* 命名空间。net.ipv4.ip_forward=1 开启转发,somaxconn 控制监听队列上限,tcp_tw_reuse 允许复用 TIME-WAIT 连接。sysctl -p 重新加载 /etc/sysctl.conf。

sysctl net.ipv4.ip_forward
sysctl -a | grep -i somaxconn
echo 'net.core.somaxconn=4096' | sudo tee -a /etc/sysctl.d/99-app.conf && sudo sysctl --system

tcp_tw_recycle 在内核 4.12 之后已被移除,网上老文章里的这条参数现在写进去会报错,用 tcp_tw_reuse 代替。

磁盘、分区与挂载

先分清「空间不够」和「inode 不够」——两者的现象一样,处理方式完全不同。

df

查看各文件系统的容量与使用率。-h 人类可读,-T 显示文件系统类型,-i 查看 inode 使用情况,-x tmpfs 排除内存文件系统。

df -hT
df -i
df -h --output=source,size,used,avail,pcent,target

df 显示空间还有剩余但新建文件报 No space left on device,就去 df -i 看 inode 是不是用满了——大量小文件(session、缓存)是元凶。

du

统计目录实际占用的块数。-s 只输出汇总,-h 人类可读,--max-depth=1 只看一层,-x 不跨越文件系统。配合 sort -hr 就能排出「谁占得最多」。

du -sh /var/log /var/lib /home
du -h --max-depth=1 /var | sort -hr | head -15
du -ah /var/log | sort -hr | head -20

du 统计的是块占用;稀疏文件和硬链接会让它和 ls -l 的结果不一致,用 du --apparent-size 看逻辑大小。

ncdu

交互式磁盘占用分析工具,可上下浏览、直接删除,比自己拼 du + sort 快得多。需要单独安装。

ncdu /var
ncdu -x /

lsblk / blkid

lsblk 以树状显示块设备与分区(-f 附带文件系统类型、UUID、挂载点);blkid 只输出设备的 UUID 与类型,写 /etc/fstab 时用它取 UUID。

lsblk -f
blkid /dev/vdb1
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,UUID

fstab 里用 UUID= 而不是 /dev/vdb1:设备名会随插拔顺序变化,UUID 不会。

mount / umount

挂载和卸载文件系统。mount 不带参数列出所有挂载;-o 传选项(ro、noexec、nosuid、noatime、remount);-a 按 fstab 挂载全部;--bind 把目录挂到另一个位置。

mount | column -t
sudo mount -o remount,rw /
sudo mount --bind /data/app /srv/app
sudo umount /mnt/disk1

卸载报 target is busy 时,用 lsof +D 挂载点 或 fuser -vm 挂载点 找出占用进程,而不是直接 umount -l(lazy 卸载会留下不一致状态)。

fstab 与 mount -a

/etc/fstab 每行六个字段:设备、挂载点、文件系统类型、挂载选项、dump 备份标志、fsck 检查顺序。改完后必须用 mount -a 验证,否则重启可能进入紧急模式。

UUID=xxxx-xxxx /data ext4 defaults,noatime 0 2
sudo mount -a && echo 'fstab OK'

把网络盘或云盘写进 fstab 时加 nofail(挂不上也不阻塞启动)和 x-systemd.automount(按需挂载),能避免开机卡死。

fdisk / parted

危险

分区工具。fdisk -l 列出分区表,fdisk /dev/vdb 进入交互式分区(n 新建、d 删除、p 打印、w 写入);parted 支持更多操作且能直接给出对齐建议。

sudo fdisk -l /dev/vdb
sudo parted /dev/vdb print free
sudo partprobe /dev/vdb

fdisk 的 w 是真正写入分区表;在此之前的所有操作只存在于内存中,退出错按 q 就不会生效。

mkfs / fsck

危险

mkfs.ext4 / mkfs.xfs 创建文件系统(会清空该分区);fsck 检查并修复文件系统,必须在卸载状态下执行,根分区需要在救援模式或重启时检查。

sudo mkfs.ext4 -L data /dev/vdb1
sudo fsck -n /dev/vdb1
sudo fsck -y /dev/vdb1

对已挂载的文件系统跑 fsck 可能造成严重损坏。带 -n 的只读检查是安全的,可以先用它看有没有问题。

LVM:pvs / vgs / lvs

查看物理卷、卷组、逻辑卷。扩展逻辑卷的完整流程是:先 vgextend 扩容卷组,再 lvextend -r 扩容逻辑卷(-r 顺便扩展文件系统),ext4 用 resize2fs、xfs 用 xfs_growfs。

sudo pvs; sudo vgs; sudo lvs
sudo lvextend -r -L +10G /dev/vg0/lv_data
sudo vgextend vg0 /dev/vdc

XFS 只能扩大不能缩小;ext4 可以缩,但必须先 e2fsck -f 再 resize2fs 缩小文件系统,最后才能缩小逻辑卷,顺序反了会丢数据。

find 大文件与旧文件

空间告急时最快的定位方式:按大小或时间排序找出该清理的对象,确认后再删。

sudo find / -xdev -type f -size +500M -printf '%s\t%p\n' 2>/dev/null | sort -nr | head -20
sudo find /var/log -type f -name '*.log' -mtime +30 -ls | head
sudo find / -xdev -type f -name '*.log' -mtime +14 -delete

第二条只列出结果,第三条才真的删除;养成先看不带 -delete 的输出,再补上动作的习惯。

磁盘配额(quota)

按用户或组限制磁盘用量。需要在挂载选项里加 usrquota / grpquota,再用 quotacheck 建库、quotaon 启用;edquota 编辑限制,repquota 查看报告,quota -s 看自己的用量。

sudo quotacheck -cugm /home
sudo quotaon -vug /home
sudo edquota -u alice
sudo repquota -s /home
quota -s

XFS 不用 quotacheck:直接挂载时带 uquota 选项,用 xfs_quota 管理即可。软限制(soft)可以超,超了会进入宽限期,硬限制(hard)是绝对上限。

文件句柄与删除后未释放的空间

df 显示空间没释放但文件已经删了,通常是进程仍持有该文件的句柄。lsof 加 deleted 过滤就能找出来,重启该进程或 kill 之后空间才会真正归还。

sudo lsof -nP | grep deleted | head -20
sudo lsof +L1
sudo truncate -s 0 /proc/$(pgrep -f app)/fd/3

日志文件被 rm 但服务没重启时,服务仍然在往已经不存在的 inode 里写。更好的做法是 logrotate 配合 truncate 或发送信号让服务重新打开文件。

性能定位

先用 uptime / vmstat 判断瓶颈在哪一类资源(CPU、内存、I/O、网络),再往下钻到具体进程。

uptime / w

一行给出当前时间、开机时长、登录用户数和 1/5/15 分钟平均负载。w 还列出每个登录用户正在执行的命令。

uptime
w
cat /proc/loadavg

负载要除以 CPU 核数看:4 核机器上 load 4.0 大约等于满载,load 8.0 表示有明显排队。nproc 查核数。

vmstat

综合报告 CPU、内存、交换、I/O、上下文切换。vmstat 1 每秒刷新。关键列:r 运行队列、b 阻塞进程、si/so 换入换出(非 0 说明内存吃紧)、wa I/O 等待占比、cs 上下文切换、us/sy/id CPU 分布。

vmstat 1 10
vmstat -s
vmstat -d 1

wa 长期偏高说明瓶颈在磁盘;sy 远高于 us 说明大量时间花在内核态(系统调用、网络中断、锁竞争)。

mpstat

按 CPU 核分别统计使用率(sysstat 包)。-P ALL 显示所有核,用来发现「单线程程序把一颗核跑满」这种情况。

mpstat -P ALL 1 5
mpstat 1 5

整体 CPU 只有 15% 但某一颗核 100%,是典型的单线程瓶颈;此时加机器核数没有帮助,要么优化代码要么起多个进程。

iostat

磁盘 I/O 统计。-x 扩展统计,-z 跳过空闲设备,-d 只看设备,-m 以 MB 为单位,1 5 表示每秒采样共 5 次。关键列:%util(设备繁忙度)、await(平均等待毫秒)、r/s w/s(IOPS)。

iostat -xz 1 5
iostat -xm 1

await 明显高于正常值、%util 接近 100% 说明磁盘已经饱和;但 %util 对 SSD / NVMe 参考意义有限,要看 await 和队列深度。

iotop / pidstat -d

iotop 按进程显示实时 I/O(-o 只看有 I/O 的进程,-P 只看进程不显示线程,-a 累计模式);pidstat -d 给出每个进程的读写速率,适合写进脚本或远程抓数据。

sudo iotop -oPa
pidstat -d 1 5
pidstat -u -p $(pgrep -f app) 1

sar

系统活动历史报告器,既能实时采样也能回看历史。sar -u CPU、-r 内存、-b I/O、-n DEV 网络、-q 负载队列,-f 指定历史文件。

sar -u 1 5
sar -r 1 5
sar -b 1 5
sar -q -f /var/log/sysstat/sa19 | tail -20

sar 的默认采集间隔和保留天数由 /etc/sysconfig/sysstat(Debian 系是 /etc/default/sysstat)里的 HISTORY 控制,默认只保留一周左右。

pidstat / ps 精确定位

pidstat 能按进程查看 CPU、内存、I/O 和上下文切换,且支持每秒采样,比 ps 的一次性快照更适合观察趋势。-w 看上下文切换,-r 看缺页,-u 看 CPU。

pidstat -u 1 5
pidstat -w 1 5
pidstat -r -p $(pgrep -f worker.py) 1

strace

跟踪进程的系统调用,是排查「程序卡在哪」的终极手段。-p 附加到运行中的进程,-f 跟踪子进程,-e 过滤调用类型,-T 显示每个调用的耗时,-c 汇总统计。

sudo strace -f -p $(pgrep -f app) -T -e trace=network
strace -c ./app --help
sudo strace -f -e trace=openat,connect -o /tmp/trace.log ./app

strace 会显著拖慢目标进程,生产环境要限时使用(配合 timeout 30 strace ...),并且优先用 -e 收窄跟踪范围。

perf

Linux 原生性能分析工具。perf top 实时看热点函数,perf stat 给出指令数、缓存命中率等计数,perf record + perf report 做采样剖析。

sudo perf top
sudo perf stat -p $(pgrep -f app) sleep 10
sudo perf record -F 99 -p $(pgrep -f app) -g -- sleep 30 && sudo perf report

容器里用 perf 往往需要额外的 capability(PERFMON / SYS_ADMIN)和匹配的内核符号,看不到符号名时先检查这一点。

OOM 与内存诊断

进程被莫名杀掉、日志里出现 Killed,先去 dmesg 找 OOM killer 的记录;再结合 /proc/<pid>/status 的 VmRSS 和 cgroup 的内存限制判断是哪个层面超限。

sudo dmesg -T | grep -i -E 'out of memory|killed process'
grep -E 'VmRSS|VmPeak' /proc/$(pgrep -f app)/status
systemctl show app-api -p MemoryMax -p MemoryCurrent

容器里 OOM 被杀的进程不一定会出现在宿主机的 dmesg 里,还要检查容器运行时的日志和 cgroup 的 memory.events。