简介:一份面向VMware虚拟化运维与存储管理人员的实用技术文档,围绕精简置备(Thin)磁盘在vmfs5文件系统下无法自动回收空间的问题展开,系统梳理了两种成熟的回收方案。该文档为可编辑的docx格式,共1个文件,压缩包仅408KB,下载后方便按需批注留存。已有1984人学习下载。方案一基于微软SDelete工具:先在Windows虚机内用sdelete64.exe清理空闲空间,再停机并通过SSH登录ESXi主机执行vmkfstools命令完成回收;方案二借助Storage VMotion在线迁移,将虚拟磁盘先转为厚置备延迟归零,再迁回时改回Thin格式,从而释放空间,无需停机。两种方法均配有操作前提、具体命令与注意事项,可帮助读者根据停机窗口灵活选择;文档还给出实际使用空间27.8G但VMDK占用36.7G的典型示例,便于直观理解空间浪费成因,有效消除精简磁盘体积膨胀带来的存储浪费。
1. 为什么VMware精简置备的虚拟磁盘越删越大
物理存储只剩几个 GB,进虚拟机删掉上百 GB 的测试数据,回到宿主机一看,vmdk 文件依旧占着原来的体积。这是精简置备虚拟机的经典误判:客户机里删除文件只改了文件系统索引,数据块还留在 vmdk 里;Hypervisor 认为这些块仍然被占用,自然不会把空间还给你。精简磁盘空间回收要解决的就是这一层错位:先让客户机把空闲区域变成全零,再让宿主机识别全零块并裁剪底层稀疏文件。以下内容面向用 VMware Workstation 跑测试机、维护 vSphere 精简存储池的工程师,按“原理 → 客户机清理 → 宿主机回收 → 自动化维护”的顺序展开。
2. VMware精简置备的膨胀原理与磁盘空间回收机制
2.1 精简置备与厚置备:vmdk 文件大小规划之前的两个选择
创建虚拟机时选择精简置备,vmdk 的逻辑容量仍按配置值显示,例如你给 C 盘分配了 100 GB,但初始 vmdk 可能只有几 MB 到几十 MB,只有真正写入数据时,存储层才按 1 MB 或 8 MB 的粒度分配新块。厚置备则相反,创建瞬间就占满配置大小;而“厚置备延迟置零”比“厚置备快速置零”的创建速度快,但首次写入时有清零开销。
这个差异也决定了回收方式完全不同。厚置备磁盘的空间固定,无论客户机怎么删文件,宿主机都没法从 vmdk 回收固定块;精简置备磁盘是稀疏文件,只要宿主机认定某些块不再被映射,就能把文件尾部或中部打洞。理解这个区别,才能解释为什么同样的回收操作在精简磁盘上有效、在厚磁盘上无效。
| 对比项 | 精简置备(Thin) | 厚置备延迟置零(Thick Lazy) | 厚置备快速置零(Thick Eager) |
|---|---|---|---|
| 创建时空间占用 | 按需分配 | 立即分配 | 立即分配并清零 |
| 回收可行性 | 高,可打孔/UNMAP | 低,需迁移重写 | 低,需迁移重写 |
| 性能稳定性 | 存在写放大 | 首次写入慢 | 无首写惩罚 |
| 适用场景 | 测试机、共享存储池 | 常规生产 | 集群/FT/关键生产 |
表格说明:日常维护中,见到的空间“越用越大”多数集中在精简置备磁盘。厚置备遇到磁盘满,只能通过 Storage vMotion 迁移到更大的数据存储,不存在“瘦身”一说。
2.2 客户机“删除文件”与主机的“块释放”之间差了什么
客户机操作系统的文件系统在删除文件时,只做了两件事:把 inode 或 FAT 表项标记为“可覆盖”,把对应逻辑块号加入空闲链表。它不会通知虚拟 SCSI 控制器哪些扇区已经失效,更不会主动把扇区内容清零。于是,vmdk 底层稀疏文件仍然维护着这些块的映射,宿主机看到的仍然是“已分配且非零”的数据。
要让宿主机承认这些块可用,需要两条路径:一是客户机主动把空闲空间“写零”,让 vmdk 里对应区域变成连续全零;二是客户机发出 SCSI UNMAP/DISCARD 命令,让虚拟磁盘控制器把块映射标记为薄。大多数客户机操作系统不会自动做这两件事,精简磁盘回收的第一步永远是客户机内的清理动作。
我常用的检查命令是vmware-vdiskmanager,它能在关机状态下查看 vmdk 的实际占用和内部布局:
# 查看虚拟磁盘信息,-d 是答辩(describe)模式,不会修改磁盘内容 vmware-vdiskmanager -d "/vmware/Win11/Win11.vmdk"执行后输出里会包含VMFS、Capacity、Used等字段,重点看实际占用是否远小于配置容量。这里逻辑是:Capacity是 vmdk 标称大小,Used是当前已有数据占用的块数。如果两者差距不大,说明内部数据依然密布,回收前必须先清理客户机。
2.3 Workstation 与 ESXi 的回收路径不同,别用错命令
精简磁盘回收在不同产品线上有不同操作入口,混用命令是运维事故的重灾区。在 VMware Workstation/Workstation Pro 里,只有虚拟机关机后才能用vmware-vdiskmanager -k或-r做压缩;在 vSphere/ESXi 里,对 VMFS 数据存储可以执行esxcli storage vmfs unmap,对虚拟机磁盘本身则常用 Storage vMotion 重写副本的方式回收。
| 环境 | 常用回收操作 | 前提条件 | 是否支持在线 |
|---|---|---|---|
| Workstation / Fusion | vdiskmanager -k / -r | 关闭虚拟机 | 否 |
| vSphere + VMFS | esxcli storage vmfs unmap | ESXi 主机可访问该存储 | 是 |
| vSphere + NFS | Storage vMotion 到新存储 | 依赖 NFS 服务器是否支持 UNMAP | 否(迁移中可继续) |
| vSphere + vSAN | vSAN 自动空间再平衡 | 无需手动 | 是 |
注意,esxcli命令只作用于 VMFS 文件系统层,不能直接在 Workstation 上执行;而vmware-vdiskmanager也不认识 vSphere 的远程 VMFS 数据存储。拿错命令的典型报错是“参数无效”或“无法识别文件类型”。先确认磁盘所在环境和文件系统类型,再决策用哪条路径。
3. Windows与Linux客户机的精简空间回收实操
3.1 先在客户机把空闲块“归零”:Windows 的 sdelete -z
为了让宿主机识别全零块,回收前必须在客户机内部把未使用区域清零。Windows 最常用的工具是 Sysinternals 的sdelete,-z参数专门用于把卷的空闲空间写零。如果漏掉这一步,后续 Workstation 里执行 shrink 也不会有效果,因为 vmdk 中删掉的数据仍是随机数据,宿主机无法区分“有用”和“已删除”。
# 管理员身份运行,-z 表示把空闲空间清零 sdelete -z C:建议按需调整参数:-c是清理空闲空间(默认行为),-z是清理并清零,两者对后续 shrink 的影响不同。一般回收场景用-z;如果开启系统还原或卷影副本,先关闭它们,因为sdelete -z不会处理受保护的还原点,真正能降下来的空间有限。执行时间取决于磁盘大小和写入速度,100 GB 的卷可能要跑 10~20 分钟,不要中途强制关机。
提示:Windows 的页面文件和休眠文件会锁定部分区域,清零后这些文件占用的空间依然存在。回收前临时关闭休眠(
powercfg /h off)、把页面文件设为固定大小,能多回收几个 GB。
3.2 Linux 客户机:fstrim 和 zerofree 的使用前提
Linux 下有两个方向:支持 DISCARD 的块设备可以执行fstrim,通知底层存储批量释放块;对 VMware 虚拟磁盘这种模拟 SCSI 设备,fstrim是否有效取决于驱动和虚拟控制器的支持程度。较新的 Ubuntu/RHEL 默认采用discard=async挂载选项,但 Workstation 默认的 LSI Logic SAS 控制器并不总是转发 UNMAP,因此最稳妥的办法是用zerofree把未分配块写零。
zerofree要求分区处于只读挂载状态,所以操作顺序是:卸载或只读挂载数据目录,然后执行清零,最后重新挂载回读写模式。
# 先卸载数据盘,假设 /dev/sdb1 是需要清理的分区 umount /data # 以只读方式挂载,避免写入产生新的脏块 mount -o ro /dev/sdb1 /data # 清零空闲块,-v 显示进度 zerofree -v /dev/sdb1 # 清理完成后重新挂载 mount -o remount,rw /data参数上-n可以做试运行,只输出哪些块会被清零;-f用于强制跳过某些文件系统标记。需要说明的是,zerofree只针对 ext2/ext3/ext4,XFS 或 btrfs 请使用fstrim -v /data再看虚拟控制器是否真正转发。验证方法是在宿主机查看 vmdk 的Used是否下降。
3.3 VMware Workstation 里的 Shrink 最小命令
Shrink 本质是重建一个不含全零块的 vmdk 文件,过程需要额外临时空间,最好保证宿主机磁盘可用容量大于当前 vmdk 实际占用的 1.2 倍。先关闭虚拟机,再用vmware-vdiskmanager的-k参数压缩磁盘。
# 关闭虚拟机后执行,-k 表示 shrink 磁盘文件 vmware-vdiskmanager -k "/vmware/Win11/Win11.vmdk"执行结果会显示压缩前后的空间变化。如果你的客户机里没有先执行 3.1 或 3.2 的清零,这里压缩完也不会有明显收益。-r参数可以重新配置磁盘类型,例如把 thick 转 thin,但需要额外指定目标文件;-k只做空间回收,不改变磁盘类型。如果虚拟机有多个 vmdk 分卷,必须逐个执行,不要只压一个主磁盘。
注意:Workstation 的 Shrink 不是在线操作,运行中虚拟机执行会报“磁盘已被锁定”。SSD 上压缩耗时较短,机械盘则建议预留半小时以上的维护窗口。
3.4 回收前后如何验证 vmdk 是否瘦下来
验证是回收操作中容易被忽略的一环。vmdk 是稀疏文件,ls -lh显示的是逻辑大小,ls -ls显示的是实际占用的扇区数。压完后看实际块数是否明显下降,这才是有效回收的指标。
# 对比压缩前后的实际磁盘块占用 ls -lh /vmware/Win11/Win11.vmdk ls -ls /vmware/Win11/Win11.vmdk如果ls -ls输出的块数没有变化,回到客户机检查是否完成清零:Windows 用fsutil volume diskfree C:看可用空间,Linux 用df /data看已用空间。有一点容易被误解:-lh显示的逻辑大小通常不会变,因为它代表虚拟磁盘容量,只有某些第三方工具的“压缩”显示才会把逻辑大小改小。所以判断标准看物理块数,而不是看文件大小的第二个字段。
4. vSphere/ESXi环境下的VMDK精简与UNMAP回收
4.1 Storage vMotion 重写:最直接也最通用的回收方案
在 vSphere 环境中,最稳妥的回收方式是 Storage vMotion:把虚拟机从一个数据存储迁移到另一个数据存储(也可以是同一数据存储内的不同位置),迁移过程会按源盘实际写入的块生成新 vmdk,自动丢弃全零块和无效映射。这个操作对 VMFS、NFS、vSAN 均有效,是跨存储协议时最省心的方案。
PowerCLI 最小命令如下:
# 把虚拟机 MyVM 迁移到 datastore2,-DiskStorageFormat 可选 Thin Get-VM -Name "MyVM" | Move-VM -Datastore (Get-Datastore -Name "datastore2") -DiskStorageFormat Thin参数含义:-DiskStorageFormat Thin控制迁移后的磁盘格式,如果原来是 Thick,可以顺道转成 Thin;-RemoveSource控制迁移完成后是否删除源文件。执行前要确认目标数据存储有足够空间,迁移过程会产生一份完整的临时副本,空间不够会直接失败。注意,同一数据存储内迁移也会触发 vmdk 重建,但 vCenter 默认会对源副本做校验,耗时更长。
4.2 VMFS 上的 UNMAP:esxcli 命令与参数表
VMFS 数据存储在创建虚拟机时也会维护一层块分配映射,删除虚拟机、删除厚置备磁盘中的某些块后,VMFS 本身并不立刻把这些块返回给文件系统。从 ESXi 6.5 开始支持自动 UNMAP,但很多运维团队关闭了自动回收,所以手动执行esxcli storage vmfs unmap仍是常规操作。
# 查看数据存储的回收参数,确认是否开启自动回收 esxcli storage vmfs unmap -l # 手动对 datastore1 执行 UNMAP,优先回收连续映射 esxcli storage vmfs unmap -l datastore1 -n 2000-l后面跟数据存储名称,-n 2000表示执行 2000 次迭代,单次迭代处理一段映射区间。执行时机建议放在业务低峰:UNMAP 发出的块释放指令会对存储控制器产生压力,全闪存阵列影响较小,机械盘会出现秒级 IO 延迟波动。如果数据存储中还有快照,先删除无用快照再执行 UNMAP,否则快照引用的块不会被归还。
| 参数 | 作用 | 建议值 |
|---|---|---|
| -l | 指定数据存储名称 | 必须 |
| -n | 迭代次数 | 视数据量,100~5000 |
| -u | 每次迭代最多处理块数 | 默认 0 不限,可调小减缓冲击 |
| -a | 自动模式开关 | 不用于手动执行 |
注意区分:esxcli storage vmfs unmap释放的是 VMFS 文件系统层的空间,虚拟磁盘内部已删除文件占用的块需要先由客户机丢出 UNMAP 或清零,主机层才能感知。所以 vSphere 环境下,客户机里执行fstrim仍值得做,它能把 vmdk 内部的空闲块转成底层全零区域,随后 VMFS UNMAP 才能从文件系统层收回实际物理空间。
4.3 NFS 和 vVOL 环境:写零不再有意义的边界情况
NFS 数据存储上的 vmdk 存在于远端文件系统,VMFS UNMAP 命令无法使用。能不能回收,取决于 NFS 服务器是否实现 UNMAP 或 SCSI 映射删除协议,例如 NetApp 的 NFSv4.1 支持相关操作,基础 Linux NFS 服务则往往不支持。对这类环境,Storage vMotion 重写仍然有效,但迁移到同一 NFS 导出路径时部分阵列不会打孔,最好迁移到另一台存储再迁回。
vVOL(Virtual Volumes)环境由存储阵列管理虚拟磁盘,回收逻辑和 VMFS 不同:阵列知道每个 vVOL 的设备映射,客户机发出的 UNMAP 会直接传到阵列,由阵列回收容量。这意味着不需要在 ESXi 层执行 esxcli,只需确认虚拟机磁盘控制器启用“标记为 SSD”或已启用丢弃支持。边界情况在于:如果存储阵列的产品文档没说明支持 vVOL 自动回收,手动迁移仍是唯一可靠手段。所以遇到“回收后空间没变化”时,不要只盯着 ESXi 侧命令,要结合存储类型判断哪一层该做动作。
5. 维持精简状态:定期回收与自动化脚本
5.1 客户机内部的定时清理与回收脚本
空间回收不应该等磁盘告警才想起。更常见的做法是在客户机内设置每周自动清空回收站并执行写零,然后在宿主机侧每月做一次压缩或 UNMAP。下面是 Linux 客户机里一个可放入 crontab 的脚本,它对所有存在的 ext4 分区执行zerofree,并对支持丢弃的挂载点执行fstrim:
#!/bin/bash # 每周日凌晨 3 点执行,清理空闲空间并触发虚拟磁盘打孔 for part in $(lsblk -o NAME,TYPE -n | awk '$2=="part" {print "/dev/"$1}'); do if findmnt "$part" >/dev/null 2>&1; then fstrim "$(findmnt -n -o TARGET "$part")" || true else zerofree -v "$part" 2>/dev/null || true fi done脚本逻辑是:已挂载分区优先用fstrim在线清理,未挂载分区用zerofree写零。|| true的作用是跳过不支持的分区类型,避免脚本中途退出。配合 cron 执行时,建议重定向输出到日志文件,便于排查哪些分区没有成功回收。Windows 客户机可以用任务计划程序运行sdelete -z C:,但注意避开业务高峰,清零过程会产生较大的存储写流量。
5.2 宿主机侧的一次性回收检查
vSphere 管理员可以用 Agentless 方式直接统计数据存储上各 vmdk 的“实际占用率”,把消耗最大的磁盘找出来,再决定是否迁移或 UNMAP:
Get-Datastore -Name "datastore1" | Get-VM | ForEach-Object { $disk = Get-HardDisk -VM $_ $used = $disk.CapacityGB $provision = ($disk | Measure-Object -Property CapacityGB -Sum).Sum [PSCustomObject]@{ VM = $_.Name; CapacityGB = $provision; AllocatedGB = $used } } | Sort-Object CapacityGB -Descending | Select-Object -First 20这条命令统计的是逻辑容量,不是物理占用;实际查看物理占用需要到 ESXi 命令行用du -h /vmfs/volumes/datastore1/虚拟机目录。把逻辑容量与实际du结果放在一起对比,能直观看出哪些虚拟机膨胀最多。定期执行这类检查后,再配合 4.1 的 Storage vMotion 或 5.1 的客户机脚本,就能把空间回收做成常态维护。如果某台虚拟机回收后空间又迅速涨回来,优先检查客户机日志、临时目录和交换文件是否常驻写入,把这些写放大源掐掉,比频繁压缩磁盘更省事。
本文还有配套的精品资源,点击获取