1. 从“能用”到“好用”:磁盘管理进阶到底在解决什么问题
上一篇聊完fdisk分区、mkfs格式化、mount挂载这条基础链路,不少朋友留言说“分完区能用不就行了”。确实,单机跑个小服务,传统分区方案足够。但只要你经历过磁盘写满业务挂掉、数据盘换机器需要停机搬迁、某目录被日志撑爆拖垮整个应用这几个场景,就会明白“能用”和“好用”之间隔着一整片海。
Linux磁盘管理第二篇,核心就干三件事:把磁盘空间变成可以随时伸缩的池子(LVM逻辑卷管理);把多块盘变成一块盘,兼顾速度和可靠(RAID磁盘阵列);以及解决“空间够但不够用”的资源分配问题(磁盘配额与容量预警)。这三板斧解决的实际痛点非常明确:单块盘容量天花板、扩容必须停机、数据冗余缺失、以及多用户场景下空间被恶意或无意耗尽。适合谁看?已经掌握基础分区命令、正在管理多台服务器、或者被扩容和故障折腾过的运维和开发者,这篇能帮你把磁盘这一层的坑提前填平。
2. LVM逻辑卷管理:把磁盘空间变成可伸缩的资源池
2.1 为什么传统分区的扩容那么痛苦
传统分区方案下,一块盘分三个区,每个分区一旦格式化,容量就锁死了。数据写满了怎么办?加新盘,把数据拷贝过去,卸载旧盘,重新挂载。这个过程要停机,要操作窗口,还有拷贝过程中数据不一致的风险。我在某公司实习时干过一回,几百GB数据,rsync跑了快两个小时,期间服务停着,领导在旁边盯着问“还要多久”,那种压力到现在都记得。
LVM的出现就是解决这个问题的。它的设计思路是把物理磁盘的容量“抽象”出来,统一放进一个池子里,再从池子里划出逻辑卷给系统用。你不需要关心数据到底写在哪块物理盘上,只需要关心池子有多大、逻辑卷分出去多少。容量不够了,往池子里加一块新盘,然后给逻辑卷“长”一块出来,全程不用停机,不用搬数据。
2.2 LVM的三层结构一次讲透
LVM的完整链路是三层结构,理解这三层是整个LVM操作的基石。
最底层叫PV(Physical Volume,物理卷)。它由物理磁盘或分区转换而来,相当于把一块盘“登记”进LVM体系。你可以把整块盘直接变成PV,也可以把某个分区变成PV,整块盘更推荐,因为后面扩容不受分区表限制。
中间层叫VG(Volume Group,卷组),也就是前面说的“资源池”。一个VG由多个PV组成,你把几块盘都变成PV,然后统统加入同一个VG,它们的容量就汇总到一起了。VG是LVM的容量核心,它的总大小决定了你能分出去多少空间。
最上层叫LV(Logical Volume,逻辑卷),这才是系统真正能格式化、能挂载、能使用的设备。一个VG可以划分出多个LV,每个LV相当于传统分区方案里的一个分区,但比传统分区灵活得多:可以在VG容量范围内随时扩展,甚至可以缩小(缩小的操作有风险,后面会专门讲)。
设备路径的对应关系也简单:整块盘变成PV后路径是/dev/sdb,VG名和LV名由你定义,最终设备路径就是/dev/<VG名>/<LV名>,比如/dev/vg_data/lv_mysql。
2.3 从零搭建LVM的完整流程
搭建一个LVM系统的完整指令链如下,我在一套测试环境里实际跑过,每一步都验证过。
先看物理盘:
lsblk # NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT # sdb 8:16 0 100G 0 disk # sdc 8:32 0 100G 0 disk创建PV:
pvcreate /dev/sdb /dev/sdc pvs # PV VG Fmt Attr PSize PFree # /dev/sdb lvm2 --- 100.00g 100.00g # /dev/sdc lvm2 --- 100.00g 100.00g创建VG并把两块盘都加进去:
vgcreate vg_data /dev/sdb /dev/sdc vgs # VG #PV #LV #SN Attr VSize VFree # vg_data 2 0 0 wz--n- 199.99g 199.99g创建LV并格式化挂载:
lvcreate -L 50G -n lv_mysql vg_data mkfs.xfs /dev/vg_data/lv_mysql mkdir -p /data/mysql mount /dev/vg_data/lv_mysql /data/mysql这里有个必须提前想清楚的决策:文件系统选xfs还是ext4?xfs是当前主流Linux发行版的默认选择,单文件大、容量大时性能稳定,但xfs不支持在线缩小,容量只能增不能减。ext4支持在线缩小,但必须严格按步骤操作,数据安全性风险更高。正常情况下选xfs就够了,除非你明确知道未来需要回收空间。
2.4 在线扩容:不加盘和加盘的两种场景
场景一:VG容量还够。这种情况最简单,直接把LV撑大就行。
lvextend -L +20G /dev/vg_data/lv_mysql xfs_growfs /data/mysql # 注意:ext4用的是resize2fs /dev/vg_data/lv_mysqllvextend对你操作的逻辑卷扩容,-L参数指定增加量或目标容量;xfs_growfs让XFS文件系统感知到底层块设备变大,并在线扩展文件系统。XFS必须先挂载再执行growfs,ext4则可以在挂载状态下用resize2fs。
场景二:VG容量耗尽。那就需要物理层面先扩容,再加逻辑扩容。
# 虚拟机里加一块新盘 /dev/sdd pvcreate /dev/sdd vgextend vg_data /dev/sdd lvextend -L +20G /dev/vg_data/lv_mysql xfs_growfs /data/mysql整个链路:PV扩容 → VG聚合 → LV扩展 → 文件系统感知。每一层都不用动现有数据,也不需要卸载挂载点,数据库连接都不会断。这个体验值多少钱?相当于你正在开着车,4S店把邮箱变大了一圈,全程不用熄火。
2.5 LVM实操避坑指南
LVM用起来的坑,基本集中在这几个地方,我每个都踩过。
第一个坑是xfs不能在线缩小。LV可以缩小,但xfs文件系统本身不支持,必须先缩小文件系统(不可行),所以xfs格式的LV容量只能增不能减。想缩,先把数据备份、卸载分区、删除LV重建。这不是LVM的问题,是文件系统设计的选择问题。
第二个坑是快照功能。LVM自带快照(snapshot),可以在秒级生成一个逻辑卷的“时间点副本”,很多数据库备份方案都依赖它。但快照不是备份:快照会持续占用VG剩余空间,一旦快照空间耗尽,快照自动失效,数据一致性也无法保证。生产环境做快照备份时,快照卷大小至少要预留原卷的15%-20%,并且设好监控、用完就删。
提示:lvextend之后如果忘记执行xfs_growfs,df -h看到的大小不会变化,这个操作本身不报错、不提醒,特别容易被忽略。扩容三步走,每步都要确认。
第三个坑是VG缺失导致的系统无法启动。如果LV建立在多块盘上,其中一块物理盘故障,整个VG可能无法激活,系统启动时会进入救援模式。这就是为什么有经验的运维都会在/etc/fstab里用UUID而不是设备路径来挂载,并定期检查blkid输出。
3. RAID磁盘阵列:用多块盘换速度和安全感
3.1 RAID不是备份,多数人对它的理解是错的
RAID的全称是Redundant Array of Independent Disks,独立磁盘冗余阵列。核心思想是把多块物理盘组合成一个逻辑盘,由RAID控制器统一管理读写。很多人以为RAID 1就是备份,这是最经典的误解。RAID提供的是高可用性,不是数据备份:RAID 1中一块盘坏了,系统还能继续运行(因为另一块盘有完整副本),但它防不了误删除、防不了勒索病毒、防不了机房火灾。备份是另一套体系,两者不能互相替代。
常见RAID等级就五个:RAID 0、RAID 1、RAID 5、RAID 6、RAID 10。选择方案的核心权衡变量有三个:性能、容量利用率、冗余能力。
RAID 0:数据条带化写入多块盘,读取和写入性能叠加,但没有备份,任意一块盘损坏,整个阵列的数据全丢。适合完全不重要、性能优先的临时存储。
RAID 1:数据镜像写入两块盘,两块盘内容完全一致,利用率50%,读性能提升(可以并行读),写性能和单盘相当。适合系统盘、数据库日志盘这种对可靠性要求高的场景。
RAID 5:需要至少3块盘,分布式奇偶校验机制,允许坏一块盘,利用率是(n-1)/n。性能和冗余的均衡方案,但坏盘后重建阵列期间压力大,极可能再坏第二块。
RAID 6:需要至少4块盘,双奇偶校验,允许同时坏两块盘,利用率(n-2)/n,写入性能比RAID 5弱一些,因为要算两组校验数据。
RAID 10:先两两做镜像,再对镜像对做条带化。至少4块盘,利用率50%,允许每组镜像坏一块,性能最均衡。生产数据库基本是RAID 10的天下,因为它的重建速度比RAID 5快得多,故障容忍能力更强。
3.2 软RAID实测:mdadm从建到查
生产环境绝大多数用硬件RAID卡,但学习阶段和虚拟化环境里,Linux的软RAID(mdadm)完全够用,而且能帮你彻底理解RAID的工作机制。mdadm创建RAID 5的命令:
mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sdb /dev/sdc /dev/sdd创建之后查看状态:
cat /proc/mdstat # Personalities : [raid6] [raid5] [raid4] # md0 : active raid5 sdd[2] sdc[1] sdb[0] # 20958208 blocks super 1.2 level 5, 64k chunk, algorithm 2 [3/3] [UUU]模拟一块盘损坏:
mdadm --manage /dev/md0 --fail /dev/sdc cat /proc/mdstat # md0 : active raid5 sdd[2] sdc[1](F) sdb[0] # 20958208 blocks super 1.2 level 5, 64k chunk, algorithm 2 [2/3] [U_U]换上新盘并重建:
mdadm --manage /dev/md0 --remove /dev/sdc mdadm --manage /dev/md0 --add /dev/sde刚才故意用(fail)制造故障、然后替换重建的过程,就是raid管理标准流程。重建过程是纯后台任务,会持续占用磁盘IO,在生产环境带宽紧张时,可以使用mdadm的转速限制参数--bitmap和/proc/sys/dev/raid/speed_limit_max来限速,避免影响业务。重建期间[UUU]中的字母代表每块盘的状态:U正常,_缺失,F故障,能实时看到哪块盘有问题。
RAID 5重建是一个漫长且危险的过程,坏一块盘后,剩下的盘都在满负荷工作,如果其中还有一块有隐患,重建到一半可能直接整体崩溃。这也是为什么大容量盘时代,RAID 5的受欢迎程度在下降,很多存储团队都在转向RAID 10或RAID 6。
3.3 硬件RAID和软RAID怎么选
刚学的时候用的都是mdadm软RAID,因为没有额外硬件成本。但生产环境要考虑的问题就多了。
硬件RAID卡自带独立处理器和缓存,与操作系统无关,性能更好,且支持掉电保护。缺点是贵,而且RAID卡本身是单点故障——卡坏了,得找同型号卡才能恢复数据。软RAID则依赖系统CPU,性能损耗通常在5%-10%,但胜在免费、透明、可查。
个人建议:学习和实验用mdadm,生产环境视业务重要程度决定。数据库和核心应用用RAID 10(硬件卡优先),文件服务器可以考虑RAID 6,追求极致性能又不差钱的可以上RAID 0+定期备份的组合。对绝大多数中小站点来说,xfs或ext4用默认配置跑在软RAID上,性能已经绰绰有余,没有需求就不要创造需求。
注意:RAID阵列创建后,设备名(如/dev/md0)在重启后可能发生变化。必须把RAID的配置文件写进/etc/mdadm.conf,并执行update-initramfs(或有对应机制的发行版对应命令),否则重启后阵列无法自动重组。
4. 磁盘配额与容量预警:把“够用”变成“可控”
4.1 xfs配额和ext4配额有什么本质区别
多用户服务器上,最头痛的事情之一就是某用户写了一个死循环,把磁盘写满,全服务跟着躺枪。磁盘配额(quota)就是干这个的:限制每个用户(或每个组)能使用的磁盘空间上限和文件数量上限。制度管人,quota管空间。
ext4和xfs在配额机制上有个根本性的差异。ext4通过挂载参数(usrquota/grpquota)启用配额,配额文件是独立的(aquota.user/aquota.group)。xfs则把配额直接集成在文件系统元数据里,不需要额外配额文件,挂载参数直接是pquota指定,但启用后的管理命令还是xfs_quota。
xfs挂载示例:
mount -o pquota /dev/vg_data/lv_home /homeext4挂载示例:
mount -o usrquota,grpquota /dev/sdb1 /data关键区别在于xfs和ext4的配额实现粒度不同:xfs基于项目(project)概念,可以限制目录级别的用量;ext4是文件系统级别的用户配额。xfs还支持实时配额(rtquota),用于实时子卷的容量限制。对绝大多数场景来说,xfs的pquota就够用了。
4.2 实操:限制某个用户只能使用5GB
用xfs_quota给用户设置配额:
xfs_quota -x -c 'limit -u bsoft=4G bhard=5G zhangsan' /home查看配额使用情况:
xfs_quota -x -c 'report -u' /home # User quota on /home (/dev/mapper/vg_data-lv_home) # Blocks # User ID Used Soft Hard Warn/Grace # ---------- ----- ----- ----- ----------- # zhangsan 1.2G 4G 5G 00 [------]上面的bsoft和bhard是两个关键参数。soft limit是软限制,用户用到这个值后开始警告,但还能继续写入。hard limit是硬限制,到了这个值直接拒绝写入,磁盘空间会被当成“只读”,应用层报错“No space left on device”。它们之间的间隔(这里预留了1GB)是给用户清理垃圾文件的缓冲时间。
ext4只能用edquota命令配合文本编辑器操作:
edquota -u zhangsan # Disk quotas for user zhangsan (uid 1001): # Filesystem blocks soft hard inodes soft hard # /dev/sdb1 100 0 0 10 0 0然后修改soft/hard列保存退出。日常管理中最常配合使用的是repquota -a,直接列出所有用户的配额使用情况,适合写监控脚本。
4.3 容量预警:别等df报警才动手
服务器磁盘被写满是运维事故里最常见的一种。常规做法是写脚本定时查df,超过80%就发告警。脚本本身逻辑非常简单:
#!/bin/bash threshold=80 usage=$(df -h /data | awk 'NR==2 {print $5}' | tr -d '%') if [ $usage -gt $threshold ]; then echo "磁盘使用率超过${threshold}%" | mail -s "磁盘告警" admin@example.com fi但实际运维中,这个简单方案有几个盲区:df看到的是文件系统整体占用率,但有时候空间是被已删除但未释放的文件占用的(比如日志进程还握着已删文件的文件句柄);有时候是inode耗尽,df显示剩下50%空间但应用就是创建不了新文件。排查思路需要更细。
第一类:已删除文件占用空间。用lsof +L1找出被删但仍被进程持有的文件:
lsof +L1 | grep deleted | sort -k7,7rn | head第二类:inode耗尽。df -i查看inode使用率,当100%时,任何创建文件的操作都会失败。排查思路是find找出小文件密集的目录:
find /data -xdev -type f | wc -l第三类:大日志文件。日志管理不能只靠手动,logrotate的配置很关键:
cat /etc/logrotate.d/mysqld # /var/log/mysql/*.log { # daily # rotate 7 # compress # maxsize 500M # missingok # notifempty # copytruncate # }copytruncate是日志切割的常见坑:先复制日志再清空原文件,进程拿到的是同一个文件句柄,写入继续成功。但它可能丢几行日志,而归rotate则更安全:先改名再通知进程重新打开文件(需要应用支持信号重开日志)。无状态服务用归rotate,数据库之类的建议先评估再决定。
4.4 配额场景的常见Bug排查
配额不生效是排障中最常见的。常见原因有:挂载时忘了加配额参数、参数加到错误的位置、xfs的quota挂在root文件系统上(/etc/fstab里写根分区配额会导致系统启动故障)。顺序排查三步走:
第一步查挂载参数:
mount | grep /home # 应看到pquota或usrquota第二步查quota状态:
xfs_quota -x -c 'state' /home第三步试写入触发配额:切换到目标用户,写一个大文件看是否被限速。
5. 性能监控与故障排查:出现问题知道去哪看
5.1 监控工具全家桶
磁盘出问题时的第一反应不是去翻日志,而是用对工具。iostat看IO整体情况,iotop看进程级别的IO占用,lsof查文件的占用者,du按目录逐步定位大占用。命令就这几条,关键在于怎么看。
iostat的指标:tps(每秒传输次数)、KB_read/s和KB_wrtn/s、await(IO请求平均等待时间)、util(设备利用率,接近100%表示盘已处于饱和)。util是判断磁盘是否成为瓶颈的最直观指标,但它有个误区:SSD的并发能力强,util高不一定慢,要看的是await和svctm的异常。
iotop实时显示每个进程的IO读写速度和累计IO量。跑生产事故时开着iotop,基本能直接看到是哪个进程在疯狂写盘。
du定位目录:
du -h --max-depth=1 /var/log | sort -hr | head -10lsof找被占用文件:
lsof | grep deleted lsof +L1 /data5.2 软件坏道还是硬件故障,怎么区分
系统日志里出现大量IO error,业界称之为“坏道”的常见现象,实际原因非常多:盘片物理损坏、线缆松动/氧化、电源供电不稳、固件Bug、文件系统元数据损坏。不同原因的处理方式差异很大,乱动数据反而可能恶化。
一般的判断流程:先看dmesg,确认错误集中在哪块设备、报错是read还是write、有没有SCSI/ATA层级的sense code;再看smartctl信息:
smartctl -a /dev/sdb重点看Reallocated_Sector_Ct(重映射扇区数)、Current_Pending_Sector(待定扇区数)、CRC_Error_Count(线缆/接口错误)。重映射和待定扇区数字持续增长,大概率是盘片物理老化;CRC错误频繁,先怀疑线缆和背板;只有smart数据完全正常但报错不断,才考虑文件系统层的问题。
这些指标只能作为参考,不能当绝对真理。我处理过一次反复报IO error的案例,smart数据全优、坏块扫描也没问题,最后发现是磁盘背板上的SAS接口松动导致接触不良,重新插拔后恢复正常。
5.3 磁盘写满后的应急处理流程
磁盘写满是最紧急的故障,处理顺序很有讲究。我建议按以下顺序操作:
第一步:快速定位大文件
du -h --max-depth=1 / | sort -hr | head -20第二步:查找已删除未释放文件
lsof | grep deleted第三步:确认是否有日志进程在无限写
ls -lh /var/log/*.log第四步:处理完后df确认释放情况,恢复业务的顺序是先止损再排查根因。
有一点要特别提醒:不要一上来就删文件。有些文件删了之后进程仍然占用空间,比如日志被进程打开着,你删了目录项,空间照样不释放,反而越删越乱。正确做法是先判断是“文件占空间”还是“进程占空间”,再决定是清文件还是重启进程。特别是数据库场景,清理前一定评估对业务的影响面。
5.4 fstab的坑:写入错误导致系统启动失败
/etc/fstab是开机挂载的核心配置,格式是“设备UUID 挂载点 文件系统类型 挂载参数 dump fsck”。最容易踩的坑是设备路径写法:
# 错误示例:用设备名,设备名可能变动 /dev/sdb1 /data ext4 defaults 0 2 # 正确示例:用UUID UUID=6f7f0e2f-0c71-4d6c-9a07-3db1f4f9640c /data ext4 defaults 0 2设备名(sda/sdb/nvme0n1)在Linux中不保证稳定,KVM虚拟机热插拔磁盘、内核设备探测顺序变化,都可能导致设备名漂移。UUID是文件系统创建时的唯一标识符,跟设备插在哪个口没关系。
调试fstab还有一种更稳的方式,先手动挂载一遍,确认mount命令不带参数能正常挂载,再写入fstab。如果已经写错了,系统启动进不了正常模式,进入单用户模式/救援模式后执行mount -o remount,rw /、编辑fstab、注释掉坏行,再reboot回来,这是几乎每个运维都经历过的常规操作。
提示:fstab最后两项:dump和fsck。dump填0,fsck填1表示根分区开机自检、2表示其他分区开机自检、0表示不检查。很多故障都是因为把非根分区写了1,开机时检查顺序乱掉导致的启动异常。除非明确需求,普通分区fsck写0或2都行。
6. 这一年多踩过的坑:磁盘管理实战经验总结
做到这里,整个磁盘管理体系已经完整了:基础分区是“能用”,LVM把空间变成池子是“好用”,RAID解决数据冗余和性能问题,配额和预警把容量变成可控资源,监控和排查保证问题发生时能快速定位。这套东西覆盖了从单机小服务到生产集群的核心链路。
最后分享几条实战经验,都是拿血泪换来的。
第一,生产环境分区时,不要把根分区和home分区混在一个物理盘上。/bin、/var这些目录跟/home的容量需求往往是冲突的,日志把根占满会导致系统根本起不来。给根分区预留足够的余地,至少20%-30%的空间建议保留在VG里不分配出去,作为应急缓冲池。
第二,做任何LVM操作、RAID操作之前,先确认有没有完备的可恢复备份。LVM的lvremove和传统的rm一样危险,操作完就是真的没了。我就见过有朋友敲错命令,把存着半年数据的LV删了,问我要恢复工具,但我只能告诉他这个场景几乎没有恢复空间。
第三,监控要提前做。扩容、RAID重建、配额设置都是“防患于未然”的工程,真正磁盘故障那天,你不可能临时去看文档学命令。建议每台服务器提前部署好zabbix或Prometheus监控,磁盘使用率、inode使用率、smart状态、RAID状态全部纳入告警,在故障发生前发现问题,比故障发生后再排查省心得多。
第四,文档和拓扑图一定要更新。磁盘、LVM、RAID的拓扑变了,及时记录到服务器文档里。服务器一旦多起来,谁还记得三年前那块盘在哪台机器上、LV的名字为什么叫vg_data_old?好记性不如烂笔头,更不如及时更新的文档。
搞磁盘管理,核心思路就一句话:先想清楚风险和容量规划,再做操作。所有扩容、重建、迁移的操作千万条,数据安全第一条。希望这篇“二”能让你从“会敲命令”进阶到“敢接生产”。