2026年Linux磁盘与存储管理:分区、LVM 与 IO 性能全栈分析

Linux磁盘与存储管理:分区、LVM 与 IO 性能全栈分析前置阅读 Linux 文件系统入门 目录结构不是随便画的 进程管理 Linux 怎么看 怎么管 怎么杀 文章目录 引言 磁盘问题为什么难排查 整体知识框架 一 IO 栈 数据从进程到磁盘的完整路径 二 分区方案 MBR GPT 的本质区别与工具选择 2 1 MBR vs GPT 不只是大小限制 2 2 三种分区工具的使用场景 2 3 分区对齐 一个容易忽略的性能陷阱 三 LVM

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



前置阅读 :Linux 文件系统入门:目录结构不是随便画的 、 进程管理:Linux 怎么看、怎么管、怎么杀


文章目录

CPU 高了看 top,内存涨了看 free,但磁盘问题往往更隐蔽------服务响应变慢,但 CPU 和内存都正常;日志写入突然卡顿,iostat 的 Օ/code> 看起来也不高;扩容之后空间又莫名其妙不够了。

原因在于磁盘问题涉及三个独立的层次:存储层 (怎么组织物理空间)、文件系统层 (怎么管理文件)、IO 栈层(数据从进程到磁盘经历了什么)。这三层之间的问题互相影响,但诊断工具各自只照亮一个层面,需要联合起来分析。

本文的核心思路是:先理解 IO 栈的结构,再看 LVM 如何在存储层提供弹性,最后建立一套"从现象到根因"的联合分析框架------不是命令清单,是排查思路。



这张图解释了几个常见的"奇怪现象":

为什么 write 返回了但数据还没真正写到磁盘? 因为默认情况下 write 只是写进 Page Cache 就返回了,内核异步刷盘。如果进程写完就退出,而内核还没来得及刷盘,机器掉电数据就丢失了------这是 fsync() 存在的原因。

为什么 Օ/code> 不高但服务还是慢? Օ/code> 反映设备的使用率,但如果 IO 调度器队列里堆积着大量等待的请求(await 高),单位时间的设备利用率可能并不高,但每个请求的等待时间却很长。

为什么 SSD 比 HDD 快这么多? HDD 每次随机 IO 都需要物理寻道(7200rpm 的磁盘寻道时间约 4-8ms),SSD 通过 FTL 层将逻辑地址映射到 Flash 块,随机 IO 没有寻道代价(约 0.1ms 级别)。这也解释了为什么 HDD 的 IO 延迟对随机读写极其敏感,而 SSD 相对容忍。


2.1 MBR vs GPT:不只是大小限制

GPT 相比 MBR 的实质性差异不只是"支持更大的磁盘",关键在于:

  • 分区表冗余:GPT 在磁盘末尾保存了分区表的完整副本,MBR 损坏了数据会难以恢复,GPT 可以从备份恢复分区表
  • 分区数量:MBR 最多 4 个主分区(或 3 主 + 1 扩展),GPT 默认支持 128 个分区,不需要"扩展分区"这个折中方案
  • 唯一标识 :每个 GPT 分区有 UUID,不会因为磁盘添加顺序变化而导致 /dev/sdb1 变成 /dev/sdc1/etc/fstab 用 UUID 挂载更安全

服务器实践原则:2TB 以上的磁盘必须用 GPT;有 UEFI 固件的机器引导盘需要 GPT + EFI 分区;2TB 以下的数据盘两者都可以,但 GPT 更推荐。

2.2 三种分区工具的使用场景
工具 适用场景 特点 fdisk MBR 分区、老设备、脚本化操作 交互式,最广泛可用 gdisk GPT 分区专用 fdisk 的 GPT 版 parted 两者兼容,支持 GB 级参数、脚本调用 非交互友好,LVM 扩容常用

实际操作流程(以 GPT + parted 为例):

 
      
    
        
# 1. 查看磁盘整体情况 

lsblk -f # 显示磁盘、分区、文件系统、挂载点 fdisk -l /dev/sdb # 显示分区表详情

2. 使用 parted 创建 GPT 分区(适合脚本化)

parted /dev/sdb –script

mklabel gpt mkpart primary ext4 1MiB 100% align-check optimal 1 # 验证分区对齐 

3. 格式化

mkfs.ext4 -L data-disk /dev/sdb1

4. 获取 UUID 后写入 fstab(重启后自动挂载)

UUID=\((blkid -s UUID -o value /dev/sdb1) echo "UUID=\)UUID /mnt/data ext4 defaults,noatime 0 2" >> /etc/fstab

5. 挂载并验证

mount -a df -h /mnt/data

 
2.3 分区对齐:一个容易忽略的性能陷阱

现代磁盘(HDD 和 SSD)的物理扇区是 4096 字节(4K),但对外报告的仍是 512 字节的逻辑扇区。如果分区起始位置不是 4K 的整数倍,每次写入都会跨越两个物理扇区,需要"读-改-写"三步操作,性能会下降 30-50%。

partedalign-check optimal 1 命令会验证分区对齐状态------如果返回 1 aligned,则对齐正常;返回 1 not aligned 则需要调整起始位置。现代版本的 parted 在创建分区时默认会对齐到 MiB 边界(1MiB = 256 个 4K 扇区),这已经满足所有常见磁盘的对齐要求。


3.1 三层模型:PV / VG / LV

总容量 1000GB

100GB

200GB

100GB

/var/log

LVM 把物理磁盘抽象成一个存储池(VG),再从池里划分出逻辑卷(LV)给文件系统使用。这个抽象层带来三个传统分区没有的能力:

  1. 在线扩容:LV 不够用了,从 VG 里划拨更多空间过来,文件系统在线扩展,服务不需要停
  2. 跨磁盘合并:VG 可以横跨多块物理磁盘,LV 的实际数据条带化分布在各 PV 上
  3. 快照:对 LV 做快照,在不停服务的情况下得到一个一致性的数据副本

LVM 的核心单位是 PE(Physical Extent),默认 4MB。所有的空间分配都以 PE 为粒度,就像内存管理里的内存页。

3.2 基础操作:创建、查看、扩容
# ─── 初始化物理卷 ──────────────────────────────────────────── pvcreate /dev/sdb1 /dev/sdc1 pvs # 查看 PV 信息(简洁) pvdisplay /dev/sdb1 # 详细信息 # ─── 创建卷组 ──────────────────────────────────────────────── vgcreate vg_data /dev/sdb1 /dev/sdc1 vgs # 查看 VG 信息 vgdisplay vg_data # ─── 创建逻辑卷 ────────────────────────────────────────────── lvcreate -L 100G -n lv_app vg_data # 固定大小 lvcreate -l 50%FREE -n lv_db vg_data # 使用 50% 可用空间 lvs # 查看 LV 信息 # ─── 在 LV 上创建文件系统并挂载 ───────────────────────────── mkfs.xfs /dev/vg_data/lv_app mount /dev/vg_data/lv_app /app

在线扩容(最常用操作)

 
       
    
         
# 场景:/var/lib/mysql 所在 LV 空间不足,需要扩容 50GB 

步骤 1:确认 VG 有足够可用空间

vgs vg_data

VFree 列要 >= 50GB,否则需要先添加新 PV

步骤 2:扩展 LV

lvextend -L +50G /dev/vg_data/lv_db

步骤 3:扩展文件系统(不同文件系统命令不同)

ext4:

resize2fs /dev/vg_data/lv_db

xfs(xfs 只支持扩大,不支持缩小):

xfs_growfs /var/lib/mysql

验证

df -h /var/lib/mysql

 

整个过程 MySQL 不需要停止------LV 扩展是元数据操作,文件系统扩展 resize2fs/xfs_growfs 在挂载状态下操作是安全的。

向 VG 添加新磁盘(扩容前提):

 
       
    
         
# 新增了一块磁盘 /dev/sdd,初始化并加入现有 VG 

pvcreate /dev/sdd vgextend vg_data /dev/sdd

此后 VG 可用空间增加,可以继续 lvextend

 
3.3 LVM 快照:写时复制的数据结构

关键原理 :快照创建时,只记录"快照时刻 LV 的元数据",不复制任何数据。当原始 LV 上的某个数据块第一次被修改时,LVM 先把该块的旧值复制到快照空间,再写入新值。这就是"写时复制"(Copy-on-Write)。

这意味着:

  • 快照创建是瞬间完成的(只是元数据操作)
  • 快照初始占用空间很小,随着原始 LV 上的数据变化而增长
  • 快照大小需要预估原始 LV 在备份期间会发生多少变化,预留足够空间,否则快照满了会自动失效

备份使用流程

 
       
    
         
# 1. 创建快照(5GB 快照空间,用于备份期间的写时复制缓冲) 

lvcreate -L 5G -s -n snap_db /dev/vg_data/lv_db

2. 挂载快照(只读方式,得到备份时刻的一致性视图)

mkdir /mnt/snap_db mount -o ro /dev/vg_data/snap_db /mnt/snap_db

3. 备份数据(快照提供一致性视图,原始 LV 正常运行)

tar -czf /backup/mysql-$(date +%Y%m%d).tar.gz -C /mnt/snap_db .

4. 备份完成,删除快照

umount /mnt/snap_db lvremove /dev/vg_data/snap_db

 
3.4 Thin Provisioning:超额分配的利与弊

普通 LVM 创建 LV 时必须明确声明大小,从 VG 中占用实际空间。Thin Provisioning 允许创建"容量超过物理空间"的逻辑卷:先创建一个 Thin Pool,再从中创建 Thin Volume,Thin Volume 声明的大小可以超过 Pool 的实际容量------前提是实际使用量不超过 Pool。

 
       
    
         
# 创建 Thin Pool(100GB 物理空间) 

lvcreate -L 100G -T vg_data/thin_pool

从 Pool 里创建超额 Thin Volume(声明 50GB,但实际按需分配)

lvcreate -V 50G -T vg_data/thin_pool -n lv_thin_app lvcreate -V 50G -T vg_data/thin_pool -n lv_thin_db

两个 LV 声明合计 100GB,但如果实际用量不超过 100GB,没有问题

监控 Pool 使用率(关键!超出会导致所有 Thin LV 变为只读)

lvs -a -o name,lv_attr,lv_size,pool_lv,data_percent

 

生产使用风险 :Thin Pool 耗尽时,所有依赖这个 Pool 的 Thin Volume 会变成只读,服务直接挂掉。所以使用 Thin Provisioning 时必须设置告警(data_percent > 80% 时报警)并定期扩容 Pool。容器环境(Docker 的 devicemapper 驱动)大量使用 Thin Provisioning,这也是 Docker 磁盘使用超预期的根本原因之一。


4.1 iostat:指标背后的内核含义

iostat 是磁盘性能分析的第一站,但它的字段容易被误读。

# 每 2 秒刷新一次,显示 x 模式(扩展统计) iostat -xz 2

典型输出:

Device r/s w/s rMB/s wMB/s rrqm/s wrqm/s r_await w_await svctm ԣsda 10.5 45.2 0.41 1.78 0.20 12.50 4.23 28.50 0.82 22.8 nvme0n1 120.0 380.0 15.0 47.5 0.00 0.00 0.15 0.12 0.08 40.2

关键字段解读

字段 含义 排查关注点 r/s / w/s 每秒完成的读/写请求数(IOPS) 对比磁盘标称 IOPS 上限 rMB/s / wMB/s 读写吞吐量 对比磁盘标称带宽上限 rrqm/s / wrqm/s 每秒合并的读/写请求数 高值说明顺序 IO,调度器在合并请求 r_await / w_await 读/写请求的平均等待时间(ms) 核心指标,HDD 正常 <20ms,SSD <1ms svctm 平均服务时间(已弃用,不再准确) 忽略此字段 Օ/code> 设备使用率 容易误读,见下方说明

Օ/code> 为什么会撒谎Օ/code> 表示"采样周期内设备处于活跃状态的时间比例",对 HDD 有意义(因为 HDD 同一时刻只能处理一个请求),但对支持队列深度(QD)的 NVMe SSD,Օ/code> 100% 并不意味着设备饱和------设备可能在并行处理 32 个请求而总吞吐量还远没到上限。

更可靠的饱和判断方式

# 查看 IO 队列长度(通过 /proc/diskstats 计算) # 或者用 iostat -x 看 aqu-sz(平均队列长度) iostat -x 2 | grep -E "Device|sda|nvme" # aqu-sz > 1(HDD)或 > 8(NVMe)时,考虑设备已接近饱和
4.2 iotop:定位到具体进程

iostat 显示磁盘 IO 很高,但不知道是哪个进程导致的,iotop 是下一步工具。

# 只显示有实际 IO 的进程(过滤掉 0 IO 的进程) iotop -o # 批处理模式(适合脚本或日志) iotop -o -b -n 5 # 采样 5 次后退出 iotop -o -b -d 2 # 每 2 秒采样 # 如果没有 iotop,用 /proc 手工查 # 找到 IO 最多的进程 PID for pid in /proc/[0-9]*; do awk '/^(read_bytes|write_bytes)/{sum+=$2}END{print sum, FILENAME}' "$pid/io" 2>/dev/null done | sort -rn | head -10

iotop 输出中的关键列:

  • DISK READ / DISK WRITE:进程当前的磁盘 IO 速率
  • SWAPIN:从交换空间读取的比例(高值说明内存压力)
  • IO>:当前 IO 优先级,0/4 是默认的 best-effort 调度 class
4.3 iowait:被误解最多的指标

iowait 出现在 topvmstat 里,含义是"CPU 在等待 IO 完成时的空闲时间百分比"。
没有可运行进程
有进程在等 IO
意味着
意味着
不一定意味着
CPU 空闲
为什么空闲?
idle 空闲
iowait
iowait 高意味着什么?
至少有一个 CPU 在空闲
有进程正在等待 IO 完成
磁盘真的是瓶颈
例如:进程在等网络 IO






























































































iowait 会高,但磁盘不忙

iowait 高不等于磁盘是瓶颈 ,需要结合 iostatawait 和吞吐量一起看:

# 联合分析示例 # 终端 1:持续监控 CPU vmstat 2 # 终端 2:持续监控磁盘 iostat -xz 2 # 如果 iowait 高 + iostat await 高 + 吞吐量接近磁盘上限 # → 磁盘确实是瓶颈 # 如果 iowait 高 + iostat await 正常 + 吞吐量不高 # → 可能是进程在等网络 IO,或者单线程程序的 IO 等待
4.4 完整的 IO 排查流程

HDD await >50ms


dfdu 是最常用的空间分析工具,但两者报告的数字有时候差异很大------这是一个生产中真实存在的困惑。

5.1 df 与 du 差异的根本原因
 
         
    
           
# 常见困惑:df 显示 /var 使用了 80GB,du -sh /var 只显示 50GB 

df -h /var

Filesystem Size Used Avail Use% Mounted on

/dev/sda2 100G 80G 20G 80% /var

du -sh /var

50G /var

差异 30GB 去哪了?

 

原因:已删除但仍被进程打开的文件 。当一个进程打开了一个文件,即使该文件被 rm 删除了(即目录项被删除,inode 引用计数减 1),只要进程还没关闭文件描述符,实际的磁盘空间不会被释放。du 遍历目录树,看不到这些"已删除但仍占用"的文件;df 从文件系统层面统计,能看到这些空间。

定位和清理

 
         
    
           
# 找到持有已删除文件的进程 

lsof +L1

输出格式:进程名 PID 用户 FD 文件大小 文件名(deleted)

常见场景:日志文件被 logrotate 删除,但程序还在写旧文件

解决方案 1:重启该进程(让它关闭旧 fd,重新打开新日志文件)

解决方案 2:如果不能重启,向进程发 SIGHUP 让它重新打开日志

kill -HUP

 
5.2 du 使用技巧:快速找到大文件目录
# 按目录大小排序,只显示第一层(不递归) 

du -h –max-depth=1 /var | sort -rh | head -20

找出大于 1GB 的文件

find /var -type f -size +1G -exec ls -lh {} ;

找出最近 24 小时内修改的大文件(排查突然增大的日志)

find /var/log -type f -mtime -1 -size +100M

快速统计某个目录的文件数量(inode 占用分析)

find /path -type f | wc -l

 
         
    
           

文件描述符(fd)耗尽不是磁盘空间问题,但症状和磁盘问题很像------应用报"too many open files",无法创建新连接,无法写日志,看起来像磁盘坏了。

6.1 现象与诊断
# 1. 查看当前系统 fd 总使用量 cat /proc/sys/fs/file-nr # 输出:已分配数 空闲数 最大限制 # 例:32768 0 (已用 32768,最大 ) # 2. 查看单个进程的 fd 使用情况 ls -la /proc/ 
             
               /fd | wc -l # 该进程打开的 fd 数 lsof -p 
              
                | wc -l # 更详细 # 3. 查看进程的 fd 限制 cat /proc/ 
               
                 /limits | grep "open files" # 4. 找出 fd 使用最多的进程 lsof 2>/dev/null | awk '{print $1}' | sort | uniq -c | sort -rn | head -20 
                
               
             
6.2 调整 fd 上限
# ─── 临时调整(重启后失效)─────────────────────────────────── ulimit -n 65535 # 当前 shell 及其子进程的软限制 # 对运行中的进程(不需要重启) prlimit --pid 
             
               --nofile=65535:65535 # ─── 持久化调整 ────────────────────────────────────────────── # /etc/security/limits.conf(PAM 方式,用户级别) cat >> /etc/security/limits.conf < 
               
                
               
             

场景 :某台服务器上的 MySQL 响应变慢,df 显示 /var/lib/mysql 所在分区使用率 92%,系统 iowait 维持在 35-40%。

 
          
    
            
# 第一步:确认空间实际占用来源 

du -h –max-depth=2 /var/lib/mysql | sort -rh | head -20

发现 binlog 文件占用了 20GB,正常情况应该只保留 7 天

第二步:确认 binlog 占用是否可清理(查 MySQL 是否在使用)

mysql -e "SHOW BINARY LOGS;" mysql -e "SHOW MASTER STATUS;"

确认 binlog 保留策略

mysql -e "SHOW VARIABLES LIKE ‘expire_logs_days’;"

如果 expire_logs_days=0,表示不自动清理

第三步:分析磁盘 IO 是否和 binlog 有关

iostat -xz 2 & iotop -o -b -d 2 -n 5

如果 mysqld 的写 IO 很高,而 binlog purge 正在进行,可能是 purge 操作造成的 IO 峰值

第四步:清理旧 binlog 并修复自动清理策略

mysql -e "SET GLOBAL expire_logs_days = 7;" mysql -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);"

第五步:确认 LVM 状态,考虑是否扩容

lvs vg_data vgs vg_data

如果 VG 有可用空间,立即扩容 LV 防止满盘

lvextend -L +20G /dev/vg_data/lv_db xfs_growfs /var/lib/mysql

 

这个场景串联了本文的多个工具:df/du 定位空间来源、iostat/iotop 分析 IO 行为、LVM 提供在线扩容兜底------三个层次各司其职。


磁盘问题的排查本质是"分层"——确认是存储层(空间不足)、文件系统层(inode 耗尽、已删除文件占用)还是 IO 栈层(延迟高、带宽满),再对应层次选择工具。跳过分层直接用单一工具排查,往往会绕很多弯路。

LVM 在生产环境中的价值不是"高级功能",而是兜底能力——在磁盘快满的紧急情况下,有 LVM 的服务器可以在5分钟内完成在线扩容,没有 LVM 的服务器需要停机操作。这种差距在凌晨告警时体现得最为明显。

小讯
上一篇 2026-04-19 11:57
下一篇 2026-04-19 11:55

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/266136.html