Ubuntu硬件信息查询:CPU、GPU、内存、硬盘与一键巡检脚本
2026/9/18 13:02:32 网站建设 项目流程

在 Ubuntu 上查 CPU、GPU、硬盘、内存这些硬件信息,是运维、算法、装机、售后几拨人共同的日常动作。手上这台机器是几核几线程、内存是单条还是双条、显卡跑在什么链路宽度上、NVMe 的健康度还剩多少——这些答案直接决定你后面能不能顺利装上 PyTorch 的 GPU 版本、能不能把 Spark 的内存参数调对、能不能在硬盘彻底罢工之前把数据搬走。可惜现实里太多人是这么干的:装完 Ubuntu,敲一个lscpu看到 64,就以为自己是 64 个物理核;nvidia-smi没报错,就以为 CUDA 环境万事俱备;df -h还有空间,就以为硬盘没事。等到真正跑任务才发现显存不够、CPU 缺 AVX 指令集、M.2 盘已经被写掉了九成寿命。这篇把 Ubuntu 下 CPU、GPU、硬盘、内存的查询链路从头捋一遍,从最基础的lscpufree,到需要动点脑子的dmidecodesmartctlnvidia-smi,最后给一个能打包带走的一键巡检脚本。刚装完系统的可以当检查清单,已经在跑业务的可以当排障手册。

1. 先把需求拆开:你到底想知道什么

硬件信息查询这件事,看起来是一个动作,实际上背后至少藏着三类完全不同的需求。把这三类分清,你才知道该用哪条命令、该看哪个字段,而不是在网上抄一串命令挨个敲一遍,敲完还是不知道机器什么水平。

1.1 三种典型场景,问的问题完全不一样

第一类是装机验货。刚从供应商那里拿到一台服务器或者自己攒了一台工作站,需要确认实物和采购单对不对得上。这时候你关心的是"是不是双路""内存插了几条、插在哪几个槽位""显卡是不是真的那张卡而不是刷了 BIOS 的山寨货""硬盘是不是标的那个型号和容量"。这一类的关键词是核对,对比对象是合同和配置单,所以输出要尽量完整、可存档。

第二类是性能排障。线上服务变慢、训练任务比预期慢一倍、JVM 堆内存老是溢出、Spark 任务频繁 spill 到磁盘。这时候你关心的是"CPU 有没有被降频""内存是单通道还是双通道""是不是跑在 NUMA 远端节点上""GPU 是不是掉到 PCIe x4 了""磁盘 IO 是不是已经打满"。关键词是瓶颈定位,你需要的是实时数据和历史趋势的对照,而不是静态清单。

第三类是环境复现。同事说"我这边跑得好好的,你那边报错了",或者你要在另一台机器上重建一模一样的环境。这时候你关心的是"内核版本、驱动版本、CUDA 版本、glibc 版本、CPU 指令集"这些能让程序行为产生差异的软硬件组合。关键词是差异比对,你需要一份能贴进聊天窗口、能被 diff 的文本快照。

三类需求对应的采集深度差别很大。装机验货要把每条内存的序列号都扒出来,性能排障要连续采样看曲线,环境复现反而只需要少数几个关键字段。我一般是先按第三类的标准采一遍全量,再根据实际问题往深里挖。

1.2 为什么不推荐一上来就装图形化工具

Ubuntu 桌面版下确实有 HardInfo、GNOME 系统监视器这类工具,Windows 那边也有 Victoria、CrystalDiskInfo 这类硬盘检测软件,界面直观。但在服务器场景下,它们基本用不上:一是大部分生产机根本不装桌面环境,二是 SSH 过去没有图形界面,三是图形工具的输出没法进脚本、没法进工单系统。

命令行工具还有一个隐藏优势——可组合lscpu的输出能被grepawk切着用,nvidia-smi支持--query-gpu直接吐 CSV,smartctl-j参数输出 JSON。这意味着你可以把巡检做成定时任务,每天自动抓一份快照,硬盘健康度掉到阈值以下就发告警。这种自动化能力是图形工具给不了的。

提示:Ubuntu 上所有硬件信息最终都来自/proc/sys和几个内核接口(DMI、SMART、NVMe 管理接口)。理解这一点,你就知道为什么有些命令要 root,为什么有些虚拟机里查出来的数据是假的。

2. CPU 信息:别再把逻辑核当物理核

CPU 这一块最容易被误读。nproc返回 64,很多人就直接认为"我这机器 64 核",然后在容器配额、线程池大小、编译并行度这些地方全按 64 来配,结果要么资源争抢,要么利用率上不去。真实情况是,nproc返回的是逻辑处理器数量,和物理核心、插槽、NUMA 节点是两回事。

2.1 lscpu 的每一行都在说什么

lscpu是第一个该敲的命令,它不需要 root,输出干净,字段含义明确。我挑几个真正有信息量的字段解释:

Architecture: x86_64 CPU(s): 64 On-line CPU(s) list: 0-63 Thread(s) per core: 2 Core(s) per socket: 16 Socket(s): 2 NUMA node(s): 2 Model name: Intel(R) Xeon(R) Gold 6248R CPU @ 3.00GHz CPU MHz: 2999.998 CPU max MHz: 4000.0000 CPU min MHz: 1200.0000 L3 cache: 48 MiB Virtualization: VT-x Flags: fpu vme de pse ... avx avx2 avx512f ...

这组数字之间的关系非常好算:

  • 物理核心数 = Socket(s) × Core(s) per socket,也就是 2 × 16 = 32 个物理核。
  • 逻辑 CPU 数 = 物理核心数 × Thread(s) per core,也就是 32 × 2 = 64,和CPU(s)对得上。
  • NUMA 节点数反映内存访问的非一致性,2 路机器通常就是 2 个节点。

为什么这个区分很重要?举两个实际例子。第一个是编译:make -j64在 32 物理核 + 超线程的机器上,通常比make -j32更慢,因为编译是计算密集型任务,超线程带来的额外吞吐抵不过缓存争抢。第二个是线程池:Java 应用里常见的Runtime.getRuntime().availableProcessors()拿到的是逻辑核数,如果你在容器里没做 CPU limit,它可能返回宿主机全部的核心数,然后 JVM 按这个数字去开 GC 线程和 ForkJoinPool 线程,在只有 2 核配额的环境里直接把自己拖死。

CPU MHz 和 CPU max MHz 的差值也值得看一眼。如果CPU MHz长期明显低于 max,要么是 BIOS 里关掉了 Turbo,要么是散热压不住在被动降频,要么是powersave调频策略在省电。cpupower frequency-info能看到当前的 governor,服务器上一般建议设成performance

2.2 /proc/cpuinfo 与指令集核对:AVX 这个坑

/proc/cpuinfolscpu的原始数据源,字段更碎但更全。它按逻辑处理器逐个列出,所以你想看某个特定核心的信息可以精确到processor : 37那一段。常用的提取方式:

# 只看物理 CPU 的 model name,去重 grep -m1 'model name' /proc/cpuinfo # 统计逻辑处理器数量 grep -c '^processor' /proc/cpuinfo # 查看物理 ID 和每颗物理 CPU 的核心数 grep -E 'physical id|cpu cores' /proc/cpuinfo | sort -u # 直接看指令集 grep -m1 '^flags' /proc/cpuinfo | tr ' ' '\n' | grep -E '^avx'

最后一个命令是我强烈建议每个人都跑一次的。指令集不匹配是个典型的"编译期看不出来、运行期直接崩"的问题。很多生信工具、深度学习框架预编译包、数学库(比如某些 BLAS 实现)在构建时启用了 AVX、AVX2 甚至 AVX-512。如果你把这类二进制拿到一台只有 SSE4 的老 CPU 上跑,程序可能启动就直接退出,报一句类似 "this CPU does not support avx, which is required" 的错误,连日志都不给你留。这不是软件坏了,是硬件真的不支持。

所以装机验货时,除了核对型号和核数,把avxavx2avx512ffma这几个 flag 记下来很有必要。后面要部署什么框架,先拿这份清单对一遍,能省掉大量无谓的排查时间。

注意:容器里读/proc/cpuinfo看到的是宿主机的 CPU 信息,不是分配给容器的资源。想知道 cgroup 到底给了你多少 CPU,得看/sys/fs/cgroup/cpu.max(cgroup v2)或者/sys/fs/cgroup/cpu/cpu.cfs_quota_us(v1)。lscpu加了-e参数也一样会显示宿主机的拓扑。

2.3 NUMA 与多路机器:numactl 补位

双路及以上的机器,内存访问是有远近之分的。每个 CPU 插槽旁边挂着一组内存控制器和对应的内存条,这就是一个 NUMA 节点。CPU 访问自己节点的内存(local)延迟低、带宽高,访问另一个节点的内存(remote)要跨 QPI/UPI 总线,延迟和带宽都要打折扣。

lscpu只告诉你节点数量,想看清每个节点的 CPU 和内存分布,用numactl --hardware

sudo apt install numactl -y numactl --hardware

输出里会列出node 0 cpusnode 0 sizenode 0 freenode distances等。node distances那一张矩阵很关键,对角线是 10(自己到自己),跨节点通常是 21 左右,数字越大跨得越贵。

这对什么场景有影响?数据库(MySQL、Redis)、大内存 JVM 应用、Spark Executor、还有做大规模数值计算的进程。如果进程的内存被分配在了远端节点而 CPU 在本地,性能可能直接掉 20% 到 40%。解决办法一般是在启动命令前加numactl --cpunodebind=0 --membind=0把进程绑死在某个节点,或者更省事地开启自动 NUMA 均衡(numactl --show能看到当前策略)。

我见过最典型的翻车是:一台双路机器,Spark Executor 的堆设得比单节点内存还大,结果一半内存跨了节点,GC 时间翻倍。后来把 Executor 内存压到单节点容量以内,问题立刻消失。

3. 内存:容量之外的三个关键维度

提到内存,大部分人的第一反应是"多大"。但容量只是最表层的一个数字,真正影响性能的是通道数、频率、插槽排布这三件事,而这三件事恰好是free完全看不出来的。

3.1 free 与 /proc/meminfo:available 才是你要看的数

free -h是最常用的命令,但它的输出常被误读。看一段典型输出:

total used free shared buff/cache available Mem: 251Gi 38Gi 3.2Gi 1.1Gi 210Gi 208Gi Swap: 8.0Gi 0B 8.0Gi

最容易踩的坑是看到free只剩 3.2Gi 就慌了,觉得内存要爆了。实际上 Linux 会把空闲内存大量用作文件缓存(buff/cache),这部分内存随时可以回收给应用。真正该看的是available,也就是"在不触发 swap 的前提下,还能给新进程用多少内存"。上面这个例子里available有 208Gi,机器其实很闲。

buff/cache拆开看是两个不同的东西:buffers是块设备元数据的缓存,cached是文件内容的页缓存。绝大多数情况下cached占大头。如果你确实想手动释放(比如做内存基准测试前需要干净环境),可以:

sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

但这只是把缓存丢掉重建,纯粹为了测量准确,日常千万别当优化手段用。

shared那一列也要留意。它统计的是 tmpfs 和共享内存段占用的内存,/dev/shm就在里面。数据库、Chromium 系浏览器、某些 JVM 应用都会用大量共享内存。如果你发现内存被吃掉但ps aux排序找不到大户,去df -h /dev/shm看一眼。

还有一个新手常问的问题:"我买了 32G 内存,系统只认 31.2G 是不是被坑了"。不一定。原因通常是集显显存共享(核显会从物理内存里划走一块)、内核保留区域、或者 DMI 中的保留段。想确认物理内存条的原始容量,得靠dmidecode

3.2 dmidecode 看清内存条本身

dmidecode读取的是主板 DMI/SMBIOS 表,也就是主板固件里记录的硬件描述信息。它能告诉你物理内存条的单条容量、类型、频率、厂商、型号、序列号,以及插在了哪个槽位。这是装机验货时最有用的一条命令:

# 先看整机内存阵列的总体信息(最大支持容量、插槽总数) sudo dmidecode -t 16 # 再看每一根内存条的详细信息 sudo dmidecode -t 17

一条健康的内存条信息大概长这样:

Memory Device Total Width: 72 bits Data Width: 64 bits Size: 32 GB Locator: DIMM_A1 Bank Locator: NODE 0 Type: DDR4 Speed: 3200 MT/s Manufacturer: Samsung Serial Number: 3xxxxxxx Part Number: M393A4K40DB3-CWE Rank: 2 Configured Memory Speed: 2933 MT/s Minimum Voltage: 1.2 V

这里有三个点值得专门看:

槽位(Locator)。它告诉你这根条插在哪个物理插槽。如果你看到所有内存条都插在DIMM_A1DIMM_A2这种同一通道的相邻槽位,那很可能没组成双通道。正确的双通道插法是隔槽插,比如 A1+B1、A2+B2,具体要看主板手册。

标称速度与配置速度的差异。上面例子里Speed是 3200 MT/s 但Configured Memory Speed只有 2933 MT/s。这说明内存条本身支持 3200,但实际运行被降到了 2933。原因通常是 CPU 内存控制器上限、主板 BIOS 的内存频率设置、或者混插了不同频率的条子导致全部按最低的那条跑。这个差异对性能有实际影响,值得追一下。

Rank。单 Rank 和双 Rank(或者四 Rank)在同样的频率下带宽和延迟表现不同。大容量条子常常是双 Rank 或四 Rank,单条带宽更高但时序可能略松。这个属于进阶话题,装机时知道有这回事就够了。

注意:虚拟机里dmidecode返回的是虚拟化平台伪造的信息,字段可能残缺或者根本不准,比如显示"最大支持容量 0"。这种情况下不要拿它的输出做任何判断。另外dmidecode需要 root 权限,因为它读的是原始固件表。

3.3 通道、频率与带宽的粗略估算

内存带宽的估算公式很简单:

带宽(GB/s)= 传输速率(MT/s) × 位宽(bit) / 8 × 通道数

单条 DDR4-3200 的位宽是 64 bit,代入计算:3200 × 64 / 8 = 25.6 GB/s。如果是双通道,就是 51.2 GB/s;四通道则是 102.4 GB/s。

这个数字为什么重要?因为它决定了你的内存敏感型任务的天花板。做 Spark 大数据处理、跑大内存 JVM 应用、用核显做推理、搞大规模矩阵运算,这些场景经常是带宽受限而不是算力受限。同样是 32G 内存,双通道和单通道能差出 30% 以上的实际性能。而free命令完全看不出通道数,只能靠dmidecode -t 17里的槽位分布去推断。

时序(CL、tRCD、tRP、tRAS)在dmidecode的标准输出里看不到,需要主板支持并开启 XMP/EXPO 后在 BIOS 里查看,或者用decode-dimms之类的工具(需要加载eeprom内核模块)。对绝大多数业务场景来说,时序的收益远小于通道数,装机时优先保证通道插满,别在时序上纠结。

4. GPU:从"卡在不在"到"能不能跑起来"

GPU 这块的查询需求层次非常分明,可以分成三层:硬件在不在驱动通不通版本配不配。三层依次推进,不要跳步。很多人一上来就nvidia-smi报错,然后开始瞎折腾驱动重装,其实问题可能出在第一步——卡根本没被识别。

4.1 第一层:lspci 确认硬件在位

lspci列出所有 PCI 设备,不依赖任何显卡厂商驱动,是最底层的检查手段:

# 列出所有显示相关设备 lspci | grep -Ei 'vga|3d|display' # 更详细,显示内核正在使用哪个驱动 sudo lspci -k | grep -A3 -Ei 'vga|3d|display' # 用 lshw 看更结构化的信息 sudo lshw -C display

输出类似:

01:00.0 VGA compatible controller: NVIDIA Corporation GA102 [GeForce RTX 3090] (rev a1) Subsystem: NVIDIA Corporation Device 1470 Kernel driver in use: nvidia Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia

几个关键判断点:

卡的型号对不对GA102 [GeForce RTX 3090]里的GA102是 NVIDIA 的核心代号,比零售型号更难伪造。如果采购单写的是 A100 但这里显示 GA102,那问题就大了。

Kernel driver in use是什么。如果显示nouveau,说明开源的 nouveau 驱动在占着卡,专有驱动没有生效。这时候nvidia-smi大概率会报错或者找不到设备。如果显示nvidia,说明专有驱动已经接管。如果这一行是空的,说明卡还没被任何驱动绑定。

设备有没有出现在多个 PCI 地址上。多卡机器上你会看到01:00.002:00.041:00.0这样的一串。如果数量比预期少,可能是卡没插好、PCIe 供电不足、或者 BIOS 里某个插槽被禁用了。

显示设备上还可能挂着音频控制器(HDMI 音频),比如01:00.1 Audio device: NVIDIA Corporation ...。这部分不用管,但别把它当成第二张显卡数错了。

4.2 第二层:nvidia-smi 字段逐条读

nvidia-smi是 NVIDIA 专有驱动自带的工具,能正常工作本身就说明驱动装对了。默认输出长这样:

+-----------------------------------------------------------------------------+ | NVIDIA-SMI 535.129.03 Driver Version: 535.129.03 CUDA Version: 12.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 NVIDIA RTX 3090 Off | 00000000:01:00.0 Off | N/A | | 30% 38C P8 22W / 350W | 4MiB / 24576MiB | 0% Default | +-------------------------------+----------------------+----------------------+

逐条看:

Driver Version是内核态驱动的版本,CUDA Version是驱动支持的最高 CUDA 运行时版本,不是你当前装的 CUDA Toolkit 版本。这两个概念经常被混。想知道实际装了什么版本,得看nvcc --version或者python -c "import torch; print(torch.version.cuda)"。一个常见的误区是:驱动显示 CUDA 12.2,就以为一定要装 CUDA 12.2 的 PyTorch。实际上驱动向下兼容,装 cu118 的 PyTorch 完全没问题。

Temp 和 Fan。数据中心卡(A100/H100)的温度上限一般在 85 度左右,超过会触发降频。消费卡可以到 90 度以上。如果满载时温度贴着上限,说明风道有问题或者风扇策略太保守。

Pwr:Usage/Cap。这一栏能看出实时功耗和功耗墙。如果 GPU 满载时功耗远低于 Cap,可能是遇到了 CPU 瓶颈、显存瓶颈,或者数据中心卡被设置了nvidia-smi -pl限功耗。

Perf是一个性能状态标记,P0 到 P12 加上 P8,P0 是最高性能,P8 是空闲。训练时如果一直停在 P5/P8,说明任务根本没真正压上去。

Memory-Usage显示已用显存和总显存。这里有件很重要的事:显存被占用不代表进程还在跑。如果进程异常退出而没有正确释放,显存可能处在僵死状态,表现为nvidia-smi里看不到进程但显存被吃掉一大块。这种情况可以用nvidia-smi --gpu-reset -i 0重置(会中断该卡上所有任务,慎用)。

GPU-Util是采样周期内 GPU 有任务执行的时间占比。这个数字高不代表效率高——如果 kernel 很小、启动开销大,利用率可以很高但吞吐很低。

想批量抓结构化数据,用 query 模式:

nvidia-smi --query-gpu=index,name,memory.total,memory.used,utilization.gpu,temperature.gpu,power.draw,compute_cap --format=csv

这个格式直接就是 CSV,扔进 Excel 或者喂给监控系统都很方便。

提示:nvidia-smi -L只列出卡名,适合写进巡检脚本的头部。nvidia-smi topo -m显示卡间互联拓扑,多卡机器必看。nvidia-smi -q输出全量信息,包括 ECC 错误计数、PCIe 链路宽度和速率,排障时很有用。

4.3 第三层:算力与框架版本的匹配

拿到显卡型号后,最关键的一步是查它的Compute Capability(计算能力),也就是 SM 版本号。这个数字决定了 PyTorch、PaddlePaddle 等框架的预编译版本能不能直接跑。

nvidia-smi --query-gpu=compute_cap --format=csv,noheader可以直接查到。常见的对应关系我整理成表:

显卡系列核心代号Compute Capability常见用途
GTX 10 系GP104/GP1026.1入门实验
RTX 20 系TU102/TU1047.5中等规模训练
RTX 30 系GA102/GA1048.6主流训练推理
RTX 40 系AD102/AD1038.9主流训练推理
A100GA1008.0数据中心训练
H100GH1009.0大模型训练

这张表怎么用?举个例子:PyTorch 官方预编译包通常会为一个 CUDA 版本同时编译多个 SM 架构。如果你装的是老版本 PyTorch(比如 1.12),它可能只编到 sm_86,那在 RTX 40 系(sm_89)上跑就会出现"能跑但没优化"或者直接报架构不支持的警告。同理,装 PaddlePaddle 的 GPU 版本时也要注意它的预编译包覆盖了哪些架构。

还有一个相关的概念叫CTA(Cooperative Thread Array),也就是 CUDA 里的线程块。这是编程模型层面的东西,硬件查询阶段用不上,但理解它有助于你解释为什么有些 kernel 在特定卡上跑不满——因为线程块的数量和大小受 SM 数量、每 SM 最大驻留块数的限制,卡不同,这些上限就不同。

驱动版本与环境匹配的实操顺序,我一般按这个流程走:

  1. lspci确认卡在位,记下型号和核心代号。
  2. nvidia-smi确认驱动正常,记下驱动版本和支持的 CUDA 上限。
  3. nvidia-smi --query-gpu=compute_cap拿到 SM 版本。
  4. 去框架官网的版本对照表,选一个 CUDA 版本不高于驱动支持上限、且覆盖了你的 SM 版本的预编译包。
  5. 装完跑一句python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"验证。

这套流程走下来,基本不会出现装完了才发现跑不起来的情况。

4.4 多卡机器:拓扑比数量更重要

8 卡机器上,卡和卡之间的通信路径差别巨大,直接影响分布式训练的效率。nvidia-smi topo -m会输出一张矩阵:

GPU0 GPU1 GPU2 GPU3 CPU Affinity NUMA Affinity GPU0 X NV12 NV12 NV12 0-31 0 GPU1 NV12 X NV12 NV12 0-31 0 GPU2 NV12 NV12 X NV12 0-31 0 GPU3 NV12 NV12 NV12 X 0-31 0

矩阵里的标记含义:

  • NV#表示通过 NVLink 连接,#是链路数量,数字越大带宽越高。
  • PIX表示同一 PCIe 交换机下的两块卡。
  • PHB表示经过 PCIe Host Bridge。
  • SYS表示跨 NUMA 节点,走的是 CPU 之间的互联总线,最慢。
  • X是自己和自己。

为什么要看这个?假设你要跑 4 卡数据并行训练,如果卡之间全是SYS,梯度同步会变成瓶颈,加速比可能只有 2 倍出头。而同样是 4 卡,如果都是NV4或以上,加速比能接近线性。这时候解决方案是调整CUDA_VISIBLE_DEVICES的卡号组合,把拓扑近的卡分到一组。

另外注意CPU AffinityNUMA Affinity两列。它们告诉你每张卡物理上挂在哪个 CPU 的 PCIe 通道下。做多卡训练时,进程的数据加载线程最好绑到同一 NUMA 节点的 CPU 上,否则会出现"DMA 跨节点"的额外开销。

5. 硬盘与存储:容量只是最不重要的一项

硬盘这块的认知偏差可能是最大的。绝大多数人只关心df -h还剩多少空间,而真正会导致事故的——健康度衰减、文件系统类型、inode 耗尽、被删除但仍被占用的文件——全都被忽略了。

5.1 lsblk 一图看清设备拓扑

lsblk是我最喜欢的磁盘命令,它用树状结构展示块设备的层级关系,一眼就能看出哪块盘分了哪些区、挂了什么文件系统、挂载在哪里:

lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,ROTA,MODEL

输出:

NAME SIZE TYPE FSTYPE MOUNTPOINT ROTA MODEL nvme0n1 953.9G disk 0 SAMSUNG MZVL21T0HCLR-00B00 ├─nvme0n1p1 512M part vfat /boot/efi 0 ├─nvme0n1p2 928G part ext4 / 0 └─nvme0n1p3 25.4G part swap [SWAP] 0 sda 1.8T disk 1 WDC WD20EZBX-00AYRA0 └─sda1 1.8T part ext4 /data 1

ROTA 字段是区分机械和固态的老办法:ROTA=1(Rotational)是机械盘,0是固态。但这个方法不严谨,因为 USB 移动硬盘、某些虚拟块设备也可能报 0。更准确的判断要看TRAN 字段

lsblk -d -o NAME,ROTA,TRAN,SIZE,MODEL

TRAN会显示nvmesatausbscsi之类的实际传输类型。这样你就能确认一块 M.2 盘到底走的是 NVMe 协议还是 SATA 协议——外观一样,速度差三倍以上,采购时被坑过的人应该深有体会。

/dev/nvme0n1/dev/sda的命名差异也值得记一下。NVMe 设备走的是独立的驱动栈,命名规则是nvme<控制器号>n<命名空间号>,分区再加p<分区号>。而 SATA/SAS 设备走 SCSI 子系统,用sd<字母>加数字分区。所以你会看到nvme0n1p1sda1这两种画风完全不同的写法。

想更详细地看 NVMe 设备信息,装个nvme-cli

sudo apt install nvme-cli -y sudo nvme list sudo nvme id-ctrl /dev/nvme0 -H | head -50

nvme list会给出一张很清爽的表,包含设备节点、SN、型号、固件版本、容量、已用百分比。其中**已用百分比(Used)**是 NVMe 自己报的健康度指标,很直观。

5.2 SMART:健康度才是重点

SMART 是硬盘自带的健康监测系统,能提前预警故障。Ubuntu 上用它需要装smartmontools

sudo apt install smartmontools -y sudo smartctl -i /dev/sda # 设备基本信息 sudo smartctl -H /dev/sda # 健康状态总览 sudo smartctl -a /dev/sda # 全部属性

机械盘和固态盘关注的属性完全不同,我分开说。

机械盘(SATA)关注这几项

属性 ID名称关注点
5Reallocated_Sector_Ct重映射扇区数,任何非零增长都是危险信号
187Reported_Uncorrect无法纠正的错误数,应为 0
197Current_Pending_Sector待重映射扇区,非零说明有读不出来的扇区
198Offline_Uncorrectable离线扫描发现的不可纠正错误
199UDMA_CRC_Error_Count传输链路 CRC 错误,通常是线材或接口问题

对机械盘来说,最危险的组合是5 和 197 同时非零且在增长。这意味着盘片上有物理坏道,并且已经在扩散。从原理上讲,硬盘写入数据时要先按磁道和扇区定位,读回时校验,一旦某个扇区的校验反复失败,固件就会把它标记出来并尝试重映射到备用区。备用区是有限的,用完了盘就彻底废了。所以看到这两项涨,别犹豫,立刻做全盘备份然后换盘。

固态盘(NVMe)关注这几项

Percentage Used: 12% Available Spare: 100% Available Spare Threshold: 10% Media and Data Integrity Errors: 0 Error Information Log Entries: 0 Temperature: 38 Celsius Power On Hours: 8,760 Data Units Written: 152,345,678 [78.0 TB]

Percentage Used是厂商根据写入量估算的寿命消耗百分比,注意这是估算值,不是精确的剩余寿命。Available Spare是剩余备用块比例,掉到 Threshold 以下就进入只读或者告警状态。Media and Data Integrity Errors理论上应该永远是 0,一旦非零说明闪存颗粒层面出现了不可纠正错误,这是最严重的信号。

Data Units Written特别值得关注。固态盘的闪存颗粒有擦写次数上限(TLC 通常 1000-3000 次 P/E),换算成 TBW(总写入字节数)就是厂商标的寿命指标。1TB 的消费级 NVMe 一般标 600 TBW 左右,企业级能到 1-3 PBW。如果你的盘一年就写了 78 TB,按这个速度跑下去三四年就到寿命了。这就是为什么数据库、日志服务器、缓存节点上的盘要专门选高耐写型号。

注意:USB 硬盘盒和部分扩展卡不透传 SMART 命令,smartctl -a会报 "Unable to detect device type"。这时候换台机器直连主板 SATA 口再测,或者换支持 UASP 且透传 SMART 的硬盘盒。另外 RAID 控制器后面的盘,需要-d megaraid,N之类的设备类型参数才能读到。

5.3 容量、inode 与被删除文件

df -h看容量,df -i看 inode。这两个必须一起看,因为**"磁盘明明还有空间但就是写不进去"**这个经典故障,八成是 inode 用尽了。inode 是小文件系统里为每个文件分配的元数据结构,数量在格式化时就定死了。如果你的应用会产生海量小文件(比如邮件队列、缓存目录、会话文件),inode 会先于空间耗尽。

df -h # 看块空间 df -i # 看 inode 使用率 du -sh /* 2>/dev/null | sort -h # 从根开始找占用大户 du -sh /var/* | sort -h # 逐层下钻

还有一个更隐蔽的情况:df显示已用和du算出来的总和对不上。典型场景是某个进程正在写一个大日志文件,你rm掉了它,但进程还持有文件句柄,内核就不会真正回收这块空间。表现就是磁盘满了,但怎么找都找不到那个文件。

排查命令:

# 找出所有被删除但仍被进程占用的文件 sudo lsof +L1 # 或者用 lsof 过滤 deleted 标记 sudo lsof | grep deleted | head -20

找到对应的 PID 后,重启那个进程,或者用> /proc/<pid>/fd/<fd>把文件清空(注意是清空不是删除)。这个坑我在日志服务上踩过一次,深夜磁盘告警,找了一个多小时才发现是一个没配好日志轮转的服务。

顺带说一下分区规划。1T 的盘怎么分,我的习惯是:EFI 分区 512M(或 1G)、根分区 100-200G、剩余全部给数据分区单独挂载。根分区太大的坏处是系统盘和业务盘混在一起,做快照、做备份、做迁移都不方便;太小的坏处是/var里的日志、Docker 镜像、包缓存容易把它撑爆。现在主流的做法其实是不给/home单独分区,而是给业务数据一个独立挂载点,系统盘的容量问题交给日志轮转和容器存储清理来解决。

6. 打包成脚本:一次采集,到处交差

零散敲命令适合现场排查,但如果你经常要给不同机器做体检,或者需要把机器的硬件信息存档、发给采购、贴给同事做对比,手动敲就太低效了。写一个巡检脚本,跑一次生成一份完整报告,后面省下的是几十次重复劳动。

6.1 脚本设计上的几个取舍

写这类脚本我有几个固定原则,先说清楚理由:

输出到文件而不是只打印到屏幕。SSH 会话断掉、终端滚动条冲掉、需要发给别人——这三种情况都会让你后悔没存文件。默认按主机名_时间戳命名,天然带版本。

每一条命令都容错。不要在脚本开头写set -e,一条命令失败就整体退出,那你拿到的是半份报告。正确的做法是让每条命令独立执行,失败就打印一行提示继续往下走。所以我用的组合是set -uo pipefail而不加-e

区分需要 root 和不需要 root 的部分dmidecodesmartctlnvme都要 root,但lscpufreelsblknvidia-smi不要。如果脚本一上来就要求 root,很多人的日常使用场景就被劝退了。我的做法是自动检测:如果是 root 就采全量,不是 root 就跳过需要权限的部分并显式标注"未采集"。

统一 locale。不同机器的语言环境不一样,df输出的表头和错误信息可能是中文,脚本解析就会出问题。在脚本开头设置export LC_ALL=C能规避这一整类问题。

GPU 部分要能优雅降级。没装 NVIDIA 驱动的机器上nvidia-smi会报 command not found,脚本不应该因此出错,直接写一句"未检测到 nvidia-smi"就行。

6.2 完整脚本

下面这个脚本我用了几年,改过好几版,可以直接抄:

#!/usr/bin/env bash # hwreport.sh - Ubuntu 硬件信息一键采集 # 用法: bash hwreport.sh [输出文件路径] set -uo pipefail export LC_ALL=C HOST=$(hostname) OUT="${1:-hwreport_${HOST}_$(date +%Y%m%d_%H%M%S).txt}" IS_ROOT=0 [ "$(id -u)" -eq 0 ] && IS_ROOT=1 sec() { printf '\n\n========== %s ==========\n' "$1" >>"$OUT"; } run() { "$@" >>"$OUT" 2>&1 || echo "[命令失败: $*]" >>"$OUT"; } need_root() { [ "$IS_ROOT" -eq 1 ] || echo "[需要 root,已跳过]" >>"$OUT"; } : >"$OUT" echo "硬件巡检报告 主机: ${HOST} 时间: $(date '+%F %T') 用户: $(id -un)" >>"$OUT" sec "0. 系统概况" run uname -a run cat /etc/os-release run uptime sec "1. CPU" run lscpu { echo "--- 指令集关键项 ---" grep -m1 '^flags' /proc/cpuinfo | tr ' ' '\n' \ | grep -E '^(avx|avx2|avx512f|fma|sse4_2)$' | sort -u } >>"$OUT" 2>&1 sec "2. 内存" run free -h if [ "$IS_ROOT" -eq 1 ]; then run dmidecode -t 16 run dmidecode -t 17 else need_root fi run numactl --hardware sec "3. GPU" if command -v nvidia-smi >/dev/null 2>&1; then run nvidia-smi run nvidia-smi --query-gpu=index,name,memory.total,memory.used,utilization.gpu,temperature.gpu,power.draw,compute_cap --format=csv run nvidia-smi topo -m else echo "未检测到 nvidia-smi,跳过 NVIDIA GPU 信息" >>"$OUT" fi run bash -c "lspci | grep -Ei 'vga|3d|display'" sec "4. 存储设备" run lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,ROTA,TRAN,MODEL run bash -c "df -hT | grep -v tmpfs" run bash -c "df -i | grep -v tmpfs" if [ "$IS_ROOT" -eq 1 ]; then command -v smartctl >/dev/null 2>&1 && \ for d in $(lsblk -dpno NAME | grep -E '/dev/(sd|nvme)'); do echo "--- SMART: $d ---" >>"$OUT" smartctl -H -A "$d" >>"$OUT" 2>&1 done command -v nvme >/dev/null 2>&1 && run nvme list else need_root fi sec "5. 网络" run bash -c "ip -br addr" run bash -c "ip -br link" sec "6. 内核模块与驱动" run bash -c "lsmod | grep -E 'nvidia|nvme|megaraid|mpt3sas'" echo "报告已生成: $OUT"

6.3 输出解读与归档

脚本跑完后会得到一个文本文件。我的习惯是把它连同机器编号一起存进一份内部文档,按时间倒序排列。这样做的价值在于趋势对比:硬盘的Percentage Used三个月涨了多少、内存有没有被人偷偷拔走一条、GPU 温度在夏天是不是明显更高——这些问题只有和历史快照对比才看得出来。

如果是给采购或者供应商核对配置,我会用diff把到货机器的报告和配置单逐项过一遍,重点看dmidecode -t 17里的型号、容量、数量和槽位。别看这一步枯燥,我见过内存条型号被换、固态被换成低耐写型号的情况,都是在这一步发现的。

7. 常见问题与排查技巧实录

前面讲了正常路径,这一节讲不正常路径。下面这些是我在实际操作中反复遇到的坑。

7.1 速查表

现象可能原因排查方向
nvidia-smi: command not found专有驱动未安装lspci -k看驱动是否为 nouveau,装ubuntu-drivers
nvidia-smi报 No devices were found驱动与内核模块不匹配 / Secure Boot 阻止加载`dmesg
free显示内存比标称少几个 G核显共享显存、内核保留段dmidecode -t 17核对物理条容量
dmidecode报 No SMBIOS 或数据异常虚拟机环境 / 权限不足物理机加 sudo 重试,虚拟机直接放弃
smartctl报 Unable to detect device typeUSB 硬盘盒不透传 SMART换直连 SATA/NVMe 接口测试
磁盘有空间但写入失败inode 耗尽df -i检查,du找小文件目录
dfdu结果对不上被删除但仍被占用的文件lsof +L1,重启持有句柄的进程
容器里lscpu显示几十核读的是宿主机信息/sys/fs/cgroup/cpu.max确认配额
内存占用高但找不到进程buff/cache 或共享内存free -h的 available,检查/dev/shm
GPU 利用率高但吞吐低kernel 太小或数据加载瓶颈看功耗是否贴近 Cap,检查 CPU 与 IO

7.2 几条用血换来的经验

第一条:所有硬件信息的判断都要有基准,没有基准就没有结论。"内存 2933 MT/s"这个数字本身说明不了任何问题,只有和内存条标称值、CPU 支持上限、同批机器对比之后才有意义。所以我在接手新机器时,第一件事就是采一份完整快照存在仓库里,后面所有异常都拿它做参照。

第二条:不要相信单次采样。GPU 利用率、CPU 频率、温度这些指标都是瞬时值,你nvidia-smi看到 0% 不代表卡闲,可能只是刚好在两次采样之间。排查性能问题至少要连续观察几分钟。我一般用nvidia-smi --query-gpu=... --format=csv -l 2每两秒刷一次,或者直接watch -n 2配合。

第三条:SSH 到别人的机器前,先问清楚能不能提权。很多只读信息(lscpufreelsblk)不需要 root,但dmidecodesmartctlnvme都需要。如果对方只给你普通账号,你拿到的报告会缺一半。提前问清楚,别到现场才发现权限不够。

第四条:把巡检脚本加入开机自启或者定时任务。硬盘故障、内存条掉线这类问题,往往是渐进式的。与其等到服务崩了再去查,不如每天凌晨自动采一份,用脚本对关键字段做阈值判断——Percentage Used超过 80%、Reallocated_Sector_Ct大于 0、Available Spare低于阈值,任何一个触发就告警。这个成本很低,收益极高。

第五条:报告要能一眼看出重点。前几版脚本我是把所有命令的原始输出一股脑塞进文件,结果一页一页全是lspci的几百行内容。后来我把命令重新排了序,把最关键的信息(核数、内存总容量、GPU 型号与算力、磁盘健康状态)放在脚本最后单独做一个小结区块。这样别人拿到报告,只看最后一段就知道机器什么水平。

最后再分享一个我自己常用的小技巧:把hwreport.sh放到 U 盘里,加上chmod +x,装机现场不需要任何依赖就能跑。脚本里所有工具(lscpufreelsblklspci)都是 Ubuntu 基础系统自带的,只有smartmontoolsnvme-clinumactl需要额外装,而且脚本对这些缺失工具都做了容错处理,不会因为少一个包就跑不下去。实测在一台刚装好的最小化 Ubuntu 上,这份报告能有 90% 的采集完整度,剩下 10% 装完包补采一次就够了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询