最近整理虚拟化环境时又遇到一个老问题:虚拟机里明明删掉了几十GB的临时文件,可数据存储上那个vmdk文件却纹丝不动,还是那么大。如果你用过VMware的精简置备(Thin Provisioning),大概率也碰到过这个现象。这篇文章就把精简置备磁盘空间回收这件事完整捋一遍,从原理到命令再到实战排查,直接把能用的步骤和参数写出来,帮你下次操作时少走弯路。
先说明一个基本事实:精简置备的精髓在于“按需分配”。虚拟机里写多少数据,vmdk就增长多少;删掉数据后,vmdk却不会自动缩回去。因为ESXi主机层面和虚拟机内部的文件系统之间,并没有一套默认的“删除通知”机制——除非你主动触发UNMAP或TRIM,否则那些已经被标记为“空闲”的块,在存储层面依然是“已分配”状态。这也是很多人备份、迁移虚拟机时发现vmdk体积远大于实际使用空间的原因。
这篇文章适合所有在用vSphere 6.0及以上版本的运维和管理员。接下来内容分四块:先讲清楚空间膨胀的机制和三种回收思路的取舍,再给出Linux和Windows虚拟机各自可落地的回收流程,最后整理几张排查速查表,把我在实际维护中踩过的坑都摊开讲。
1. 为什么精简置备的磁盘文件“只增不减”
在动手执行回收命令之前,先把原理吃透。很多人回收失败,不是命令敲错,而是没搞明白vmdk文件大小、虚拟机内文件系统大小、VMFS卷空间这三者之间的关系。
1.1 精简置备的核心机制:分配是按需的,回收不是
精简置备磁盘创建时,vmdk的“虚拟大小”可以指定为500GB,但实际占用的存储空间可能只有20GB。因为ESXi依据SCSI协议里的WRITE命令,在虚拟机真正写入数据时,才从VMFS卷里划分对应的块。这种机制的好处显而易见:一台物理主机上可以创建总体积远超物理存储容量的虚拟机,赌的就是它们不会同时写满。
但虚拟机的删除操作走的是另一条路径。当你在虚拟机内部删除文件时,客户机操作系统只是把文件系统的位图标记为“可用”,并没有通知底层SCSI设备“这些块可以回收了”。于是,宿主机的VMFS文件系统依然认为这些块属于该vmdk,不会把它们释放回存储池。日积月累,就形成了空间黑洞。
1.2 回收空间的三种途径:UNMAP、缩容、克隆对比
针对“删除文件后vmdk不缩小”的问题,常用的处理手段有三种,它们的原理和适用场景有明显差异:
| 方式 | 原理 | 适用场景 | 复杂度 |
|---|---|---|---|
| 手动UNMAP命令 | 在ESXi上执行VMFS UNMAP,通知存储层释放空闲块 | 虚拟磁盘本身是精简置备,且希望在线回收 | 低 |
| 客户机TRIM/fstrim | 客户机操作系统主动发送TRIM/UNMAP指令,配合底层UNMAP回收 | 支持TRIM的操作系统(Linux 3.0+、Windows 2012+) | 低 |
| 克隆/迁移再造磁盘 | 将虚拟机克隆到新虚拟磁盘,只复制已使用的数据块 | 无法在线回收、需要彻底整理空间时 | 中高 |
手动UNMAP是直接作用于VMFS卷的,它会扫描卷上所有可回收的“空洞”并向存储阵列发出UNMAP请求。这种方式适合用在对整个数据存储做空间整理的场景;客户机TRIM则是从虚拟机内部逐文件系统、逐块地去通知底层释放,属于最精细、最推荐优先尝试的方案;而克隆或Storage vMotion则相当于“复制一份只含有效数据的干净副本”,能彻底解决碎片和空间膨胀问题,代价是需要停机或业务低峰期执行。
1.3 版本差异:vSphere 6.5是一个分水岭
如果你用的是vSphere 6.0及更早版本,手动UNMAP是较常用的做法,但需要SSD或特定存储阵列支持,而且ESXi上执行UNMAP会占用一定的I/O资源,所以一般建议在业务低峰期做。vSphere 6.5起,VMFS6默认支持自动UNMAP,每隔一定周期(默认60天)会自动回收一次,减轻了很多手动运维压力。但自动UNMAP的触发周期比较长,如果你今天删了50GB临时文件,想立刻看到数据存储可用空间回升,依然需要手动执行一次UNMAP命令。
另外,UNMAP到底能否真正生效,还取决于底层存储阵列是否支持VNML(Virtual Machine New Local)或UNMAP相关的SCSI命令。常见的vSAN、中端存储、闪存阵列一般支持良好,但某些老旧的机械阵列可能并不响应UNMAP,导致命令执行成功但空间没有变化。这个兼容性问题,在后面的排查表里详细展开。
2. 回收前的准备:先确认三件事,再动命令
回收空间不是简单敲一条命令就能完成的。如果准备工作没做好,轻则白忙一场,重则数据损坏。我习惯在操作前固定确认三件事:目标磁盘类型、快照状态、存储阵列兼容性。
2.1 确认磁盘是否为精简置备,以及设置单位
打开虚拟机属性,查看硬盘设置。如果显示“精简置备”,说明空间有可能回收;如果是“厚置备延迟置零”或“厚置备快速置零”,那UNMAP通常不起作用,需要先做磁盘转换迁移。另外,确认磁盘的总线类型和虚拟SCSI控制器版本——较新的PVSCSI控制器对TRIM指令支持更好,老旧的LSI Logic并行控制器可能无法透传客户机的TRIM指令。
获得实际磁盘类型的命令也很快,登录ESXi主机shell,执行:
vmkfstools -v1 /vmfs/volumes/datastore1/虚拟机名/虚拟机名.vmdk注意查看输出中的“VMFS type”和“Disk Mode”字段。如果是“thick”或“eagerzeroedthick”,就说明当前方式不适合UNMAP。
2.2 快照状态是回收的隐形杀手
只要虚拟机存在快照,回收效果就会大打折扣。原因在于:快照会把原vmdk的所有块锁定为“快照底层”,即使客户机内删除了文件,处于快照底层的数据块也不能释放。很多时候磁盘文件越撑越大,不是因为平时写入多,而是快照迟迟不删除或不合并。操作前一定要确认虚拟机没有快照,或者先将快照删除并等待合并完成。
检查快照的路径有两个:vSphere Client的“快照”管理器,或通过PowerCLI查询。
Get-VM -Name "虚拟机名" | Get-Snapshot如果返回结果为空,说明无快照,可以进行后续操作。
2.3 存储阵列与VMFS版本确认
这一步容易被忽略。在VMFS5和VMFS6上,UNMAP的行为不同;在支持UNMAP的存储阵列上,命令能真正释放空间;在不支持的环境里,命令只是“静默成功”,空间却没有变化。建议在维护窗口前,查一下存储厂商的兼容性列表,或者做一个小规模的测试——在测试环境里建一个1GB的精简盘,写入数据再删除部分文件,执行UNMAP,观察数据存储空间变化。
我常用的快速测试方法是:在目标数据存储上创建一个小虚拟机(或直接使用现有虚拟机),写入一个临时文件,然后手动执行fstrim+UNMAP,对比前后数据存储可用空间。如果可用空间完全没有变化,大概率就是阵列不响应UNMAP,此时就不要浪费时间反复尝试,直接走克隆迁移方案。
3. Linux虚拟机回收流程:从fstrim到esxcli unmap,一步步写清楚
Linux虚拟机在vSphere环境里做空间回收,整体分为三个环节:虚拟机内删除文件并执行fstrim,确认文件系统与LVM层的空闲块,再到ESXi主机侧执行UNMAP。下面按顺序展开。
3.1 第一步:在虚拟机内删除无用文件,并执行fstrim
先确认内核和文件系统支持TRIM。CentOS/RHEL 6.2+、Ubuntu 16.04+通常没问题;ext4、xfs、btrfs都支持TRIM,但建议提前确认一下挂载属性,最好使用discard或定期使用fstrim。
删除文件后,执行:
fstrim -av这个命令会对所有支持TRIM的已挂载文件系统发送UNMAP指令。执行完以后,再用df确认实际使用空间:
df -h这里有一个经验:fstrim执行成功不能直接等同于回收成功。fstrim是把“文件系统层认为空闲的块”通知给底层SCSI设备,ESXi收到指令后会将这些块标记为“可回收”,但最终是否回收并交还VMFS卷,还需要等待自动UNMAP周期或手动执行ESXi侧UNMAP。所以我习惯把“fstrim”和“ESXi侧UNMAP”当成一对组合命令来执行。
3.2 第二步:处理LVM,必要时先缩容再收拢PE
如果虚拟机里使用的是LVM(比如安装CentOS时默认的lvm分区方案),文件系统删除文件后,LVM层的逻辑卷和物理卷并不会自动缩小。即使fstrim把块标记为可回收,仍需在LVM层把空间“让出来”,才能让后续的UNMAP更有效。一个常见的场景是这样的:
- 先执行
vgdisplay,查看当前卷组的“Free PE”数量与“PE Size”。 - 如果Free PE还不少,说明其实文件系统并没有把空余空间返还给LVM。
- 如果希望彻底回收,就需要缩减逻辑卷(Lvreduce),让文件系统先缩到实际使用大小,再执行pvresize收缩物理卷。
具体命令示例(以ext4为例):
# 先缩文件系统,注意顺序不可颠倒 umount /dev/mapper/vg_data-lv_data e2fsck -f /dev/mapper/vg_data-lv_data resize2fs /dev/mapper/vg_data-lv_data 100G # 再缩逻辑卷 lvreduce -L 100G /dev/mapper/vg_data-lv_data # 重新挂载 mount /dev/mapper/vg_data-lv_data /data执行完缩容后,再执行:
pvresize /dev/sda2 vgdisplay这时可以看到物理卷的“Free PE”已经归零,或者缩小到指定大小。这个动作的本质,是让LVM层的底层存储区间与文件系统实际使用量对齐,这样后续UNMAP才能回收大部分空闲块。
3.3 第三步:在ESXi主机上执行UNMAP回收
使用SSH登录到ESXi主机,开启shell后执行:
esxcli storage vmfs unmap -l 数据存储名称注意,这里的“数据存储名称”通常是类似datastore1的标识。如果需要指定具体卷,可以先执行esxcli storage vmfs list查看卷名和UUID。如果机器上同时挂载了多个VMFS卷,建议只对目标卷执行,避免不必要的全量扫描。
执行时观察返回值,正常情况下会显示类似“Done”的信息。之后可以在vSphere Client中查看数据存储的已使用空间是否下降。实际效果取决于磁盘当前的未使用程度、阵列对UNMAP的支持度。如果使用专门的数据存储监控工具,也可以用df -h对比执行前后的变化。
3.4 实操中的参数补充与执行时机
ESXi侧UNMAP在VMFS6上执行时,可以指定区块大小:
esxcli storage vmfs unmap -l datastore1 --reclaim-unit=256--reclaim-unit的单位是MB,数值越大,单次UNMAP的数据量越大,执行速度越快,但可能增加存储阵列的负载;设小一些(默认通常是4MB)则更精细,适合碎片化程度高的卷。个人经验:如果执行后发现I/O延迟上升,立即降低reclaim-unit数值或错峰执行。
执行UNMAP的时间点,建议放在业务低峰期。一个典型的场景:在凌晨备份结束后、业务起来之前执行,既能避开备份I/O,也不影响白天核心业务。
4. Windows虚拟机的替代方案:在线回收受限,怎么办
Windows虚拟机同样面临vmdk越用越大的困扰,但在线回收的限制比Linux多一些。NTFS文件系统支持TRIM,但vSphere虚拟SCSI控制器对Windows TRIM指令的透传支持并不像Linux那样“开箱即用”。另外,Windows虚拟机通常还会遇到休眠文件、页面文件、回收站文件等系统级的大块占用,这些都很难通过UNMAP直接清理。
4.1 Windows虚拟机在线回收的两个尝试
方法一:Windows内置的TRIM触发。在Windows Server 2012 R2及以上版本中,可以通过以下命令向文件系统发送TRIM指令:
fsutil behavior set DisableDeleteNotify 0 Optimize-Volume -DriveLetter C -ReTrim执行完毕后,再在ESXi侧执行UNMAP。这个方法能回收一部分块,但如果你曾经对虚拟机做过大量的文件增删,NTFS的MFT碎片和系统文件占用会导致回收率有限。
方法二:使用Storage vMotion迁移数据存储。无需真正克隆,但效果等同于克隆——将磁盘从一个VMFS卷迁移到另一个VMFS卷,底层会重新分配块,只有实际使用的数据会被复制,剩余空间就会被释放。如果只有一个数据存储,可以先创建一个临时VMFS卷做中转,迁移完成后再迁移回来,或者直接做完整克隆并替换原虚拟机。
4.2 针对大文件的补充处理:先清理,再回收
对于Windows虚拟机,我通常在回收前先做一轮“系统层面瘦身”:
- 清理临时目录、补丁缓存、Windows.old文件夹;
- 调整页面文件策略,改为固定大小或迁移至独立虚拟盘;
- 关闭休眠,删除休眠文件(powercfg /h off);
- 强制清空回收站。
然后关机,在vSphere中做个临时快照(方便回退),再开机执行上述Optimize-Volume和ESXi侧UNMAP。这样回收率能提升不少。如果这样操作后数据存储空间仍未明显下降,就不要犹豫,直接走克隆迁移,别在UNMAP命令上死磕。
5. 常见问题与排查技巧实录
最后这部分,把我在实际操作和线上故障处理中整理出的排查思路分享出来,每一条都是踩过的坑。内容偏速查性质,可以转发收藏备用。
5.1 执行完unmap后,空间完全没变
这是被问得最多的问题。可能性从高到低排列如下:
- 磁盘本身不是精简置备。厚置备磁盘没有“精简”语义,UNMAP无效。确认方式见2.1。
- 存储阵列不支持UNMAP。这种情况下命令会返回成功但并不做实际释放。建议做实验验证,或直接使用迁移/克隆。
- 有快照存在。快照底层的块无法释放,先删除快照并等待合并,或者直接合并完成后再次执行UNMAP。
- UNMAP被“未回收但不可释放的块”占满。比如vmdk里还包含了swap、日志文件碎片等依然占用的块,这些块不属于可回收范围。
此时用vmkfstools -v1看一下文件的“Allocated Size”字段,如果“Allocated Size”明显小于“vmdk Virtual Size”,说明其实有回收潜力,问题大概率出在存储阵列侧。
5.2 UNMAP执行很慢,如何加速和止损
当数据存储上的虚机较多且删除比较频繁时,UNMAP会扫描大量块,有时执行半小时代它还停着。这里有几点经验:
- 拆分执行,减少单次扫描范围。如果只需要回收某一台虚拟机的空间,不要对整个数据存储执行UNMAP,而是先迁移这台虚拟机到空卷,再对旧卷执行UNMAP,或直接克隆该虚拟机到一个新精简盘。
- 调整
--reclaim-unit参数为较大值,例如256或512,可以减少指令数,但注意观察存储阵列的I/O压力,避免影响生产。 - 执行前先查看卷的空闲程度。如果卷本身可用空间充足,反而可以不急着UNMAP——等自动UNMAP周期到了自然回收。如果卷可用空间已经低于10%,那不建议继续往里写数据,先执行UNMAP或扩容卷。
5.3 回收后虚拟机性能下降怎么解释
说实话,UNMAP本身不会让虚拟机性能下降,但它会占用存储阵列I/O,导致一段时间内其他虚拟机的延迟上升。特别是机械阵列或I/O能力偏弱的中端存储,这种影响会更明显。解决办法是严格错峰执行;生产环境建议设置限速或周期任务,并保留手动触发入口。另外,不要在同一时间对多个数据存储执行UNMAP,错开执行更稳妥。
5.4 虚拟机内fstrim报错“不支持”怎么办
Linux虚拟机里执行fstrim -av时,提示“the filesystem is not mounted with discard”或“operation not supported”。可能是几种情况:文件系统类型不支持TRIM(如FAT、NFS盘);虚拟机磁盘控制器类型太老,不传递TRIM指令;日志型文件系统的挂载选项里没有discard属性。
修复方式分两种:对支持TRIM的文件系统,修改/etc/fstab,在挂载参数里加上discard,或改用定时fstrim服务(systemctl enable fstrim.timer)。如果问题出在虚拟SCSI控制器上,那么只能通过对虚拟机进行“升级虚拟硬件”或“迁移到新虚拟磁盘”解决。这些操作可以在线执行,但建议提前备份。
5.5 快照残留导致回收不彻底的复盘案例
某台虚拟机连续三个月没有重启,磁盘占用越来越大,vmdk已扩大到了原实际使用量的两倍多。刚开始怀疑是应用日志过多,但清理日志并执行UNMAP后,空间依然没有回落。仔细检查后才发现,虚拟机有一个两个月前创建的旧快照,一直未删除。从快照管理器看很正常,但进入虚拟机目录查看vmdk列表时,能看到多个-delta.vmdk文件。删除快照并等待合并后,再执行一轮UNMAP,数据存储可用空间立刻涨了100多GB。这个案例说明了一个道理:排查空间问题时,先看快照链是否干净,比从应用层折腾文件系统高效得多。除非业务明确需要快照保护,否则重要虚拟机建议定期做“无需快照”的冷备,把快照使用周期控制到最短。
我个人的做法是:每季度固定安排一次空间回收巡检,把如下几件事一起做了——检查快照残留、清理日志和临时文件、执行fstrim和esxcli unmap、核对数据存储空间趋势。平日低峰期的定时TRIM任务也打开,虽然不能做到立刻缩小,但至少能在60天周期内逐步压回空间峰值。这个方案用了很久,操作不算复杂,胜在规律和稳定,建议你下次保养环境时也一并试试。