1
2
3
4
5
6
7
作者:李晓辉

联系方式:

1. 微信:Lxh_Chat

2. 邮箱:939958092@qq.com

很多人学习 Linux 性能调优的时候,第一反应就是:

1
2
3
top
vmstat
iostat

然后开始盯着 CPU 利用率、内存使用率、磁盘 IO 一顿分析。这当然没有错。但是在真实的生产环境里,我见过不少性能问题,最后定位下来,根本不是 Linux 参数没调好,也不是应用配置有问题,而是——硬件本身就已经决定了这台服务器的性能上限。

比如:

  • 应用跑得慢,最后发现服务器只有 2 个 CPU 核心;
  • 数据库频繁读盘,最后发现内存只有 4GB;
  • 虚拟机 Load 很高,进一步排查才发现底层存储性能很差;
  • 网络吞吐怎么都上不去,最后发现网卡只有 1Gbps;
  • 明明业务文档写的是 8GB 内存,操作系统实际只能使用其中一部分。

所以,如果你一上来就执行:

1
top

然后看到:

1
CPU  80%

就开始研究 CPU 为什么这么高,很可能从第一步就走偏了。因为在性能分析之前,还有一个非常基础的问题需要先回答:

这台服务器到底长什么样?

医生看病之前,通常要先量体温、测血压、做检查。运维工程师给服务器做性能调优,也一样。

先体检,再诊断;先了解硬件,再分析性能。


建立服务器硬件画像

假设有一天老板跑过来告诉你:

“这个 Web 系统最近越来越慢,帮我看看。”

你登录服务器之后,第一反应可能就是:

1
top

然后看到:

1
%Cpu(s): 80.0 us, 10.0 sy, 10.0 id

于是马上得出结论:

“CPU 使用率这么高,CPU 不够用了。”

这个结论真的正确吗?不一定。我们来看一个非常简单的例子。

服务器 A:

1
2
2 Core
CPU Usage 80%

服务器 B:

1
2
64 Core
CPU Usage 80%

两台服务器的 CPU 使用率都是 80%,但是它们的计算能力显然不是一个量级。所以:

CPU 使用率只是一个指标,它必须放在服务器硬件配置的上下文中去理解。

同样的道理。如果你看到:

1
Memory Usage: 80%

你也不能马上得出“内存不够”的结论。一台 128GB 内存的服务器使用 80%,和一台 4GB 内存的服务器使用 80%,背后的问题完全不同。因此,在开始性能分析之前,我们应该先建立一份:服务器硬件画像。

最基础的硬件画像,可以从四个维度开始:

flowchart TB
    Server["Linux 服务器硬件画像"]

    Server --> CPU["CPU"]
    Server --> MEM["Memory"]
    Server --> STORAGE["Storage"]
    Server --> NET["Network"]

    CPU --> CPU1["Socket"]
    CPU --> CPU2["Core / Thread"]
    CPU --> CPU3["L1 / L2 / L3 Cache"]
    CPU --> CPU4["NUMA"]

    MEM --> MEM1["总容量"]
    MEM --> MEM2["DIMM 插槽"]
    MEM --> MEM3["内存类型 / 频率"]

    STORAGE --> ST1["HDD"]
    STORAGE --> ST2["SSD"]
    STORAGE --> ST3["NVMe"]
    STORAGE --> ST4["RAID / HBA"]

    NET --> NET1["网卡型号"]
    NET --> NET2["链路速率"]
    NET --> NET3["驱动"]
    NET --> NET4["链路状态"]

也就是说,在开始真正的性能分析之前,我们至少应该先搞清楚:

CPU 有多少?

内存有多少?

磁盘是什么类型?

网络有多快?

这几个问题看起来简单,但它们实际上决定了后面大量性能指标应该如何解读。


建立完整的性能调优流程

这里其实可以进一步理解一个问题:

为什么我一直强调“先看硬件”?

因为性能调优并不是:

1
2
3
4
5
6
7
8
9
发现系统慢
↓
top
↓
发现 CPU 高
↓
调参数
↓
重启

一个更合理的性能分析过程应该是:

flowchart LR
    A["业务变慢"] --> B["① 硬件体检"]
    B --> C["② 建立硬件画像"]
    C --> D["③ 采集性能数据"]
    D --> E["④ 定位瓶颈"]
    E --> F["⑤ 分析根因"]
    F --> G["⑥ 实施优化"]
    G --> H["⑦ 验证效果"]

    H --> I{"问题是否解决?"}
    I -->|是| J["优化完成"]
    I -->|否| D

这张图非常重要。

因为后面学习 top、vmstat、iostat、sar、PCP 等工具的时候,你就会发现,这些工具解决的其实是**“采集和分析性能数据”**的问题。而今天我们要做的是整个流程的第一步:先搞清楚服务器有什么资源。


从 dmesg 开始认识你的服务器

Linux 内核是整个操作系统与硬件之间的核心管理者。服务器启动的时候,CPU、内存、磁盘、PCI 设备、网卡以及其他硬件,都会被内核探测,并产生相应的内核日志。最简单的查看方式就是:

1
dmesg

很多初学者看到 dmesg,第一反应是:

“这不是看报错的吗?”

其实不完全是。

dmesg 更像是:

Linux 内核留下的一份服务器启动档案。

里面不仅有错误信息,还包含大量硬件初始化、驱动加载以及设备识别信息。

例如:

1
2
3
4
[root@localhost ~]# dmesg | head -n 2
[ 0.000000] Linux version 6.12.0-211.16.1.el10_2.0.1.x86_64 (mockbuild@iad1-prod-build001.bld.equ.rockylinux.org) (gcc (GCC) 14.3.1 20251022 (Red Hat 14.3.1-4), GNU ld version 2.41-63.el10) #1 SMP PREEMPT_DYNAMIC Sun May 24 12:24:17 UTC 2026
[ 0.000000] Command line: BOOT_IMAGE=(hd0,gpt2)/vmlinuz-6.12.0-211.16.1.el10_2.0.1.x86_64 root=/dev/mapper/rlm-root ro resume=UUID=66bf8ede-b5a0-4338-994d-56e7f216dde9 rd.lvm.lv=rlm/root rd.lvm.lv=rlm/swap

这里可以看到 Linux 内核版本以及启动参数。如果想快速搜索内存相关信息,可以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[root@localhost ~]# dmesg | grep -i memory
[ 0.000000] DMI: Memory slots populated: 1/128
[ 0.008258] ACPI: Reserving FACP table memory at [mem 0xbfefee73-0xbfefef66]
[ 0.008259] ACPI: Reserving DSDT table memory at [mem 0xbfedd001-0xbfefee72]
[ 0.008259] ACPI: Reserving FACS table memory at [mem 0xbfefffc0-0xbfefffff]
[ 0.008260] ACPI: Reserving FACS table memory at [mem 0xbfefffc0-0xbfefffff]
[ 0.008260] ACPI: Reserving BOOT table memory at [mem 0xbfedcfb4-0xbfedcfdb]
[ 0.008261] ACPI: Reserving APIC table memory at [mem 0xbfedc872-0xbfedcfb3]
[ 0.008261] ACPI: Reserving MCFG table memory at [mem 0xbfedc836-0xbfedc871]
[ 0.008262] ACPI: Reserving SRAT table memory at [mem 0xbfedb72f-0xbfedbffe]
[ 0.008262] ACPI: Reserving HPET table memory at [mem 0xbfedb6f7-0xbfedb72e]
[ 0.008262] ACPI: Reserving WAET table memory at [mem 0xbfedb6cf-0xbfedb6f6]
[ 0.008263] ACPI: Reserving DMAR table memory at [mem 0xbfedb67f-0xbfedb6ce]
[ 0.009046] Early memory node ranges
[ 0.135708] PM: hibernation: Registered nosave memory: [mem 0x00000000-0x00000fff]
[ 0.135709] PM: hibernation: Registered nosave memory: [mem 0x00097000-0x00097fff]
[ 0.135709] PM: hibernation: Registered nosave memory: [mem 0x00098000-0x0009ffff]
[ 0.135710] PM: hibernation: Registered nosave memory: [mem 0x000a0000-0x000cdfff]
[ 0.135710] PM: hibernation: Registered nosave memory: [mem 0x000ce000-0x000cffff]
[ 0.135711] PM: hibernation: Registered nosave memory: [mem 0x000d0000-0x000dbfff]
[ 0.135711] PM: hibernation: Registered nosave memory: [mem 0x000dc000-0x000fffff]
[ 0.135712] PM: hibernation: Registered nosave memory: [mem 0xbfed0000-0xbfefefff]
[ 0.135712] PM: hibernation: Registered nosave memory: [mem 0xbfeff000-0xbfefffff]
[ 0.135713] PM: hibernation: Registered nosave memory: [mem 0xc0000000-0xefffffff]
[ 0.135713] PM: hibernation: Registered nosave memory: [mem 0xf0000000-0xf7ffffff]
[ 0.135714] PM: hibernation: Registered nosave memory: [mem 0xf8000000-0xfebfffff]
[ 0.135714] PM: hibernation: Registered nosave memory: [mem 0xfec00000-0xfec0ffff]
[ 0.135714] PM: hibernation: Registered nosave memory: [mem 0xfec10000-0xfedfffff]
[ 0.135715] PM: hibernation: Registered nosave memory: [mem 0xfee00000-0xfee00fff]
[ 0.135715] PM: hibernation: Registered nosave memory: [mem 0xfee01000-0xfffdffff]
[ 0.135715] PM: hibernation: Registered nosave memory: [mem 0xfffe0000-0xffffffff]
[ 0.421035] Freeing SMP alternatives memory: 40K
[ 0.564170] Memory: 8029688K/8387992K available (18432K kernel code, 5846K rwdata, 14520K rodata, 4388K init, 6492K bss, 342776K reserved, 0K cma-reserved)
[ 0.565416] x86/mm: Memory block size: 128MB
[ 1.625662] Freeing initrd memory: 39292K
[ 1.698530] Non-volatile memory driver v1.3
[ 1.826118] Freeing unused decrypted memory: 2028K
[ 1.826787] Freeing unused kernel image (initmem) memory: 4388K
[ 1.827604] Freeing unused kernel image (rodata/data gap) memory: 1864K
[ 2.615233] vmwgfx 0000:00:0f.0: [drm] Legacy memory limits: VRAM = 4096 KiB, FIFO = 256 KiB, surface = 0 KiB
[ 2.615241] vmwgfx 0000:00:0f.0: [drm] Maximum display memory size is 262144 KiB

这类信息可以帮助我们了解 Linux 内核启动时识别到了多少内存。

不过这里需要注意:

dmesg 是内核日志,不应该把它当成查看当前硬件配置的唯一工具。

例如当前系统实际内存使用情况,更适合使用:

1
free -h

所以我们可以简单理解:

1
2
3
4
5
6
7
dmesg
↓
看内核启动和硬件初始化发生了什么

free
↓
看当前系统内存使用情况

两个工具解决的是不同的问题。


查看 CPU:先搞清楚 Socket、Core 和 Thread

CPU 是性能调优过程中最重要的资源之一。查看 CPU 信息,最经典的工具就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
[root@localhost ~]# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 45 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Vendor ID: GenuineIntel
BIOS Vendor ID: GenuineIntel
Model name: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
BIOS Model name: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz CPU @ 2.3GHz
BIOS CPU family: 2
CPU family: 6
Model: 141
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 2
Stepping: 1
BogoMIPS: 4608.00
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp
lm constant_tsc arch_perfmon rep_good nopl xtopology tsc_reliable nonstop_tsc cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma c
x16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch ssbd
ibrs ibpb stibp ibrs_enhanced tpr_shadow ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq r
dseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves user_shstk arat vnmi a
vx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid movdiri movdir64b fsr
m avx512_vp2intersect md_clear flush_l1d arch_capabilities
Virtualization features:
Virtualization: VT-x
Hypervisor vendor: VMware
Virtualization type: full
Caches (sum of all):
L1d: 192 KiB (4 instances)
L1i: 128 KiB (4 instances)
L2: 5 MiB (4 instances)
L3: 48 MiB (2 instances)
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0-3
Vulnerabilities:
Gather data sampling: Unknown: Dependent on hypervisor status
Indirect target selection: Mitigation; Aligned branch/return thunks
Itlb multihit: KVM: Mitigation: Split huge pages
L1tf: Not affected
Mds: Not affected
Meltdown: Not affected
Mmio stale data: Not affected
Old microcode: Not affected
Reg file data sampling: Not affected
Retbleed: Not affected
Spec rstack overflow: Not affected
Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl
Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI SW loop, KVM SW loop
Srbds: Not affected
Tsa: Not affected
Tsx async abort: Not affected
Vmscape: Not affected

这时候很多初学者就开始迷糊:

Socket、Core、Thread 到底是什么关系?

其实可以用一栋写字楼来理解。

1
2
3
Socket = 一栋楼
Core = 楼里的办公室
Thread = 办公室里的工位

如果服务器是:

1
2
3
1 Socket
12 Core
2 Thread

可以理解为:

flowchart TB
    S["Socket 1"]

    S --> C1["Core 1"]
    S --> C2["Core 2"]
    S --> C3["Core 3"]
    S --> C4["..."]
    S --> C12["Core 12"]

    C1 --> T11["Thread 1"]
    C1 --> T12["Thread 2"]

    C2 --> T21["Thread 1"]
    C2 --> T22["Thread 2"]

    C3 --> T31["Thread 1"]
    C3 --> T32["Thread 2"]

    C12 --> T121["Thread 1"]
    C12 --> T122["Thread 2"]

因此:

1
2
1 Socket × 12 Core × 2 Thread
= 24 个逻辑 CPU

也就是:

1
CPU(s): 24

这里有一个非常重要的概念:

操作系统看到的 CPU 数量,通常是逻辑 CPU 数量,而不是简单意义上的物理核心数量。

所以以后看到:

1
CPU(s): 64

不要马上理解成:

“这台服务器有 64 个物理核心。”

还需要结合:

1
2
3
Socket(s)
Core(s) per socket
Thread(s) per core

一起看。


不要忽略 CPU Cache

除了 CPU 数量和拓扑结构,还有一个经常被初学者忽略的东西:

CPU Cache。

执行:

1
lscpu

通常还可以看到类似信息:

1
2
3
4
5
Caches (sum of all):
L1d: 192 KiB (4 instances)
L1i: 128 KiB (4 instances)
L2: 5 MiB (4 instances)
L3: 48 MiB (2 instances)

Cache 到底是什么?还是用办公室来理解。假设一个员工正在处理文件。文件可能放在:

1
2
3
4
5
6
7
办公桌
↓
抽屉
↓
办公室文件柜
↓
仓库

离员工越近,拿文件越快。

CPU Cache 也是类似的:

flowchart LR
    CPU["CPU Core"]

    L1["L1 Cache<br/>容量小<br/>访问最快"]
    L2["L2 Cache<br/>容量更大<br/>速度稍慢"]
    L3["L3 Cache<br/>容量更大<br/>通常由多个 Core 共享"]
    RAM["Memory<br/>容量更大<br/>访问延迟更高"]

    CPU --> L1 --> L2 --> L3 --> RAM

可以简单记住:

L1 最靠近 CPU,通常最快;L2 次之;L3 更大;再往后就是内存。

这也是为什么不同 CPU 即使核心数量差不多,在某些工作负载下性能仍然可能有明显差异。

例如数据库、虚拟化、计算密集型应用等场景,CPU 架构、Cache、内存带宽以及 NUMA 拓扑,都可能影响最终性能。

所以性能调优的时候,不要只问:

“CPU 有几个?”

还应该进一步问:

“这是什么 CPU?Cache 多大?拓扑是什么样?”


dmidecode:服务器的“身份证”

如果说:

1
dmesg

更像是服务器的“出生证明”,那么:

1
dmidecode

就更像服务器的“身份证”。

dmidecode 可以读取系统 DMI/SMBIOS 中记录的硬件信息。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[root@localhost ~]# dnf install dmidecode -y

[root@localhost ~]# dmidecode -t system
# dmidecode 3.6
Getting SMBIOS data from sysfs.
SMBIOS 2.7 present.

Handle 0x0001, DMI type 1, 27 bytes
System Information
Manufacturer: VMware, Inc.
Product Name: VMware Virtual Platform
Version: None
Serial Number: VMware-56 4d 14 56 23 99 29 28-d9 5b 8f e8 0c 29 c1 31
UUID: 56144d56-9923-2829-d95b-8fe80c29c131
Wake-up Type: Power Switch
SKU Number: Not Specified
Family: Not Specified

Handle 0x01A1, DMI type 15, 29 bytes
System Event Log
Area Length: 16 bytes
Header Start Offset: 0x0000
Header Length: 16 bytes
Data Start Offset: 0x0010
Access Method: General-purpose non-volatile data functions
Access Address: 0x0000
Status: Invalid, Full
Change Token: 0x00000036
Header Format: Type 1
Supported Log Type Descriptors: 3
Descriptor 1: POST error
Data Format 1: POST results bitmap
Descriptor 2: Single-bit ECC memory error
Data Format 2: Multiple-event
Descriptor 3: Multi-bit ECC memory error
Data Format 3: Multiple-event

Handle 0x0265, DMI type 23, 13 bytes
System Reset
Status: Enabled
Watchdog Timer: Present
Boot Option: Do Not Reboot
Boot Option On Limit: Do Not Reboot
Reset Count: Unknown
Reset Limit: Unknown
Timer Interval: Unknown
Timeout: Unknown

Handle 0x0268, DMI type 32, 20 bytes
System Boot Information
Status: No errors detected

这些信息在企业运维环境里非常实用。比如你接手了几十台甚至几百台物理服务器,领导突然问:

“这台服务器是什么型号?哪个厂商的?序列号是多少?”

你总不能跑到机房里,一台一台去看服务器标签。

可以先执行:

1
dmidecode -t system

快速获取服务器的基础资产信息。

因此在服务器资产盘点、硬件故障排查以及自动化资产管理中,dmidecode 都非常常见。


查看内存:不仅要看容量,还要看插槽

前面我们可以通过:

1
free -h

查看当前系统的内存使用情况。但是如果你面对的是一台物理服务器,还有一个非常实际的问题:

这台服务器到底插了多少根内存?还有没有空闲插槽?

比如领导告诉你:

“最近数据库内存不够了,再给服务器加点内存。”

你总不能直接回答:

“买一根 32GB 的回来。”

应该先看看服务器当前的内存布局。

执行:

1
dmidecode -t memory

可能看到:

1
2
3
4
5
Memory Device
Size: 32 GB
Locator: DIMM_A1
Type: DDR4
Speed: 3200 MT/s

如果某个插槽没有安装内存,也可能看到:

1
Size: No Module Installed

这样我们就可以进一步确认:

  • 当前安装了多少内存;
  • 使用了哪些 DIMM 插槽;
  • 哪些插槽为空;
  • 内存类型是什么;
  • 内存频率是多少。

这里有一个非常容易混淆的地方:

“系统还有多少内存”与“服务器还能不能继续扩容内存”是两个完全不同的问题。

例如:

1
free -h

解决的是:

当前系统内存还剩多少?

而:

1
dmidecode -t memory

更关注:

物理服务器的内存条和插槽是什么情况?

这两个信息结合起来,才更完整。


lspci:看看服务器到底有哪些 PCI 设备

服务器中的很多硬件设备,都连接在 PCI/PCIe 总线上。

比如:

  • 网卡;
  • RAID 卡;
  • HBA 卡;
  • GPU;
  • NVMe 控制器;
  • 其他 PCIe 扩展设备。

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[root@localhost ~]# dnf install pciutils -y
[root@localhost ~]# lspci
00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge ( AGP disabled) (rev 01)
00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (re v 01)
00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08)
00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
00:07.7 System peripheral: VMware Virtual Machine Communication Interface (rev 1 0)
00:0f.0 VGA compatible controller: VMware SVGA II Adapter
00:11.0 PCI bridge: VMware PCI bridge (rev 02)
00:15.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.7 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.7 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.7 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.7 PCI bridge: VMware PCI Express Root Port (rev 01)
02:00.0 USB controller: VMware USB1.1 UHCI Controller
02:01.0 Multimedia audio controller: Ensoniq ES1371/ES1373 / Creative Labs CT251 8 (rev 02)
02:02.0 USB controller: VMware USB2 EHCI Controller
02:03.0 SATA controller: VMware SATA AHCI controller
03:00.0 Ethernet controller: VMware VMXNET3 Ethernet Controller (rev 01)
0b:00.0 Non-Volatile memory controller: VMware NVMe SSD Controller

这时候你就可以快速知道:

这台服务器到底挂了哪些 PCI 设备。

可以把它理解成:

flowchart TB
    PCI["PCI / PCIe 总线"]

    PCI --> NIC["网卡"]
    PCI --> RAID["RAID Controller"]
    PCI --> HBA["HBA"]
    PCI --> GPU["GPU"]
    PCI --> NVME["NVMe Controller"]

    NIC --> NICD["网络驱动"]
    RAID --> RAIDD["存储驱动"]
    HBA --> HBAD["HBA 驱动"]
    GPU --> GPUD["GPU 驱动"]
    NVME --> NVMED["NVMe 驱动"]

如果想查看更详细的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@localhost ~]# lspci -vv
00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled) (rev 01)
Subsystem: VMware Device 1976
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0

00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle+ MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap- 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Bus: primary=00, secondary=01, subordinate=01, sec-latency=64
I/O behind bridge: [disabled] [16-bit]
Memory behind bridge: [disabled] [32-bit]
Prefetchable memory behind bridge: [disabled] [32-bit]
Secondary status: 66MHz+ FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- <SERR- <PERR-
BridgeCtl: Parity- SERR- NoISA+ VGA- VGA16- MAbort- >Reset- FastB2B+
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-

00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08)
Subsystem: VMware Virtual Machine Chipset
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0

因此,当你遇到硬件相关问题时,可以形成一个很实用的排查思路:

1
2
3
4
5
6
7
8
9
PCI 设备
↓
硬件有没有被识别?
↓
驱动有没有加载?
↓
链路是否正常?
↓
性能是否正常?

这比单纯看到“网络很慢”之后直接开始修改 TCP 参数,要靠谱得多。


USB 设备也别忘了

USB 在服务器上的重要程度可能没有 CPU、存储、网络那么高,但有时候我们也需要知道系统识别到了哪些 USB 设备。

可以使用:

1
2
3
4
5
6
7
[root@localhost ~]# dnf install usbutils -y
[root@localhost ~]# lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse
Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub

如果需要更详细的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[root@localhost ~]# lsusb -vv

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Negotiated speed: High Speed (480Mbps)
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 9 Hub
bDeviceSubClass 0 [unknown]
bDeviceProtocol 0 Full speed (or root) hub
bMaxPacketSize0 64
idVendor 0x1d6b Linux Foundation
idProduct 0x0002 2.0 root hub
bcdDevice 6.12
iManufacturer 3 Linux 6.12.0-211.16.1.el10_2.0.1.x86_64 ehci_hcd
iProduct 2 EHCI Host Controller
iSerial 1 0000:02:02.0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0019
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 9 Hub
bInterfaceSubClass 0 [unknown]

普通服务器环境下,这个命令使用频率可能没有 lscpu、lspci 高。但是当你怀疑 USB 设备、虚拟 USB 设备或者相关驱动存在问题时,它就非常有用了。


lshw:不想一个一个看?直接给服务器做一次“全身体检”

如果你觉得前面的命令有点多:

1
2
3
4
5
dmesg
lscpu
dmidecode
lspci
lsusb

一个一个执行比较麻烦,那么可以使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@localhost ~]# lshw | more
localhost.localdomain
description: Computer
product: VMware Virtual Platform
vendor: VMware, Inc.
version: None
serial: VMware-56 4d 14 56 23 99 29 28-d9 5b 8f e8 0c 29 c1 31
width: 64 bits
capabilities: smbios-2.7 dmi-2.7 smp vsyscall32
configuration: administrator_password=enabled boot=normal frontpanel_password=unknown keyboard_password=unknown power-on_password=disabled uuid=56144d56-9923-2829-d95b-8fe80c29c131
*-core
description: Motherboard
product: 440BX Desktop Reference Platform
vendor: Intel Corporation
physical id: 0
version: None
serial: None
*-firmware
description: BIOS
vendor: Phoenix Technologies LTD
physical id: 0
version: 6.00
date: 02/17/2026
size: 86KiB
capabilities: isa pci pcmcia pnp apm upgrade shadowing escd cdboot bootselect edd int5printscreen int9keyboard int14serial int17printer int10video acpi smartbattery biosboots
pecification netboot
*-cpu:0

如果只是想快速查看整体硬件结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost ~]# lshw -short | more
H/W path Device Class Description
==========================================================
system VMware Virtual Platform
/0 bus 440BX Desktop Reference Platform
/0/0 memory 86KiB BIOS
/0/1 processor 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
/0/1/0 memory 16KiB L1 cache
/0/1/1 memory 16KiB L1 cache
/0/2 processor 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
/0/5 processor CPU
/0/5/95 memory 16KiB L1 cache
/0/6 processor CPU
/0/6/96 memory 16KiB L1 cache
/0/7 processor CPU
/0/7/97 memory 16KiB L1 cache
/0/8 processor CPU
/0/8/98 memory 16KiB L1 cache
/0/9 processor CPU
/0/9/99 memory 16KiB L1 cache

这时候基本就可以快速建立一个整体印象:

1
2
3
4
5
6
服务器
├── CPU
├── Memory
├── Network
├── Storage
└── PCI Devices

所以当我拿到一台陌生 Linux 服务器的时候,如果只是想先快速扫一眼硬件情况:

1
lshw -short

通常就是一个不错的起点。然后再针对具体资源深入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CPU 有问题?
↓
lscpu

内存有问题?
↓
free / dmidecode

存储有问题?
↓
lsblk / lspci / lshw

网络有问题?
↓
ip / ethtool / lspci

驱动有问题?
↓
lspci -vv / dmesg

这样排查效率会高很多。


可以。这三个工具非常适合接在你前面 CPU / 内存 / PCI / 硬件画像 后面,不过它们的定位不一样:

  • lstopo-no-graphics:看 CPU / NUMA / 硬件拓扑
  • rasdaemon:后台记录 RAS(可靠性、可用性、可维护性)硬件错误
  • ras-mc-ctl:查询、管理 Machine Check / 内存纠错等硬件错误信息

下面我按照你前面文章的风格,直接给你可以放进 Markdown 的内容。


lstopo-no-graphics:把 CPU 和 NUMA 拓扑画出来

前面我们使用 lscpu 可以看到 CPU 的 Socket、Core、Thread 等信息,但它输出的是一张表。

如果服务器配置比较复杂,比如:

  • 双路 CPU
  • 多个 NUMA Node
  • 每个 NUMA Node 对应一部分内存
  • CPU Core 分布在不同 Socket
  • PCIe 设备与 NUMA Node 存在亲和关系

这时候只看 lscpu 往往不够直观。这时候可以使用 lstopo-no-graphics。它来自 hwloc 工具集,最大的特点就是:

把服务器的 CPU、NUMA、Cache、内存等硬件拓扑关系,用树形结构直接展示出来。

安装 hwloc

CentOS / Rocky Linux / AlmaLinux:

1
[root@localhost ~]# dnf install -y hwloc

安装完成以后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost ~]# lstopo-no-graphics
Machine (7903MB total)
NUMANode L#0 (P#0 7903MB)
Package L#0 + L3 L#0 (24MB)
L2 L#0 (1280KB) + L1d L#0 (48KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
L2 L#1 (1280KB) + L1d L#1 (48KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
Package L#1 + L3 L#1 (24MB)
L2 L#2 (1280KB) + L1d L#2 (48KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
L2 L#3 (1280KB) + L1d L#3 (48KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
HostBridge
PCI 00:07.1 (IDE)
PCI 00:0f.0 (VGA)
PCIBridge
PCI 02:03.0 (SATA)
Block(Removable Media Device) "sr0"
PCIBridge
PCI 03:00.0 (Ethernet)
Net "ens160"
PCIBridge
PCI 0b:00.0 (NVMExp)
Block(Disk) "nvme0n1"

这个结果实际上是在告诉我们:

这个结果实际上是在告诉我们:

1
Machine (7903MB total)

首先可以看到整个服务器,也就是 Machine,总内存大约是 7903MB,也就是我们通常所说的 8GB 内存。

接下来:

1
NUMANode L#0 (P#0 7903MB)

说明这台服务器只有 一个 NUMA Node。

也就是说,这是一台单 NUMA 节点的服务器,所有大约 7.9GB 内存都属于 NUMA Node 0。

继续往下看:

1
2
Package L#0 + L3 L#0 (24MB)
Package L#1 + L3 L#1 (24MB)

这里就比较有意思了。

Package 可以简单理解为一个 CPU Socket。

所以这台服务器实际上有:

1
2 个 CPU Socket

而且每个 Socket 都有自己的:

1
L3 Cache = 24MB

也就是说:

1
2
3
4
5
Socket 0
└── L3 Cache 24MB

Socket 1
└── L3 Cache 24MB

再继续看:

1
2
3
4
5
L2 L#0 ... + Core L#0 + PU L#0
L2 L#1 ... + Core L#1 + PU L#1

L2 L#2 ... + Core L#2 + PU L#2
L2 L#3 ... + Core L#3 + PU L#3

这里可以看到一共存在:

1
4 个 Core

每个 Core 对应一个:

1
PU

这里的 PU 可以理解为 hwloc 看到的一个逻辑处理单元(Processing Unit)。

因此,这台服务器的 CPU 拓扑大致可以理解成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
服务器
├── Socket 0
│ ├── L3 Cache 24MB
│ ├── Core 0
│ │ └── PU 0
│ └── Core 1
│ └── PU 1
│
└── Socket 1
├── L3 Cache 24MB
├── Core 2
│ └── PU 2
└── Core 3
└── PU 3

所以从这个结果来看:

1
2
3
4
5
Socket:2
Core:4
PU:4
NUMA Node:1
Memory:约 8GB

这也是 lstopo-no-graphics 比单纯看 lscpu 更直观的地方——它不仅告诉你有多少 CPU,还把 CPU、Cache、NUMA、内存之间的层级关系展示出来了。


再往下面看:

1
HostBridge

这里开始进入 PCIe / PCI 设备拓扑。

例如:

1
PCI 00:0f.0 (VGA)

说明系统检测到了一个 VGA 显示设备。

然后:

1
2
PCI 03:00.0 (Ethernet)
Net "ens160"

这里就比较有价值了。

它告诉我们:

1
2
3
PCI 03:00.0
└── Ethernet
└── ens160

也就是说,系统中的:

1
ens160

这块网卡对应 PCI 地址:

1
03:00.0

后面如果遇到网络性能问题,我们就可以进一步使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[root@localhost ~]# lspci -s 03:00.0 -vv
03:00.0 Ethernet controller: VMware VMXNET3 Ethernet Controller (rev 01)
DeviceName: Ethernet0
Subsystem: VMware VMXNET3 Ethernet Controller
Physical Slot: 160
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 32 bytes
Interrupt: pin A routed to IRQ 18
Region 0: Memory at fd4fc000 (32-bit, non-prefetchable) [size=4K]
Region 1: Memory at fd4fd000 (32-bit, non-prefetchable) [size=4K]
Region 2: Memory at fd4fe000 (32-bit, non-prefetchable) [size=8K]
Region 3: I/O ports at 4000 [size=16]
Expansion ROM at fd400000 [virtual] [disabled] [size=64K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [48] Express (v2) Endpoint, IntMsgNum 0
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag- AttnBtn- AttnInd- PwrInd- RBE- FLReset- SlotPowerLimit 0W TEE-IO-
DevCtl: CorrErr- NonFatalErr- FatalErr- UnsupReq-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
LnkCap: Port #0, Speed 5GT/s, Width x32, ASPM L0s, Exit Latency L0s <64ns
ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp-
LnkCtl: ASPM Disabled; RCB 64 bytes, LnkDisable- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 5GT/s, Width x32
TrErr- Train- SlotClk- DLActive- BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Not Supported, TimeoutDis- NROPrPrP- LTR-
10BitTagComp- 10BitTagReq- OBFF Not Supported, ExtFmt- EETLPPrefix-
EmergencyPowerReduction Not Supported, EmergencyPowerReductionInit-
FRS- TPHComp- ExtTPHComp-
AtomicOpsCap: 32bit- 64bit- 128bitCAS-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-
AtomicOpsCtl: ReqEn-
IDOReq- IDOCompl- LTR- EmergencyPowerReductionReq-
10BitTagReq- OBFF Disabled, EETLPPrefixBlk-
LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance Preset/De-emphasis: -6dB de-emphasis, 0dB preshoot
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete- EqualizationPhase1-
EqualizationPhase2- EqualizationPhase3- LinkEqualizationRequest-
Retimer- 2Retimers- CrosslinkRes: unsupported
Capabilities: [84] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Capabilities: [9c] MSI-X: Enable+ Count=25 Masked-
Vector table: BAR=2 offset=00000000
PBA: BAR=2 offset=00001000
Capabilities: [100 v1] Device Serial Number 00-0c-29-ff-ff-29-c1-31
Kernel driver in use: vmxnet3
Kernel modules: vmxnet3

或者:

1
ethtool ens160

继续查看它的硬件、驱动、链路速率等信息。


再看存储设备:

1
2
PCI 0b:00.0 (NVMExp)
Block(Disk) "nvme0n1"

这里说明:

1
2
3
PCI 0b:00.0
└── NVMe Controller
└── nvme0n1

也就是说,这台服务器存在一块 NVMe 存储设备:

1
/dev/nvme0n1

如果后面发现磁盘 IO 很高,就可以继续使用:

1
lsblk

查看设备结构,再结合:

1
2
3
4
[root@localhost ~]# nvme list
Node Generic SN Model Namespace Usage Format FW Rev
--------------------- --------------------- -------------------- ---------------------------------------- ---------- -------------------------- ---------------- --------
/dev/nvme0n1 /dev/ng0n1 VMware NVME_0000 VMware Virtual NVMe Disk 0x1 536.87 GB / 536.87 GB 512 B + 0 B 1.4

以及:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# iostat -x
Linux 6.12.0-211.16.1.el10_2.0.1.x86_64 (localhost.localdomain) 09/27/2026 _x86_64_ (4 CPU)

avg-cpu: %user %nice %system %iowait %steal %idle
0.09 0.02 0.35 0.02 0.00 99.51

Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
dm-0 3.87 131.92 0.00 0.00 0.34 34.05 1.51 71.81 0.00 0.00 0.57 47.42 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.73
dm-1 0.04 0.87 0.00 0.00 0.06 22.28 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
nvme0n1 4.04 137.16 0.00 0.08 0.27 33.99 1.41 72.61 0.15 9.39 0.78 51.48 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.11

进一步分析。


把整个结果串起来,这台服务器的硬件拓扑可以简单理解成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                   Linux Server
│
┌──────────────┴──────────────┐
│ │
CPU/Memory PCIe Devices
│ │
┌────┴────┐ ┌─────────┼─────────┐
│ │ │ │ │
Socket 0 Socket 1 VGA Ethernet NVMe
│ │ │ │
2 Core 2 Core ens160 nvme0n1
│ │
L3 24MB L3 24MB
│
NUMA Node 0
│
7.9GB RAM

这样一看,就比单纯执行:

1
2
3
4
lscpu
free -h
lsblk
lspci

然后分别查看几个命令的输出更加直观。

不过这里还要注意一个细节:

lstopo-no-graphics 展示的是硬件拓扑,不等于完整的硬件信息。

例如它可以告诉我们:

1
2
3
4
5
6
7
有几个 Socket
有几个 Core
有几个 PU
Cache 有多大
NUMA 怎么组织
网卡挂在哪个 PCI 设备下面
NVMe 挂在哪个 PCI 设备下面

但它并不会替代:

1
2
3
4
5
lscpu
dmidecode
lspci -vv
ethtool
lsblk

这些工具。

所以在实际服务器巡检中,可以把它理解成:

lstopo-no-graphics 负责“看全局拓扑”,其他工具负责“钻进去看细节”。

这也是我们在性能调优中需要建立“硬件画像”的原因。

当后面看到:

1
2
3
4
5
CPU 使用率很高
内存访问延迟异常
NVMe IO 很高
网络吞吐异常
NUMA 访问不均衡

我们才有一张完整的硬件地图,可以知道这个性能指标到底对应服务器中的哪一部分。

rasdaemon:给服务器建立一份“硬件故障日志”

前面的工具主要是在回答:

服务器现在是什么硬件?

而 rasdaemon 开始回答另外一个非常重要的问题:

这台服务器最近有没有发生过硬件错误?

RAS 是:

1
2
3
Reliability
Availability
Serviceability

也就是:

1
2
3
可靠性
可用性
可维护性

对于企业服务器来说,有一些硬件问题并不会立即导致服务器宕机。

例如:

1
2
3
4
ECC 内存发生可纠正错误
CPU Machine Check
PCIe 错误
内存控制器错误

系统可能还能继续运行。但是:

“现在还能运行”不代表“硬件完全正常”。 如果这些错误不断增加,就需要引起注意。

安装 rasdaemon

CentOS / Rocky Linux:

1
[root@localhost ~]# dnf install -y rasdaemon

启动服务:

1
[root@localhost ~]# systemctl enable --now rasdaemon

检查:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost ~]# systemctl status rasdaemon
● rasdaemon.service - RAS daemon to log the RAS events
Loaded: loaded (/usr/lib/systemd/system/rasdaemon.service; enabled; preset: disabled)
Active: active (running) since Sun 2026-09-27 15:49:31 CST; 10s ago
Invocation: ad0c3493e1ba4c7889fc7c55c4bef888
Process: 5415 ExecStartPost=/usr/sbin/rasdaemon --enable (code=exited, status=0/SUCCESS)
Main PID: 5414 (rasdaemon)
Tasks: 128 (limit: 50278)
Memory: 11.6M (peak: 12.3M)
CPU: 34ms
CGroup: /system.slice/rasdaemon.service
└─5414 /usr/sbin/rasdaemon -f -r

查看 RAS 错误

可以使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@localhost ~]# ras-mc-ctl --errors
No Memory errors.

No PCIe AER errors.

No CXL AER uncorrectable errors.

No CXL AER correctable errors.

No CXL overflow errors.

No CXL poison errors.

No CXL generic errors.

No CXL general media errors.

No CXL DRAM errors.

No CXL memory module errors.

No Extlog errors.

No devlink errors.

No disk errors.

No Memory failure errors.

No MCE errors.

也可以查看 rasdaemon 记录:

1
ras-mc-ctl --summary

不同发行版版本的输出可能存在差异。重点不是死记输出格式,而是关注:

1
2
3
4
5
是否存在错误
错误类型是什么
错误发生了多少次
错误是否持续增加
错误发生在哪个硬件组件

ECC 内存错误

比如服务器运行一段时间后发现:

1
Corrected memory errors: 152

这里需要注意:

Corrected Error 并不等于服务器已经坏了。

ECC 内存可以自动纠正部分错误,因此系统可能完全没有宕机。

但是如果:

1
2
3
昨天:2 次
今天:152 次
明天:1000 次

那么情况就值得关注了。可以把它理解成:

汽车仪表盘偶尔亮一次故障灯,和每天不断亮故障灯,是完全不同的事情。

因此 RAS 数据非常适合用于:

1
2
3
4
硬件健康监控
故障预警
服务器巡检
硬件更换依据

一个比较典型的硬件故障案例

假设一台数据库服务器运行了一段时间。

业务人员反馈:

“最近偶尔会卡一下,但是服务器没有重启。”

这时候如果只执行:

1
top

可能看到:

1
2
3
CPU 35%
Memory 58%
Load 2.3

看起来一切正常。

于是很多人会直接把问题归到:

1
2
3
数据库
网络
代码

但我们换一个思路。

先看:

1
dmesg -T | grep -Ei "mce|edac|hardware error|machine check"

如果发现:

1
2
3
4
Hardware Error
Machine Check
EDAC MC
Corrected error

再查看:

1
ras-mc-ctl --summary

发现:

1
2
Memory errors
Corrected errors

并且错误数量不断增长。

那么排查方向就发生了变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
业务偶发卡顿
↓
top 没发现明显异常
↓
检查内核日志
↓
发现 Machine Check / EDAC
↓
检查 rasdaemon
↓
发现 ECC / Memory Corrected Error
↓
定位具体 DIMM / Memory Controller
↓
安排硬件进一步检测

这就是 RAS 工具真正的价值:

它可以帮助我们发现那些“服务器还没有挂,但是硬件已经开始发出信号”的问题。


为什么 Corrected Error 也需要关注?

这里特别容易出现一个误区:

“既然错误已经被 ECC 自动修复了,那就不用管了。”

这个理解并不完全正确。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
第一次:
Corrected Error

第二次:
Corrected Error

第三次:
Corrected Error

……

第 1000 次:
Corrected Error

虽然每一次都被纠正了,但错误频率本身就是一个重要信号。尤其是在企业生产环境中,如果发现:

1
2
3
某一个 DIMM
某一个内存通道
某一个 CPU Socket

持续产生错误,那么就应该进一步检查硬件。最终可能涉及:

1
2
3
4
5
内存条
内存插槽
CPU 内存控制器
主板
BIOS / Firmware

存储和网络:硬件画像不能少了这两个维度

前面我们已经看了 CPU、内存、PCI 等信息。但如果想建立一份比较完整的硬件画像,还不能忘记:

存储和网络。

因为很多性能问题,最终都会落到这两个资源上。


查看存储设备

首先可以使用:

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sr0 11:0 1 1024M 0 rom
nvme0n1 259:0 0 500G 0 disk
├─nvme0n1p1 259:1 0 1M 0 part
├─nvme0n1p2 259:2 0 2G 0 part /boot
└─nvme0n1p3 259:3 0 498G 0 part
├─rlm-root 253:0 0 490.2G 0 lvm /
└─rlm-swap 253:1 0 7.8G 0 lvm [SWAP]

至少需要知道:

  • 系统使用的是 HDD、SSD 还是 NVMe;
  • 有多少块磁盘;
  • 哪些磁盘用于系统;
  • 哪些磁盘用于数据库;
  • 是否存在 RAID;
  • 是否存在独立存储控制器。

因为:

磁盘 IO 高,并不意味着一定是 Linux IO 参数没调好。

假设我们后面发现:

1
2
3
4
5
业务 IO 很高
↓
磁盘响应时间很长
↓
IOPS 上不去

这时候第一件事情之一就是:

“这到底是什么盘?”

如果是一块老旧机械硬盘,它和 NVMe SSD 的性能上限,本身就不是一个级别。所以后面的 iostat 数据,必须结合底层存储硬件一起分析。


查看网络设备和网卡速率

网络同样如此。

首先可以使用:

1
2
3
4
5
6
7
8
[root@localhost ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:29:c1:31 brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname enx000c2929c131

查看网卡设备。然后进一步使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost ~]# dnf install ethtool
[root@localhost ~]# ethtool ens160
Settings for ens160:
Supported ports: [ TP ]
Supported link modes: 1000baseT/Full
10000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: No
Supported FEC modes: Not reported
Advertised link modes: Not reported
Advertised pause frame use: No
Advertised auto-negotiation: No
Advertised FEC modes: Not reported
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: off
Port: Twisted Pair
PHYAD: 0
Transceiver: internal
MDI-X: Unknown
Supports Wake-on: uag
Wake-on: d
Link detected: yes

这时候如果业务告诉你:

“服务器网络吞吐怎么都上不去?”

你就应该先确认:

1
2
3
4
5
6
7
8
9
10
11
网卡是什么型号?
↓
支持多少速率?
↓
当前协商出来多少?
↓
链路是否正常?
↓
有没有错误包?
↓
有没有丢包?

如果网卡当前就是:

1
1000Mb/s

那么无论你怎么调整 Linux 网络参数,都不可能让这条物理链路直接变成:

1
25Gbps

这就是为什么:

性能调优必须建立在资源边界之上。


把这些命令串起来:建立一份真正的服务器硬件画像

到这里,我们已经认识了一批非常重要的 Linux 硬件信息工具:

1
2
3
4
5
6
7
8
dmesg
lscpu
dmidecode
lspci
lsusb
lshw
lsblk
ethtool

但真正需要记住的,并不是这些命令本身。更重要的是:

每一个命令到底是在帮我们回答什么问题?

可以把它们整理成下面这张图:

flowchart TB
    Server["Linux 服务器"]

    Server --> CPU["CPU"]
    Server --> MEM["内存"]
    Server --> STORAGE["存储"]
    Server --> NET["网络"]
    Server --> DEV["其他设备 / 驱动"]

    CPU --> LSC["lscpu"]
    CPU --> LSC1["Socket / Core / Thread / Cache"]

    MEM --> FREE["free"]
    MEM --> DMI["dmidecode"]
    MEM --> MEM1["容量 / DIMM / 类型 / 频率"]

    STORAGE --> LSBLK["lsblk"]
    STORAGE --> PCI1["lspci"]
    STORAGE --> ST1["磁盘 / RAID / HBA / NVMe"]

    NET --> IP["ip link"]
    NET --> ETH["ethtool"]
    NET --> NET1["网卡 / 链路 / 速率"]

    DEV --> PCI2["lspci -vv"]
    DEV --> USB["lsusb"]
    DEV --> DMSG["dmesg"]
    DEV --> LSHW["lshw"]
    DEV --> DEV1["设备识别 / 驱动 / 内核日志 / 整体硬件"]

这时候你就会发现:这些命令并不是孤立存在的。它们共同完成了一件事情:

把一台陌生服务器,从“黑盒子”变成一份可以理解的硬件画像。


硬件画像建立之后,再开始看性能数据

假设现在我们已经知道:

1
2
3
4
5
6
7
8
9
10
11
12
13
CPU:
2 Socket
24 Core
48 Thread

Memory:
128GB

Storage:
2 × NVMe SSD

Network:
2 × 10Gbps NIC

那么这个时候再执行:

1
top

看到:

1
CPU usage: 80%

我们的理解就会完全不同。

我们不会马上说:

“CPU 不够。”

而是会继续问:

  • 是所有 CPU 都忙吗?
  • 还是只有几个 CPU 忙?
  • 用户态 CPU 高,还是内核态 CPU 高?
  • 有没有大量 iowait?
  • 有没有进程占满单个 CPU?
  • 是否存在 CPU affinity 问题?
  • 是否涉及 NUMA?

同样,如果看到:

1
Memory usage: 90%

我们也不会马上说:

“内存不够。”

还要进一步判断:

1
2
3
4
5
6
7
8
9
是否真的没有可用内存?
↓
是否大量使用 Page Cache?
↓
是否发生 Swap?
↓
是否存在内存泄漏?
↓
是否存在 OOM 风险?

如果看到磁盘 IO 很高,也不会马上认为:

“磁盘性能不好。”

还需要结合:

1
2
3
4
5
6
7
8
9
10
11
磁盘类型
↓
IOPS
↓
吞吐量
↓
IO await
↓
队列深度
↓
业务 IO 模式

一起分析。

这就是为什么:

性能指标永远不能脱离硬件背景单独分析。


性能调优最怕什么?不是指标高,而是没有上下文

这一点非常重要。

比如:

1
CPU 使用率:80%

单独看,这个数字其实没有太大意义。你还需要知道:

1
2
3
4
5
6
7
服务器有多少 CPU?
什么 CPU?
多少 Core?
多少 Thread?
哪个进程在使用?
用户态还是内核态?
有没有 iowait?

再比如:

1
内存使用率:80%

也需要继续问:

1
2
3
4
5
总内存多少?
真正 Available 还有多少?
Cache 有多少?
Swap 是否使用?
是否发生 OOM?

磁盘也是一样:

1
Disk IO:500MB/s

听起来好像非常高。

但:

1
500MB/s 的机械盘

和:

1
500MB/s 的 NVMe

意义完全不同。网络更不用说:

1
网络流量:900Mbps

如果你的网卡是:

1
1Gbps

那已经非常接近链路上限。

如果网卡是:

1
25Gbps

那么这个流量可能只是很小的一部分。所以性能分析最核心的一点其实是:

不要只看数字,要给数字找到上下文。

而服务器硬件画像,就是这个上下文的第一部分。


一次完整的 Linux 服务器“硬件体检”

如果以后你接手一台完全陌生的 Linux 服务器,可以先按照下面的思路做一次快速体检。

第一步:看整体硬件

1
lshw -short

先快速了解:

1
2
3
4
5
CPU
Memory
Storage
Network
PCI Devices

第二步:查看 CPU

1
lscpu

重点关注:

1
2
3
4
5
6
7
CPU(s)
Socket(s)
Core(s) per socket
Thread(s) per core
Model name
L1/L2/L3 Cache
NUMA

第三步:查看内存

1
free -h

了解当前系统内存使用情况。

如果是物理服务器,再进一步:

1
dmidecode -t memory

了解:

1
2
3
4
5
内存条数量
内存容量
DIMM 插槽
内存类型
内存频率

第四步:查看服务器身份

1
dmidecode -t system

了解:

1
2
3
4
Manufacturer
Product Name
Serial Number
UUID

第五步:查看 PCI 设备

1
lspci

如果怀疑驱动问题:

1
lspci -vv

重点关注:

1
Kernel driver in use

第六步:查看存储

1
lsblk

确认:

1
2
3
4
HDD
SSD
NVMe
RAID

等信息。


第七步:查看网络

1
ip link

然后:

1
ethtool eth0

确认:

1
2
3
Speed
Duplex
Link detected

第八步:必要时查看内核日志

1
dmesg

或者针对具体问题:

1
2
3
4
dmesg | grep -i error
dmesg | grep -i memory
dmesg | grep -i network
dmesg | grep -i disk

把这次硬件体检变成一个固定习惯

做运维久了,你会发现:

真正厉害的工程师,很多时候并不是因为记住了更多命令。而是因为他们面对问题的时候,有一套稳定的排查顺序。拿到一台服务器,不是:

1
“哪里报错了?”

而是先问:

1
“这台机器是什么配置?”

然后:

1
2
3
4
5
6
7
CPU 有多少?
内存有多少?
磁盘是什么?
网卡是多少?
有没有 RAID?
有没有 NUMA?
驱动有没有问题?

这些问题回答完以后,再进入:

1
2
3
4
5
6
7
8
9
性能数据
↓
瓶颈定位
↓
根因分析
↓
优化
↓
验证

这时候你会发现,性能调优其实并没有想象中那么神秘。它更像医生看病。

flowchart LR
    A["服务器出现性能问题"] --> B["硬件体检"]
    B --> C["建立硬件画像"]
    C --> D["采集性能指标"]
    D --> E["定位异常资源"]
    E --> F["分析根因"]
    F --> G["实施优化"]
    G --> H["再次检查"]

    H --> I{"恢复正常?"}
    I -->|是| J["完成"]
    I -->|否| D

你不会因为病人发烧 39℃,就马上告诉他:

“你缺某种药。”

你需要结合年龄、身体状况、检查结果以及其他指标综合判断。性能调优也是一样。

CPU 80% 不代表 CPU 一定不够。

内存 80% 不代表内存一定不足。

磁盘 IO 高不代表磁盘一定有问题。

网络流量高也不代表网络一定异常。

所有这些指标,都必须放到具体的硬件环境中分析。


总结:性能调优思维

可以把整个过程理解成:

flowchart LR
    A["Linux 服务器"] --> B["硬件画像"]

    B --> B1["lscpu"]
    B --> B2["dmidecode"]
    B --> B3["lspci"]
    B --> B4["lshw"]
    B --> B5["lsblk"]
    B --> B6["ethtool"]

    B --> C["硬件拓扑"]
    C --> C1["lstopo-no-graphics"]
    C --> C2["numactl"]

    B --> D["硬件健康状态"]
    D --> D1["dmesg"]
    D --> D2["rasdaemon"]
    D --> D3["ras-mc-ctl"]

    C --> E["NUMA / CPU 拓扑"]
    D --> F["ECC / MCE / PCIe 等错误"]

    E --> G["性能分析"]
    F --> G

这样一来,我们对服务器的认识就从:

“这是一台 32 核、128GB 内存的 Linux 服务器。”

进一步变成:

“这是一台什么 CPU 拓扑、什么 NUMA 架构、什么内存布局、什么 PCIe 设备,并且硬件历史上有没有出现异常的服务器。”

这才算真正建立了一份比较完整的 Linux 服务器硬件画像。

而这份画像,就是后面继续分析 CPU、Load、内存、磁盘 IO、网络以及 NUMA 性能问题 的基础。