
在RH134这门课里“管理存储堆栈”这一章很多人第一次看到名字会愣一下存储就存储为什么要叫“堆栈”我第一次接触这个表述时也琢磨了半天——它不是让你把磁盘一块块堆起来而是要你把“一块物理硬盘到用户能在目录里正常读写文件”之间这一整条链路彻底搞清楚。这一章是RHCSA考试里最容易拉开分的地方也是我后来做系统运维时天天在用的底层能力。这篇文章我按自己的理解把这章拆开讲一遍从整体地图到具体命令从扩容缩容到故障排错全部结合实操经验来说。1. 先在心里搭一张“存储堆栈”地图磁盘到目录之间隔着什么我见过太多初学者上来就敲mkfs和mount结果是能跑通但稍微换个环境就懵了。原因就是脑子里没有那张“存储地图”。在 Linux 里用户访问文件走的是目录路径而数据最终落在物理磁盘上。这条路不是一步到位的中间隔着好几层。RH134 第八章讲的管理存储堆栈指的就是这些层级以及它们之间的合作关系。简单来说从下往上看是这样一个链条物理磁盘 → 分区 → 物理卷PV→ 卷组VG→ 逻辑卷LV→ 文件系统 → 挂载点如果从内核视角去看链条还可以进一步细化应用通过 VFS虚拟文件系统发请求进入具体的文件系统层再到块设备层再经过 device mapper 映射最后才到磁盘驱动和硬件设备。这也是为什么 RHEL 里 LVM 创建的设备在/dev/mapper/目录下能看到对应的映射名称因为 LVM 本质上就是基于内核 device mapper 机制实现的虚拟块设备。我在讲这套内容时经常打一个比方物理磁盘是快递公司的仓库货架分区是货架上的隔断LVM 是在仓库里重新规划出来的虚拟仓板区文件系统则是仓库管理员的登记簿——它知道仓库里每一件货文件放在哪个仓板、哪个格子。你作为用户在.bashrc里写个快捷键也好在/data目录下创建文件也好数据都不是凭空跑到硬盘上的它必须一层层“登记”“搬运”“落架”。1.1 一个读请求的实际旅行路径假设你执行cat /data/report.txt系统内部大致经历这样的过程VFS 根据路径找到/data挂载点对应的文件系统实例XFS 文件系统根据文件名找到 inode再由 inode 找到数据所在逻辑地址这些地址是“文件系统块号”层面的地址文件系统把这个地址请求发给底层块设备也就是挂载时绑定的逻辑卷设备LVM 层通过 device mapper 的映射表把逻辑卷上的地址转换成真正物理卷上的地址最终由磁盘驱动去物理硬盘的对应扇区读取数据。关键点在于每一层都在向上层提供一个“抽象”接口向下层操作另一个块设备。扩容逻辑卷时文件系统根本感知不到底层数据被分散到多块磁盘这件事它只知道自己的块设备变大了。这是 LVM 最值得学的核心价值——在线扩容实际改变的是映射关系不需要搬动已有数据。1.2 在真正的系统里一眼认出这些层判断一台机器的存储结构最直观的工具就是lsblk。我一般上了服务器先跑三条命令lsblk看结构blkid看文件系统和 UUIDdf -h看实际挂载使用情况。lsblk的输出会自动缩进展示层级关系比如NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS vda 252:0 0 40G 0 disk ├─vda1 252:1 0 1G 0 part /boot ├─vda2 252:2 0 39G 0 part │ └─vg_root-lv_root 253:0 0 39G 0 lvm / vdb 252:16 0 20G 0 disk └─vdb1 252:17 0 20G 0 part注意输出里的TYPE列disk表示物理磁盘part表示分区lvm表示逻辑卷。看到vda2下面挂着一个vg_root-lv_root就说明这台机器的根文件系统是建在 LVM 上的。这一眼扫过去整个堆栈结构就清楚了。还有一点值得提醒不要看见/dev/mapper/xxx就以为是特殊设备它其实就是逻辑卷设备节点直接对它执行mkfs、mount都没问题。真正的底层磁盘设备反而要小心操作因为很多工具比如parted、fdisk一旦写错分区表数据很难找回。2. 裸盘到可用目录从GPT分区到LVM文件系统的完整搭建这一节是整章实操量最大的部分。我给你一个比较标准的练习流程一台虚拟机里加一块 20G 的虚拟磁盘/dev/vdb我们要把它做成一个可用的挂载点/data。整个过程分四步走分区、建 PV/VG/LV、格式化文件系统、挂载并持久化。2.1 第一步分区表选型MBR还是GPT很多人觉得分区表无所谓的直接fdisk一路回车就完事。但放到现在这个习惯该改改了。MBR也叫 msdos 分区表是老前辈兼容性好但最多只能分 4 个主分区单分区上限 2T而且分区表只有一份坏了就坏一整块盘。GPT 分区表则支持 128 个分区、分区大小上限远超 2T还自带备份分区表头安全性更高。RHEL 8/9 在 UEFI 下默认就用 GPT新磁盘我基本无脑选 GPT。实操命令# 查看磁盘现状 lsblk # 给 /dev/vdb 打上 GPT 分区表标签 parted /dev/vdb mklabel gpt # 创建一个从盘头到盘尾的主分区 parted /dev/vdb mkpart primary xfs 0% 100% # 确认分区结果 lsblk /dev/vdb这里有两个小细节。第一parted的mkpart primary xfs 0% 100%中那个xfs只是给分区一个类型标识并不会真的格式化文件系统真正建文件系统在后面第二0% 100%在练习环境无所谓但在生产环境我一般会预留一点空间不把整块盘全分出去以免以后遇到分区表或对齐问题没有回旋余地。2.2 第二步LVM 三件套PV、VG、LV分区完成之后真正的 LVM 操作就开始了。LVM 的管理对象是分层递进的物理卷 PV底层分区或整盘设备LVM 会在设备开头写自己的卷标元数据卷组 VG一个“空间池”由多个 PV 组成逻辑卷 LV从 VG 里切出来的块设备可以格式化文件系统后挂载。命令顺序也很直观# 把分区初始化为物理卷 pvcreate /dev/vdb1 # 创建卷组 vg_data把刚才的 PV 放进去 vgcreate vg_data /dev/vdb1 # 从卷组里划出逻辑卷这里直接把全部空间给 lv_data lvcreate -n lv_data -l 100%FREE vg_data # 查看三件套的状态 pvs vgs lvs如果你执行完lvs会看到类似lv_data vg_data -wi-a----- 20.00g的输出。那一串-wi-a-----是 LV 的状态标记重点不是死记每个字母而是要知道-a表示 active也就是正在使用中。这里必须讲一下 VG 的默认 PE 大小。创建卷组时如果没有特别指定默认 PE Size 是 4MiB。PE 是卷组里最小的空间分配单位LV 的大小就是 PE 的整数倍。比如一块 20G 的盘PE 大小为 4MiB整块盘大约能划出 5120 个 PE。这也是为什么lvcreate既可以用-L 20G指定容量也可以用-l 5120指定 PE 数量两者本质是一回事。生产环境里如果想精细控制空间理解 PE 概念会很有用。还有一点容易被忽略合理规划下其实可以不对整块盘做分区直接pvcreate /dev/vdb也行。PV 和分区本来就不是绑定关系。但我个人强烈建议走“先分区、再 PV”的路径。原因有两个一是分区在lsblk里结构更清晰遇到问题容易定位二是万一这个盘要挪作他用比如改成普通数据盘挂载有分区表比整盘 PV 的状态更容易理解和回退。2.3 第三步文件系统与挂载有了 LV 设备/dev/vg_data/lv_data接下来才是格式化和挂载# 建 XFS 文件系统 mkfs.xfs /dev/vg_data/lv_data # 创建挂载点并临时挂载 mkdir /data mount /dev/vg_data/lv_data /data # 查看挂载结果 df -h /data到这一步/data已经可以正常读写文件了。但注意mount只是临时生效重启之后就没了。这就是 RH134 里特别强调的持久化配置问题我们放到第 4 节细聊。2.4 为什么这么分层而不是直接格式化和挂载我经常被问既然最终是格式化一个设备、挂载到目录那何必绕一圈做 PV/VG/LV答案是灵活性。直接对/dev/vdb1格式化确实简单后续想扩容只能靠分区工具而分区扩不了备份重建成本很高。用了 LVM 之后你可以随时找一块新盘pvcreate后vgextend进卷组再lvextend把逻辑卷放大最后在文件系统层执行在线扩容命令。整个过程中服务不用停数据不用动这是生产环境最需要的特性。3. 扩容缩容实战LVM的灵活性为什么是RHEL的默认答案RHEL 安装系统时默认把根文件系统建在 LVM 上这不是没有理由的。日常运维里“磁盘快满了怎么办”这个问题十次有九次是靠 LVM 解决。3.1 先搞懂文件系统类型的分水岭xfs能不能缩RHEL 8/9 的默认文件系统是 XFSRH134 课件里大量练习也是基于 XFS 的。XFS 针对大文件和大容量做了很好的设计但它有一个特性非常关键XFS 文件系统不能缩小。官方设计就是只允许增长不允许 shrink。如果你建了一个 20G 的 LV 并格式化成 XFS后面想把它缩到 10G基本没戏。所以在规划阶段就要想好逻辑卷的大小不要拍脑袋要为未来留出余量或者你明确知道需要缩容那就选择 ext4 文件系统。ext4 可以缩但缩起来步骤繁琐而且必须先卸载、检查文件系统存在数据风险。我自己在大多数场景下更倾向 XFS 预留充足空间把缩容当成“下策中的下策”。3.2 我的一次真实扩容过程有一台文件服务器跑着 Prometheus 数据目录/dataLVM 卷组vg_data里有一个 LVlv_data格式是 XFS。某天df -h一看使用率到了 92%需要临时扩展。操作是这样# 1. 先看卷组还有没有空间 vgs # 2. 看逻辑卷当前大小 lvs # 3. 卷组剩余空间足够直接给 LV 增加 20G lvextend -L 20G /dev/vg_data/lv_data # 4. 重点来了XFS 扩容要执行 growfs不是在 LV 层停了就完事 xfs_growfs /data # 5. 确认结果 df -h /data第 4 步是新手最容易漏掉的地方。lvextend只把逻辑卷这个“虚拟磁盘”变大了文件系统并不知道自己可以扩展所以必须再执行xfs_growfs让文件系统感知新空间。如果你平时用的 ext4对应的命令则是resize2fs /dev/vg_data/lv_data。对于新版 lvm2lvextend带-r选项时会自动调用适当的文件系统扩容工具。但考试也好、生产也好我建议你仍要把两步拆开理解因为自动化的底层逻辑就是这两件事理解之后再图省事才不会出问题。再补充一个细节xfs_growfs后面接挂载点/data是最省心的写法它自己会查到对应设备。直接传设备路径也能写但挂载点写法更不容易记错。3.3 缩容流程仅限ext4且必须先卸载如果你真的遇到必须缩容的极端场景用的是 ext4完整流程是这样# 1. 卸下文件系统不能在线缩容 umount /dev/vg_data/lv_dat # 2. 强制检查文件系统完整性 e2fsck -f /dev/vg_data/lv_data # 3. 把文件系统缩到目标大小比逻辑卷目标稍大一点 resize2fs /dev/vg_data/lv_data 10G # 4. 再把逻辑卷缩到目标大小 lvreduce -L 10G /dev/vg_data/lv_data # 5. 再次检查并重新挂载 e2fsck -f /dev/vg_data/lv_data mount /dev/vg_data/lv_data /data这里面最容易出错的是顺序必须先缩文件系统再缩逻辑卷千万不能倒过来。我先resize2fs把文件系统缩到 10G再lvreduce把逻辑卷从 20G 缩到 10G两者之间还留了一点余量避免文件系统边界超出逻辑卷边界导致数据损坏。我没有把缩容当成常规操作每次做都要备份这一点必须写在前头任何缩容都伴随着风险没有备份别动手。3.4 LVM快照最实用的隐藏技能RH134 第八章的重点未必是快照但运行维护两年之后你会发现 LVM 快照真的很值钱。创建快照的基本命令是lvcreate -L 2G -s -n lv_data_snap vg_data/lv_data它不复制数据而是按“copy-on-write”机制记录原始卷的数据变化。做系统升级或应用发版前给关键逻辑卷拍个快照出问题能秒级回滚。这个机制同样基于 device mapper理解了存储堆栈的分层思想之后快照就变成了很自然的能力——它就是在映射表里加了一层只读视图而已。4. 挂载持久化、UUID与交换空间那些重启后才会暴露的问题挂载这件事临时用谁都会难点在于重启之后系统还能不能自动挂载。RH134 对这块的要求非常明确你要能写出正确的/etc/fstab并且理解为什么用 UUID 而不是设备名。4.1 fstab 六字段到底在写什么/etc/fstab每一行都有 6 个字段空格或制表符分隔。拿我们前面搭的/data举例UUID3f7c1d2e-8a4b-4f6c-9d0e-123456789abc /data xfs defaults 0 0字段含义如下字段作用常见取值1设备标识/dev/vg_data/lv_data或UUID...推荐 UUID2挂载点/data、/boot、/3文件系统类型xfs、ext4、swap4挂载选项defaults、noatime、nodev等5是否允许 dump 备份一般写 06开机 fsck 检查顺序根文件系统写 1其他写 2不需要检查写 0我先解释两个最常见的坑。第一坑设备名漂移。/dev/sda、/dev/vdb这种设备名是内核按照发现顺序分配的加一块新盘、换个启动顺序、调整了虚拟机的磁盘控制器后两块盘的盘符可能对调造成挂载错位。UUID 是文件系统创建时生成的唯一标识跟设备盘符无关所以必须用 UUID。获取 UUID 我推荐blkid命令blkid /dev/vg_data/lv_data输出里UUID3f7c1d2e-...直接复制进 fstab尽量不要手敲。第二坑第六列乱写。第六列是 fsck 顺序如果你写了一个系统里根本不存在的 UUID 对应的设备开机阶段systemd-fsck会出现等待和失败最后把你送进 emergency mode。这个场景太经典了下面第五节详细说修复。4.2 写完fstab之后请先执行 mount -a这是我最想让你记住的一个习惯改完/etc/fstab不要立刻reboot去验证先执行mount -amount -a会按 fstab 内容把所有还没挂载的条目挂载一遍它是检验配置最安全的方式。如果命令静默通过再重启基本没问题如果报错直接改就行不用担惊受怕。我每次改完 fstab 都养成了这个强迫症动作已经救过我很多次。4.3 交换空间管理swap分区和swapfile第八章里的交换空间也是存储堆栈的重要组成部分。当物理内存不足时内核会把一些不常访问的内存页换出到 swap腾出物理内存给更活跃的进程。日常查看 swap 我有三个命令free -h swapon --show cat /proc/swaps创建 swapfile 的流程也比较固定。假设我要加 2G swap 文件# 用 dd 创建指定大小的文件bs 和 count 相乘等于最终大小 dd if/dev/zero of/swapfile bs1M count2048 statusprogress # 权限必须是 600否则 mkswap 会警告也不安全 chmod 600 /swapfile # 格式化为 swap 结构 mkswap /swapfile # 立即启用 swapon /swapfile为什么权限要 600swap 文件里可能会残留内存中的敏感数据普通用户如果可读等于把内存里的密钥、密码片段暴露出去。这个细节 RH134 教材里强调过我自己也在生产环境见过因为权限没设对导致的安全告警。写入 fstab 让重启之后自动启用/swapfile none swap defaults 0 0这里注意第二字段写none而不是挂载点第三字段写swap而不是文件系统类型。关于 swap 大小老教程常说“物理内存的两倍”这个说法现在已经过时了。现代服务器动辄 32G、64G 内存swap 配 64G 纯属浪费磁盘。RHEL 官方推荐的内存容量 2G 以下时设 2 倍、2G 到 8G 设与内存相同、超过 8G 反而是从 8G 起根据负载增量调整。我自己的通用策略是普通虚拟机 2G-4G swap 足够数据库服务器可以不配或少配让数据库缓冲池尽量留在内存里。还有一个内核参数值得知道vm.swappiness默认一般是 60数值越大内核越倾向于使用 swap越小越倾向于优先回收页缓存。某些对延迟敏感的场景可以把 swappiness 调低到 10 左右让内存尽量不被换出去sysctl -w vm.swappiness10写进/etc/sysctl.conf可持久生效。这不是 RH134 的必考内容但绝对符合真实运维场景。5. 存储故障排查复盘emergency模式、inode耗尽和“消失”的空间这一章的知识点如果只是“学过”而不去踩坑过两个月就会忘。我挑几个自己真实遇到、也是考试和工作中常出现的故障场景带你走一遍完整排查思路。5.1 重启后进入emergency mode我的完整排查链路场景是这样的在一台测试机上我往/etc/fstab加了一行挂载/dev/sdc1的配置UUID 没有认真抄而是凭记忆敲进去的。结果重启之后系统没有正常进入登录界面而是卡在类似这样的状态You are in emergency mode. After logging in, type journalctl -xb to view system logs.当时心里咯噔一下但修复思路其实很固定输入 root 密码进入紧急模式此时根文件系统通常是只读挂载直接改不了 fstab先重挂载为读写mount -o remount,rw /查看/etc/fstab找到错误行。注意紧急模式下没有熟悉的编辑器也可以用sed或直接用 vim只要能改vim /etc/fstab把错误行注释掉保存退出执行reboot确认能正常启动。排查过程中更高效的做法是执行journalctl -xb它会列出本次启动过程中失败的单元。如果报错信息指向某个挂载点或设备基本就是 fstab 对应的 UUID、设备名、文件系统类型三处里有一处写错了。这条链路我也带学员复盘过很多次结论都一样绝大多数情况不是文件系统损坏而是/etc/fstab里的一行抄错了。所以我的建议很明确fstab 是 boot 流程的一部分不是你随手编辑的普通配置文件每次修改都值得先mount -a验证并且备份一份再动。5.2 df -h 显示还有空间但文件就是写不进去有一次业务告警“目录写入失败”我登录上去df -h一看空间还有 30%第一反应是权限问题。结果权限正常再一看df -iinode 使用率 100%。df -i查看的是 inode 数量不是空间容量。每个文件或者目录至少消耗一个 inode存储大量小文件比如几十万个日志碎片、邮件、缓存项时磁盘空间可能没满但 inode 先耗尽了。定位到元凶之后我清了一批过期小文件之后又写了个定时任务来清理临时目录问题才算彻底解决。排查命令汇总# 看空间 df -h # 看 inode 数量 df -i # 找哪个目录文件最多 du --inodes -d 2 /var | sort -nr | head -20这个场景在第八章文件系统管理部分其实没有大篇幅展开但在实际用户环境里非常高频所以我专门提一笔。5.3 磁盘空间凭空消失文件被删但进程没释放另一个诡异问题是df -h显示使用了 100%但你去/下挨个目录du -sh怎么加都凑不出那个数字。原因是某个进程打开了文件后又把文件删除了文件系统里的目录项已经没了但进程持有的文件描述符还没关闭文件占用的块自然也不会释放。排查方法# 找出所有已被删除但仍被进程占用的文件 lsof | grep deleted或者更精确lsof L1拿到进程号之后重启或者让应用重新打开日志即可释放空间。如果是个不该重启的数据库那就得临时扩 LV等维护窗口再做处理。这类问题属于“存储堆栈”上层和进程管理交叉的典型场景我把它写进来是想提醒你排查空间问题不要只看文件系统还要看进程在背后做了什么。5.4 多层存储结构下怎么快速定位“到底哪一层出了问题”排查 LVM 相关问题我会按层级从上往下看文件系统层df -h看空间mount看挂载选项LV 层lvs看状态是否为 activeVG 层vgs看 PE 分配情况PV 层pvs看物理卷是否在线底层设备lsblk、dmesg | tail看驱动和硬件错误。如果 LVM 设备消失了优先执行pvscan和vgchange -ay尝试重新激活卷组。很多情况下只是重启后卷组没有被自动激活并不代表数据损坏。这条经验在处理虚拟机迁移、快照恢复时特别有用。最后说几句实在话弄懂了存储堆栈这一章你会发现后面学系统调优、容器存储、云镜像制作都轻松很多因为底层概念都是同一套。我个人的建议是不要满足于把命令背下来去找一台练习虚拟机建一个 VG、切几个 LV、格式化、挂载、扩容、再拍快照折腾坏了再从零来一遍。摔过几次跟头之后分区表、LVM、UUID、挂载选项这些东西就会成为你的肌肉记忆。RHCSA 考试里存储相关的题目很多但真正到了生产环境这一章的价值远比考试分数大。