做运维这些年,我越来越发现一个事实:很多看似诡异的问题,最后都能在磁盘管理上找到病灶。要么是分区规划不合理导致空间浪费,要么是挂载配置写错开机直接进不了系统,要么是日志把根分区撑爆才发现当初没做配额。磁盘管理在Linux里属于那种“平时不起眼,出事了全是它”的基础功,但它恰恰又最能体现一个运维或开发对系统底层的理解程度。
这篇文章我就围绕Linux磁盘管理这条主线,把分区格式化、挂载、LVM逻辑卷、配额、排障这几块内容串起来讲一遍。重点不是堆命令,而是讲清楚每一步“为什么这么做”、遇到坑时“怎么排查”。无论你是刚接触Linux的新手,还是日常跟服务器打交道的后端开发、运维工程师,按这个思路去梳理磁盘管理,应该都能少走不少弯路。
1. 分区与格式化:把一块新硬盘变成系统可用的空间
1.1 分区到底在解决什么问题
很多人一开始会疑惑:现在整块磁盘直接格式化不就能用了吗,为什么还要先分区?
原因可以从三个层面理解。首先是管理隔离。系统盘、数据盘、备份盘如果都堆在同一块磁盘上,一旦日志把空间写满,整个系统都可能因为写不进去临时文件而卡死。分开独立分区后,某个分区满了不影响其他分区的读写,就像家里把卧室和厨房分开,厨房水管爆了至少不会淹到床。
其次是文件系统的限制。不同的文件系统对单个分区或卷的大小有上限,而且不同分区可以用不同的文件系统。比如放小文件多的业务用ext4更稳,放超大文件、顺序读写多的场景用XFS更合适。这些诉求必须通过分区或卷来承载。
第三是引导需要。BIOS或UEFI启动时要读取引导程序,而引导程序往往只认特定格式、特定位置的分区,比如传统的MBR分区表或UEFI下的ESP分区。没有分区,操作系统连启动的入口都找不到。
所以分区不是给硬盘添麻烦,而是给系统和数据做规划。
1.2 分区工具选型:fdisk、gdisk、parted该怎么选
Linux下常用的分区工具有三个,我第一次用的时候也被选择困难症困扰过,这里直接说结论。
fdisk是绝大多数发行版默认带的老牌工具,交互式操作,适合处理MBR分区表。MBR分区表本身有单盘容量上限(约2TB),超过2TB的磁盘,fdisk就扶不住了。gdisk是fdisk的GPT版,界面风格几乎一样,只是底层处理的是GPT分区表,可以支持到非常大的容量,现在新加的磁盘建议一律用gdisk。parted是命令行和脚本友好的工具,擅长非交互式操作,一条命令就能完成分区创建,适合写自动化脚本,也能同时处理MBR和GPT格式。
MBR和GPT还有一个关键区别,MBR最多支持4个主分区,想更多就得把一个主分区转成扩展分区、再往里切逻辑分区,非常麻烦。GPT没有这个限制,默认就能建几十上百个分区,这也是新磁盘建议直接上GPT的理由。
注意:如果磁盘要作为系统盘在传统BIOS模式下启动,MBR依然有它的用武之地。但如果是UEFI启动或单纯做数据盘,直接选GPT即可。
1.3 分区实操步骤与对齐细节
以一块新加的1TB数据盘为例,我通常用parted一条命令完成GPT分区表的初始化和分区创建:
# 把磁盘从MBR空白状态改成GPT格式 parted /dev/sdb mklabel gpt # 创建第一个分区,从磁盘起始位置开始,占100GB parted /dev/sdb mkpart primary 0% 100GB # 查看分区结果 parted /dev/sdb print创建分区时有一个容易被忽略但非常重要的细节:对齐。硬盘物理读写的最小单位是扇区,而现代磁盘普遍采用4K扇区(或更复杂的叠瓦结构)。如果分区起点没有对齐到物理扇区边界,每次IO都可能跨越两个物理扇区,读一个小文件要额外多写一笔,长期来看性能损耗非常明显。
parted新版默认会做对齐,但如果是老版本或写脚本,最好手动指定:
parted --align=optimal /dev/sdb mkpart primary xfs 0% 100GB实操中我建议用--align=optimal参数,让parted根据磁盘参数自动计算最佳对齐位置。做完分区后,可以用下面的命令确认:
cat /sys/block/sdb/sdb1/alignment_offset如果输出为0,说明对齐没问题。
分完区必须格式化一次,不然文件系统不存在,系统没法往里写数据。格式化的命令长这样:
mkfs.ext4 /dev/sdb1 mkfs.xfs /dev/sdb1ext4和XFS的选择我放在后面章节仔细讲,这里只提醒一个易错点:mkfs是破坏性操作,执行后该分区原有数据基本无法恢复。我见过有人手滑把命令里的sdb1输成sdb,整块盘被格式化,教训相当惨痛。格式化前先lsblk确认设备名,这是必须养成的习惯。
2. 挂载与自动挂载:让系统在开机后认得你的磁盘
2.1 手动挂载:mount命令的正确用法
格式化只是给磁盘“铺好了地砖”,系统要使用它,还得把它“安装”到目录树的某个位置上,这个动作叫挂载。
挂载命令最基本的写法:
mount /dev/sdb1 /data这条命令把/dev/sdb1上的文件系统挂到/data目录。需要注意,挂载前/data目录必须存在,否则会报错。如果/data不是空目录,挂载成功后原目录里已有的内容会被“隐藏”——底层数据还在,只是访问路径被文件系统遮住了。所以挂载点最好用专用空目录,避免和已有文件混在一起。
实际生产环境不建议直接这样挂,因为没指定文件系统类型,系统靠探测识别,偶尔会出错。更严谨的写法是显式指定类型和挂载选项:
mount -t xfs -o defaults,noatime /dev/sdb1 /data这里noatime很实用。Linux默认记录每个文件的访问时间,高并发读多的小文件场景下,每次读都得更新一次元数据,白白增加磁盘IO。加上noatime后不再更新读访问时间,性能有明显提升,大多数业务场景都不影响正确性。
2.2 /etc/fstab:写错一次就让你开机进不了系统
手动挂载在重启后自动失效,想让系统开机自动挂载,必须写入/etc/fstab。
fstab每行有6个字段,按顺序分别是:设备、挂载点、文件系统类型、挂载选项、dump备份标记、fsck检查顺序。一个标准示例:
UUID=6b36d3f3-2c6f-4d0d-9c02-0e0b3f6f0e8a /data xfs defaults,noatime 0 2这里强烈建议用UUID而不是设备名。为什么?因为设备名(如/dev/sdb1)是内核按识别顺序动态分配的,插拔磁盘或调整启动顺序后,sdb可能变成sdc,如果fstab里写的是设备名,开机时就会找不到设备,进入紧急恢复模式。UUID是文件系统创建时生成的唯一标识,只要不重新格式化,就一直不变。
获取UUID的办法:
blkid lsblk -ffstab改完先别急着重启,用下面命令验证写法是否正确:
mount -a这条命令按fstab配置挂载所有尚未挂载的文件系统,如果有错误会立刻报出来。很多新手改完fstab直接reboot,结果卡在emergency mode,只能单用户模式进去改回来,非常折腾。正确的做法是先mount -a验证,再考虑重启。
注意:如果fstab真的写错导致进不了系统,在紧急模式下执行
mount -o remount,rw /把根分区重新以读写方式挂载,然后编辑fstab修正错误,再reboot恢复。
2.3 bind mount:把目录挂到另一个目录
fstab不仅能挂磁盘设备,还能把目录“投影”到另一个目录,这叫bind mount。比如某个程序只能访问/var/www,但你实际的数据在更大的存储盘/data/www上,又不想改程序路径:
mkdir -p /var/www mount --bind /data/www /var/www这种方案在迁移数据时特别好用:先在数据盘上把完整目录结构起好,拷好数据,再临时bind过去,程序无感知地切换底层存储,大部分场景都不用重启服务。
fstab里对应的写法:
/data/www /var/www none bind 0 0需要注意的是,bind mount不会改变文件的访问路径语义,程序通过/var/www写入的数据,实际落在/data/www里。记得定期备份真实路径下的数据,不要只盯着挂载点。
3. LVM逻辑卷管理:给磁盘扩容留一条后路
3.1 为什么说LVM是磁盘管理的“高配版”
直接分区方案有个很大的痛点:分区大小在创建时定死,后面空间不够了想扩容,要么重新分区——数据全没;要么迁移数据到新盘——操作繁琐耗时长。LVM(Logical Volume Manager)通过把物理磁盘抽象成“存储池”,彻底解决了这个问题。
LVM的层级像俄罗斯套娃,最底层是物理卷PV(Physical Volume),多块PV组成一个卷组VG(Volume Group),VG再切成逻辑卷LV(Logical Volume)。对上层系统来说,它看到的只是LV这块“分区”;对管理员来说,LV的大小可以在VG剩余空间内随时调整,甚至可以跨多块物理磁盘。
用LVM最适合的场景包括:数据库数据目录(经常需要扩容)、虚拟机的磁盘镜像、多个业务共享同一批物理磁盘但需要独立分配空间。如果你只是加块盘随便存点东西,分区就够用;但只要你预感到以后可能要扩容,直接用LVM能省下后面大量迁移成本。
3.2 LVM的完整创建流程
用两块新磁盘做LVM的完整命令流程长这样(设备名仅为示例,实际要按lsblk确认):
# 1. 创建物理卷 pvcreate /dev/sdc /dev/sdd # 2. 创建卷组,名字设为vg_data vgcreate vg_data /dev/sdc /dev/sdd # 3. 创建逻辑卷,分配100GB lvcreate -L 100G -n lv_web vg_data # 4. 格式化逻辑卷 mkfs.xfs /dev/vg_data/lv_web # 5. 挂载使用 mount /dev/vg_data/lv_web /data这里每一步都可以逆查:pvs看物理卷,vgs看卷组剩余空间,lvs看逻辑卷已分配大小。三套命令是LVM排障的基础,相当于物理层的“存款余额查询”。
LV的路径在/dev/下,但它的命名是符号链接,真正的设备节点在/dev/mapper/里。比如上面创建的lv_web,完整设备路径是/dev/mapper/vg_data-lv_web,/dev/vg_data/lv_web只是方便阅读的软链接。写脚本时建议统一用/dev/mapper路径,避免链接异常导致文件系统无法挂载。
3.3 扩容与缩容:在线调整空间的全过程
先说扩容。这是LVM最爽的操作,不需要停机就能给逻辑卷加空间。假设/data使用lv_web,现在空间快满了,但VG里还有600GB余量:
# 把lv_web扩大200GB lvextend -L +200G /dev/vg_data/lv_web # 关键步骤:扩容文件系统 # XFS文件系统用这个 xfs_growfs /data # ext4文件系统用这个 resize2fs /dev/vg_data/lv_web扩容后一定要记得做文件系统层面的扩容,这一步是新手最容易漏的。只扩LV不扩文件系统,系统看到的分区大小没变,df还是显示原来的容量,容易误以为命令没生效。
如果VG剩余空间也不够了,先加一块新磁盘进VG:
pvcreate /dev/sde vgextend vg_data /dev/sde然后再执行上面的lvextend。整个流程可以在业务运行期间操作,实测下来对在线服务的影响很小。
缩容就麻烦不少,而且有严格限制。XFS文件系统不支持缩减,ext4支持离线缩容(部分场景支持在线缩容)。缩容前务必备份数据,我所见过的缩容事故比例远高于扩容,非必要不建议在生产环境做。
缩容ext4的标准顺序是“先缩文件系统,再缩LV”,和扩容刚好相反:
umount /data e2fsck -f /dev/vg_data/lv_web resize2fs /dev/vg_data/lv_web 200G lvreduce -L 200G /dev/vg_data/lv_web mount /dev/vg_data/lv_web /data顺序换一下后果很严重:先缩LV再缩文件系统,文件系统的元数据可能已经被LV截断破坏,磁盘数据直接报废。我有个朋友当年就是从网上复制了反序的缩容命令,差点把整个数据库目录都搭进去。
3.4 LVM快照:低成本数据备份的实用技
LVM还支持创建快照,利用写时复制技术,在瞬间完成一个逻辑卷的“时间点镜像”。快照刚创建时几乎不占用额外空间,之后原始数据发生变更时,被修改的旧数据块会复制到快照空间里,所以快照空间大小决定了它能保存多久的“旧状态”。
一个典型场景:备份数据库前先打快照,然后从快照做备份,数据库本身几乎不受影响:
lvcreate -s -L 10G -n snap_web /dev/vg_data/lv_web mount /dev/vg_data/snap_web /mnt/snap # 从/mnt/snap拷贝数据完成备份 umount /mnt/snap lvremove /dev/vg_data/snap_web快照使用中有两个坑。一是快照空间如果被写满,快照会自动失效,所以空间至少要预估出备份期间的数据变更量。二是快照只保护LVM层面的一致性,数据库这类应用需要配合事务日志才能恢复出一致的数据状态。
4. 磁盘故障排查与性能分析:别等磁盘满了才动手
4.1 df和du这对双胞胎,用不对会被表象骗
df和du是磁盘排查最重要的两个命令,但它俩统计的维度完全不同,这也导致很多人对“磁盘满了”的判断出现偏差。
df -h看的是文件系统层,显示各挂载点的总空间、已用空间、可用空间和使用率。du -sh /目录看的是目录层,统计该目录下所有文件的实际占用大小总和。
两者对比经常能发现诡异现象:df显示某个挂载点使用率100%,但du统计挂载点里各个目录加起来远小于总占用。这种差异常见原因有三个:有删除但被进程占用着句柄的文件、隐藏的保留块、以及特殊文件。排查时用这个组合命令特别有效:
# 查看所有挂载点空间 df -h # 查看哪个目录占用最大 du -sh /* 2>/dev/null | sort -rh | head -20 # 找出已被删除但仍被进程持有的文件(重点) lsof +L1第三个命令非常神奇。进程打开文件后,你把文件删了,文件名没了,但进程还在往文件描述符里写数据,空间并不会因此释放。lsof +L1能列出所有这类“已删除但仍打开”的文件,确认后重启对应进程或服务,空间就回来了。这个现象在日志文件上出现得最多,比如删除大日志后df依然显示满,很多人一脸懵,其实根因就在这。
4.2 不只是空间:inode耗尽更隐蔽
还有一类“磁盘满”是inode耗尽。df -i查看inode使用情况,如果IUse%达到100%,哪怕磁盘还有大量剩余空间,系统也会报“No space left on device”,因为文件系统无法再创建新文件。
inode是文件系统管理文件的元数据结构,每个文件(包括目录)至少要占一个inode。小文件特别多的业务场景,比如缓存目录、消息队列积压、异常进程的临时文件,最容易把inode用光。
定位方法是先df -i看哪个分区inode使用率高,再到对应目录里统计文件数量:
for d in /data/*; do echo "$(ls -A "$d" | wc -l) $d" done | sort -rn | head根治思路是清理无用小文件,或者调整mkfs时的inode分配密度。新文件系统可以在格式化时用-i参数增大inode数量,但这是有上限的,真正高密度小文件的业务更应该考虑对象存储这类方案。
4.3 用iostat定位性能瓶颈
空间排查完,另一大类是性能问题。iostat -x 1能看到每个磁盘的详细IO指标,重点关注这几列:
%util:设备忙闲比例,接近100%说明IO已饱和await:平均每次IO请求处理时间,包含排队和服务时间svctm:实际服务时间,过高说明磁盘本身慢rkB/s、wkB/s:每秒读写数据量
举个例子,某个节点%util持续高位、await超过几十毫秒,说明磁盘性能跟不上了。这时候先看是不是日志刷盘太频繁,或者数据库的随机读写把IO吃满了。
顺手把IO调度器也看一眼,这是块设备层面的排队策略,常见的调度器有mq-deadline、kyber、none(noop)。普通使用默认就好,SSD高速盘可以用none减少排队层,机械盘用mq-deadline兼顾响应时间。修改方式:
echo none > /sys/block/sdb/queue/scheduler这只是临时生效。稳定的改动要写入udev规则或引导参数,生产环境调整前务必先做基准测试对比,不要凭感觉换调度器。
4.4 常见报错与处理速查
我在实际运维中整理了一套磁盘相关的报错速查表:
| 现象 | 可能原因 | 处理思路 |
|---|---|---|
| mount提示 device busy | 挂载点有进程占用 | fuser -km /data后先确认进程可杀再强杀 |
| 文件系统变只读 | 硬件错误或文件系统异常 | 卸载后fsck前先备份,必要时换盘 |
| df和du不一致 | 删除文件仍被进程占用 | lsof +L1定位进程并重启 |
| 开机进emergency mode | fstab写错 | 输入root密码mount -o remount,rw /修正 |
| 磁盘损坏报smart错误 | 物理介质故障 | 先备份,再长测SMART确认坏道范围 |
文件系统变为只读是相对危险的状态。有时是硬件临时异常导致VFS挂起,先卸载再重新挂载能恢复;但如果每次挂载后不久又变只读,大概率是磁盘物理损伤,赶紧备份数据换盘才是正路。
5. 磁盘配额:限制空间浪费的最后一招
5.1 配额机制与开启流程
多人共用一台服务器或某个共享目录时,单用户把磁盘写满会拖垮所有人。Linux的quota功能可以按用户、按用户组限制他们在特定文件系统上的磁盘空间与文件数量。
配额有软限制和硬限制两个概念。软限制是警告线,超过后系统会记录并给出宽限期,宽限期内还能继续写;硬限制是绝对上限,超过就直接拒绝写入,报磁盘空间不足。宽限期过了软限制也会转换为硬限制,强制拦截。
开启配额的分区,挂载时要加上usrquota(按用户限额)或grpquota(按组限额)选项:
mount -o remount,usrquota /data如果是fstab,那就在options字段里加:
UUID=xxx /data xfs defaults,usrquota,grpquota 0 0还需要确保系统安装并初始化配额数据库。不同文件系统做法略有差异,传统ext4系是quotacheck -cug /data生成配额数据库文件,然后quotaon /data启用;XFS的配额用法稍有不同,用xfs_quota工具而非传统quotacheck,这里不展开命令细节,只说核心思路:启用前确认挂载选项带了usrquota,否则后续命令会报quotafile not found之类的错误。
5.2 设置与查询配额
给用户设置额度的命令是edquota:
edquota -u zhangsan这会打开一个编辑器,里面有blocks(空间块数)、soft、hard等字段,按需修改保存。Block计数单位通常是1KB,要限制500GB就写524288000。
批量给所有用户设同一配额的常用办法是克隆:
edquota -p zhangsan -u lisi wangwu配额生效后的查询命令:
# 查看当前用户的配额使用 quota -vs # 查看整个文件系统的配额使用报表 repquota -arepquota输出里能看到每个用户的块使用数、软硬限制、超过次数等,是我巡检脚本里必加的一项。
5.3 配额使用中的坑
配额系统用久了有几点体会必须提一下。
首先,配额统计的是文件系统上的块数,不是“这个用户创建的文件的实际总大小”。如果用户对目录做了压缩打包,释放了块,配额统计会自动回落,不用手动干预。
其次,配额只对普通用户生效,root用户默认不受限制。所以别指望用配额来约束root用户的意外写满,root用户的写满只能靠监控报警和良好的日志轮转习惯来避免。
第三,配额不影响已写入的存量数据,只拦截新的写入。如果用户已经用了480GB,硬限制设为500GB,那还能写20GB;但如果用户已经用了520GB,哪怕配额刚设置,他也写不了任何新内容,只能删到500GB以下才能恢复写入。
6. 实用技巧与日常工作流沉淀
把所有东西串起来,我维护服务器时的标准流程是这样的。
新磁盘到手,先lsblk确认盘符,parted或gdisk创建GPT分区,mkfs按场景选XFS或ext4,然后立刻写入fstab并mount -a验证。如果这个磁盘未来有扩容可能,就从创建PV开始走LVM流程。挂载选项默认加noatime,减少不必要元数据写入。
日常巡检固定跑三组命令:df -h看空间水位、df -i看inode状态、iostat -x 1看IO压力。三组下来,绝大多数磁盘隐患都能提前发现。再配合repquota -a检查多人共享目录的配额使用,基本能做到睡前不用被磁盘告警叫醒。
最后分享一个我在实际项目里养成的小习惯。任何涉及系统盘的修改——不管是fstab、分区表还是LVM结构——动手之前,先把fdisk -l、blkid、df -hT、pvs/vgs/lvs的输出截图存一份到自己的记录文件。这个习惯救过我不少次:出问题后拿着操作前的原始状态对照,五分钟就能定位是自己哪一步改错了,还是硬件真的出问题了。磁盘管理的本质其实就是“清楚自己手上有什么、改了哪里、影响哪些服务”,把这三件事做好,Linux磁盘这块基本就稳了。