简介面向VMware运维人员的一份精简磁盘空间回收文档聚焦VMFS5环境下Thin磁盘不会自动释放空间这一常见困扰适合需要处理存储容量虚高、VMDK占用偏大问题的管理员与虚拟化学习者参考。压缩包内仅1个docx文件大小约408KB内容以图文记录方式组织便于按场景查阅。文档围绕两种回收路径展开一是借助SDelete清零Windows虚拟机空闲空间再停机通过ESXi命令行执行vmkfstools回收二是利用Storage VMotion迁移并转换磁盘格式在不影响业务运行的前提下完成空间释放。文中还结合Server2012R2实例对磁盘实际使用27.8G、VMDK却占用36.7G的现象做了对照说明并提示两种方法的停机要求、目标存储容量与格式选择等注意事项可帮助读者判断适用条件、理解回收原理并形成排错思路。目前已有2021人学习。1. 别等存储告警才想起它Thin 盘删了不释放卡在哪在 vSphere 里用 Thin 格式给 VMware 虚拟机分配磁盘本意是把存储超分出去、让容量跟着真实用量走。可很多人第一次遇到这个场景都会愣一下客户机里明明删掉了十几个 G 的文件磁盘属性里可用空间也回来了回头一看数据存储那个-flat.vmdk一点没瘦甚至客户机里只用了 27.8GVMDK 却实打实占了 36.7G。删掉的空间像被吞进了黑匣子既不在客户机里也没还给存储。根子在 VMFS5它不会自动回收精简卷的空闲块删除动作只发生在客户机文件系统这一层底层块是否为空VMFS 并不知道。要让它知道只有两条路——在客户机里把空闲空间写成零再让主机把这些零块打洞释放或者借一次存储迁移让新落盘的磁盘按真实用量重新分配。前一条要停机后一条可以在线做但吃目标存储容量。这份文档把两条路都写成了可照抄的步骤适合正在管 ESXi 集群、被 Thin 盘膨胀拖着的运维也适合在自己实验环境里踩过这个坑的人。2. 先把账算清Thin、VMFS5 与三个对不上的数字动手之前先别急着敲命令。同一块磁盘上会同时出现三个数字客户机操作系统报告的已用空间、数据存储里 VMDK 文件的实际占用、以及虚拟磁盘的配置大小。这三个数字对不上是常态搞清楚它们各自代表什么后面才知道回收有没有真的生效也才不会在迁移时把目标存储算爆。2.1 配置大小、实际占用与客户机用量Thin 格式的虚拟磁盘在创建时会得到一个配置大小比如 200GB这是客户机看到的最大容量但落在数据存储上的只有一个描述符文件和一个-flat.vmdk数据文件后者初始很小随客户机写入逐步增长。增长的单位是 VMFS 的块写多少分配多少所以早期它看起来非常省。问题出在只增不减。客户机删除文件时改的是自己文件系统里的元数据位图那些数据块在客户机看来空闲了但 VMFS 层面这些块仍被标记为已分配-flat.vmdk自然不缩小。于是出现正文里那个典型差值客户机实际使用 27.8GVMDK 占了 36.7G中间差出来的部分就是历史上写过、后来删掉、但从未被回收的块。判断一块盘值不值得回收我一般看两个指标客户机内已用空间与 VMDK 实际占用之差以及这个差值占配置大小的比例。差值只有几个 G回收收益有限不如等下一次维护窗口差值到几十 G 甚至上百 G那就值得排一次停机或迁移。2.2 VMFS5 为什么不会自己把空间还回来自动回收依赖一套叫 UNMAP 的机制客户机文件系统在删除文件时向下发一条这些块不要了的通知虚拟化层再转给数据存储数据存储把对应块标记为空闲。这条链路要客户机、虚拟磁盘、文件系统、后端存储四层都支持才走得通。VMFS5 这一层不支持自动 UNMAP通知到它这里就断了。所以哪怕客户机是支持 UNMAP 的系统删除动作也不会传导到数据存储-flat.vmdk只涨不跌。这也解释了为什么很多环境里 Thin 盘用了一两年之后膨胀率接近厚置备——省下来的空间又被删了不释放吃回去了。提示判断当前数据存储是不是 VMFS5在 ESXi 上执行vmfsFstypelist或直接在 vSphere 客户端看数据存储的 VMFS 版本不要凭印象。VMFS6 的行为不一样套用 VMFS5 的结论容易翻车。2.3 停机清零与在线迁移怎么选两条路的本质区别在于谁来发现空闲块。清零法是让客户机自己把空闲块写成零主机再用vmkfstools -K扫描出全零块并打洞释放全程需要虚拟机关机迁移法是让 Storage vMotion 重新写一遍磁盘新写出来的目标磁盘只分配真实数据源端旧磁盘随之删除虚拟机可以不停机。对比项sdelete vmkfstools -KStorage vMotion 借道厚置备是否停机需要关机回收命令必须在关机状态执行可在线业务不中断目标存储容量不需要额外容量需要能放下整块磁盘的配置大小耗时构成客户机清零 IO 主机扫描打洞两次全量迁移去程厚置备、回程 Thin对源盘的要求必须是 Thin且无快照无特殊要求但两次迁移都要排队适用场景有维护窗口、目标存储紧张不能停机、有富余存储或临时挂载点选型上我一般这样定能停机、且存储本来就紧张走清零法一次搞定不占额外空间不能停机、或者手头有临时存储可以借走迁移法代价是迁移期间源和目标各占一份带宽也会被吃掉一大截。两种方法可以组合使用比如先在线迁到厚置备把空间吐出来等窗口期再迁回 Thin。3. 方法一sdelete 清零加 vmkfstools -K 的完整操作链这条链路分成两段前半段在客户机里做目的是把空闲变成全零后半段在 ESXi 主机上做目的是把这些全零块从 VMDK 里摘出去。两段之间必须关机中间不能让客户机再跑起来写数据否则前面清零的区域会被重新弄脏白干一场。3.1 sdelete -z 到底在客户机里做了什么sdelete 是 Sysinternals 套件里的命令行工具常被用来安全擦除文件但它有个-z参数是专门为零化空闲空间设计的遍历目标卷上所有未被占用的簇逐块写入零写完不留下任何文件。对文件系统来说卷的已用空间没有变化对下层存储来说原先那些内容不明的空闲块现在内容确定了全是零。这一步的意义在于给主机一个可判定的信号。VMFS 无法理解 NTFS 的位图但它能识别这块数据全是零vmkfstools -K就是靠扫描全零块来决定哪些块可以打洞释放。所以清零做得越彻底后面能回收的空间越接近客户机里的空闲量。代价是 IO。零化会向卷写入等于空闲空间大小的数据量一块剩 40G 空闲的盘就要写 40G机械盘阵列上跑几个小时不稀奇。我一般放在业务低峰做并且提前确认客户机所在存储的写带宽够用别把同一数据存储上的其他虚拟机一起拖慢。3.2 客户机侧的命令与参数把sdelete64.exe拷到客户机 C 盘根目录用管理员权限打开命令提示符。第一次运行会弹出许可协议确认交互式确认在无人值守场景里容易卡住所以直接带-accepteula参数跳过。:: 进入工具所在目录 cd /d C:\ :: -accepteula 免交互接受许可-z 零化空闲空间C: 为目标卷 sdelete64.exe -accepteula -z C:执行后会看到逐块推进的百分比。参数上没有太多可调的-z就是零化模式-p可以指定覆盖次数默认一次就够多覆几次只会成倍拉长耗时对回收结果没有额外帮助-q会关掉进度输出适合写进批处理脚本但不利于观察。关于卷的选择要特别小心。正文里的环境只有一个分区所以一条命令就够了。多分区的情况必须逐个卷执行-z D:、-z E:各来一遍漏掉的卷上那部分空闲空间就回收不了。系统保留分区和恢复分区没有盘符不用管量也很小。跑完之后不要重启客户机也不要在上面继续装软件、拷文件。零化结果保存在磁盘块里客户机继续运行会正常写入新数据把刚清零的区域重新弄脏。正确做法是确认进度到 100%立刻在 vSphere 里执行关机。注意Linux 客户机没有 sdelete常见做法是用dd if/dev/zero of/zerofill bs1M把剩余空间写满再删掉文件或者用zerofree处理只读挂载的 ext 文件系统。思路一致都是把空闲块写成零。3.3 关机之后SSH 上主机执行 vmkfstools -K虚拟机关机后回收动作要在 ESXi 主机上做。先确认主机开启了 SSH 服务然后用 root 登录。虚拟机的文件都在/vmfs/volumes/数据存储/虚拟机目录/下面进目录之前先看清楚磁盘文件名带-flat的那个是数据文件vmkfstools要作用在描述符文件上也就是不带-flat后缀的那个.vmdk。# 登录 ESXi 主机把地址换成你自己的主机 ssh root192.0.2.10 # 进入虚拟机所在目录目录名含空格时要加引号 cd /vmfs/volumes/DS01/WinVM01 # 确认磁盘文件名和当前占用 ls -lh *.vmdk # 对目标磁盘执行打洞回收 vmkfstools -K WinVM01.vmdk-K的作用是扫描 VMDK 中的全零块把它们标记为空闲并归还给数据存储执行时会打印进度和最终释放的块数量。这一步只对 Thin 磁盘有意义厚置备磁盘本身已经占满打洞不会改变占用。执行前必须确保虚拟机关机因为运行中的虚拟机持有磁盘锁命令会直接报错退出。执行时间跟磁盘容量和存储性能相关几十 G 的盘通常在几分钟到十几分钟上百 G 的可能要等更久。中途不要 CtrlC中断不会损坏磁盘但已经处理的部分要重新扫。如果目录里还有快照产生的 delta 文件先别急着跑-K快照链的存在会让回收作用在错误的层级上具体处理方式在避坑那章展开。3.4 回收效果怎么验证命令跑完后不要只看它打印的成功提示回到目录里看文件实际占用。# 查看配置大小第一列是逻辑大小 ls -lh WinVM01.vmdk WinVM01-flat.vmdk # 查看实际占用块数换算后的空间 du -h WinVM01-flat.vmdkls -lh显示的是文件逻辑大小对 Thin 盘来说这个值基本等于配置大小不会因为回收而改变du -h统计的是实际占用的块回收生效后这个数字应该明显下降理想情况下接近客户机内的真实用量。两个数字的差值就是还挂在 VMDK 上没被释放的块。验证完再开机进客户机确认数据完整、卷可用。有些环境回收后第一次开机会触发文件系统检查属于正常现象等它跑完即可。如果du显示几乎没有变化先别怀疑命令回去查三件事回收前客户机有没有真正跑完零化、虚拟机是不是彻底关机、磁盘上有没有快照。4. 方法二Storage vMotion 借道厚置备的在线回收不能停机的时候这条路是唯一选择。它的巧妙之处在于不直接跟 VMFS5 的回收缺陷较劲而是绕过它既然旧磁盘上的块标记删不掉那就把数据搬到一块新磁盘上让新磁盘在写入过程中只分配真实数据搬完把旧磁盘整个删掉空间自然就回来了。4.1 迁移为什么能让空间掉下来Storage vMotion 的本质是读源盘、写目标盘、切换、删源盘。写入目标盘时虚拟化层只知道客户机文件系统里哪些块有数据无数据或全零的区域不会被实际分配所以目标盘落下来就是按真实用量分配的。源盘被删除后它占用的那些块一次性归还给数据存储膨胀了几年的大文件就此消失。这里有个前提容易被忽略迁移的目标格式选什么决定了目标盘是按需分配还是一次占满。如果目标格式仍然选 Thin那目标盘确实只占真实用量但源端空间要到迁移完成、源盘删除那一刻才释放如果选厚置备目标盘会按配置大小一次性占满源端同样在完成后释放。两种都能达到释放源端空间的目的区别在于目标端占多少。正文给的方案是去程选厚置备延迟归零回程再选 Thin。为什么要绕这一圈因为在 VMFS5 上把一块已经膨胀的 Thin 盘直接迁成 Thin目标端会按真实用量分配源端释放理论上一步到位。但在部分旧版本环境里直接 Thin 到 Thin 的迁移对已膨胀磁盘的处理并不彻底落下来仍可能带着历史占用先落成厚置备再迁回 Thin等于强制重写了两遍结果最干净。这条经验在老环境里流传很广属于稳妥优先的做法。4.2 第一次迁移改成厚置备延迟归零操作入口在 vSphere 客户端选中虚拟机右键选择迁移迁移类型选仅更改存储然后挑目标数据存储在磁盘格式那一栏选厚置备延迟归零。虚拟机右键 → 迁移 → 仅更改存储 → 选择目标数据存储容量必须 ≥ 虚拟磁盘配置大小 → 虚拟磁盘格式厚置备延迟归零Lazy Zeroed Thick → 确认并开始迁移厚置备延迟归零的含义是创建时把全部空间分配出来但块内容在首次写入前不预先清零。相比厚置备置零它省掉了迁移过程中写零的开销迁移速度快很多相比 Thin它保证目标端有完整的物理空间不会因为超分导致迁移中途失败。这一趟迁完源数据存储上的旧磁盘被删除空间立即释放。此时虚拟机的磁盘格式已经变成厚置备延迟归零占用的空间等于配置大小——如果只是想把空间要回来、不在乎格式到这里就可以收工。4.3 第二次迁移迁回 Thin还想继续享受 Thin 的容量优势就再迁一次。同样是仅更改存储目标选回原来的数据存储磁盘格式这次选Thin。虚拟机右键 → 迁移 → 仅更改存储 → 选择原数据存储此时它已有足够空闲 → 虚拟磁盘格式Thin → 确认并开始迁移这一趟写入的目标盘是 Thin只按真实数据分配落下来就是我们要的结果。原来的厚置备磁盘在迁移完成后删除它占的那份配置大小的空间一并归还。两次迁移之后虚拟机的实际占用应该接近客户机内的真实用量。顺序不要弄反。如果先去程选 Thin、回程选厚置备最后留下的是一块占满配置大小的厚盘空间没省下来。判断标准很简单最后一次迁移选的格式就是最终留在数据存储上的格式。4.4 容量与时间估算迁移法最容易翻车的地方是容量算错。去程目标端要放下整块磁盘的配置大小不是客户机的已用空间。一块配置 500G、实际只用 80G 的 Thin 盘去程目标存储必须有 500G 以上可用否则迁移直接失败而且失败前已经把一部分数据写过去需要手工清理残留。阶段目标端需要容量迁移后源端迁移后目标端占用去程厚置备延迟归零≥ 磁盘配置大小释放 配置大小回程Thin≥ 客户机真实用量释放≈ 真实用量时间上迁移速度取决于存储带宽和磁盘数量。普通千兆环境下一块几百 G 的盘跑几个小时是常事万兆或 FC 环境会快很多。迁移期间虚拟机的 IO 会走镜像模式源和目标同时承担写入如果目标存储本身压力大业务侧能感受到抖动。建议把迁移排在业务低峰并且一次只迁一台别批量排队。批量迁移会把存储带宽吃满单台的完成时间成倍拉长中途出问题时也更难定位是哪一台。迁完之后同样用du -h在主机上核对实际占用别只信客户端显示的磁盘容量。5. 避坑与排查五条现场血泪记录这两套流程单独看都不复杂真正让人加班的是细节。下面五条都是我在实际环境里遇到或帮人排查过的情况按现象、原因、解决三段写遇到对得上的直接照方抓药。5.1 清零阶段的三条记录第一条跑完vmkfstools -K占用几乎没变。现象是命令正常结束打印了完成信息但du -h看到的数字跟执行前差不多。原因通常是客户机侧零化没做彻底或者做完零化之后客户机又运行了一段时间把刚清零的区域重新写脏了主机扫描时找不到足够的全零块。解决办法是重新开机跑一遍sdelete64 -accepteula -z C:跑完立刻关机中间不重启、不做任何写操作然后重新执行-K。如果客户机有多个分区确认每个卷都做过零化。第二条命令直接报错提示磁盘被占用或无法锁定。现象是vmkfstools -K一执行就退出报文件被锁定。原因基本是虚拟机没真正关机——挂起不算关机虚拟机处于休眠或挂起状态时磁盘仍然被持有。另一种可能是这台虚拟机在别的 ESXi 主机上注册着或者有备份任务正在跑磁盘上有快照挂载。解决办法是先确认虚拟机状态是已关闭电源检查有没有残留的快照确认备份窗口已过仍不行就在主机上执行vmfslunlock类的排查思路先定位是谁持有锁再决定是否重启管理代理。第三条磁盘上有快照回收做完没效果。现象是磁盘明明膨胀得厉害回收后空间纹丝不动或者只掉了一点点。原因是快照存在时客户机的写入落在 delta 文件上基础盘变成了只读层-K作用在基础盘上能回收的只有快照创建前就已存在的零块快照之后删掉的数据全在 delta 里。解决办法是先在快照管理器里删除全部快照并等待合并完成合并过程本身会重写磁盘、可能顺带释放一部分空间合并完再按流程走一遍清零和打洞。有快照的盘不要硬做回收这是最容易白干的一步。5.2 迁移阶段的两条记录第四条去程迁移到一半失败目标存储被写满。现象是迁移进度卡在某个百分比后报错目标数据存储告警容量不足。原因是容量按客户机已用空间估算忽略了厚置备延迟归零会按配置大小一次性分配。解决办法是迁移前用配置大小加 10% 余量核算目标容量不够就先扩数据存储或者换一个更大的目标。失败后要去目标存储里删掉残留的虚拟机目录和注册信息否则那部分空间会一直挂着不释放下次迁移还会失败。第五条迁回 Thin 之后占用还是很大。现象是两趟迁移都成功了格式也确认是 Thin但du -h看到的占用远高于客户机里的真实用量。原因有两个方向一是回程迁移时客户机的空闲块里还留着历史数据虚拟化层无法判定这些块可丢弃照原样写了过去二是去程之前没做任何零化处理脏块一路被搬来搬去。解决办法是在回程迁移前先在客户机里跑一次零化能停机就用 sdelete不能停机就用系统自带的优化工具再迁回 Thin落下来的占用会明显更接近真实用量。这条的教训是迁移只保证不分配空块不保证识别脏块两者不是一回事。6. 进阶把一次性回收做成能重复执行的例行操作单次回收解决的是存量问题真正省心的是让它别再堆积。我现在管理的数据存储里Thin 盘的膨胀巡检是固定动作每季度跑一次差值超过阈值就排进维护窗口。下面两段是我常用的做法拿去改成自己环境的版本即可。6.1 用主机侧 UNMAP 做批量回收如果环境里已经有不支持自动回收之外的其他版本能力主机侧提供了一条手动触发 UNMAP 的命令可以一次性对整个数据存储做块回收不用逐台虚拟机上去敲vmkfstools。执行前先确认当前版本支持这条命令在测试数据存储上验证过再用。# 先看命令支持的参数 esxcli storage vmfs unmap --help # 对指定数据存储触发回收reclaim-unit 控制每次提交的块数量 esxcli storage vmfs unmap -l DS01 -n 200-l指定数据存储标签也可以用-u传 UUID-n是每次提交的回收单元数值越大单次处理越快但对存储的瞬时压力也越大业务时段建议调小或干脆避开。这条命令不会替代客户机侧的零化它回收的是 VMFS 层面已知的空闲块客户机里那些删除但未通知的块它照样看不见。所以正确顺序仍然是先零化、再 UNMAP两步都做才有效果。注意UNMAP 会产生持续的存储 IO在共享阵列上跑之前跟存储侧确认一下队列深度和限额别把整片存储拖慢。6.2 回收前的检查清单与巡检脚本每次动手前我都会过一遍这几项虚拟机是否已关机或已确认可在线迁移、有没有未合并的快照、目标存储容量是否够配置大小、备份任务是否在跑、客户机零化是否完成。这五项里任何一项没确认我都会先停下来因为返工的成本远高于多花十分钟检查。巡检可以用一段短脚本在主机上跑把配置大小和实际占用差值超过阈值的盘列出来作为下一轮回收的输入。#!/bin/sh # 扫描所有数据存储下的 thin 盘差值超过 5GB 的输出 THRESHOLD$((5 * 1024 * 1024 * 1024)) find /vmfs/volumes -name *-flat.vmdk -type f 2/dev/null | while read -r f; do cfg$(ls -ln $f | awk {print $5}) # 逻辑大小约等于配置大小 real$(du -k $f | awk {print $1 * 1024}) # 实际占用 diff$((cfg - real)) [ $diff -gt $THRESHOLD ] echo $f 配置$cfg 实际$real 差值$diff done脚本逻辑很直白遍历每个数据存储下的-flat.vmdk拿逻辑大小减实际占用超过阈值就打印。阈值按自己的存储规模调小环境设 5GB 合适大盘多的环境可以提到 20GB 以上避免输出刷屏。这段脚本只读不写跑在业务时段也没有风险缺点是遍历全量数据存储比较慢量大时建议分数据存储分批跑。早些年我在一个测试集群上直接对着一块有快照的盘敲了-K命令跑完什么也没释放白白占了一个停机窗口从那以后每次回收前我都强制走一遍检查清单快照、关机状态、容量余量三项确认完才动手。这套流程和命令我整理在那份文档里了按自己的环境替换路径和盘符就能用。希望帮到你。本文还有配套的精品资源点击获取