ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VMware虚拟机vmdk只涨不缩?精简置备磁盘空间回收全攻略

VMware虚拟机vmdk只涨不缩?精简置备磁盘空间回收全攻略 “这真的见鬼了。”我盯着vCenter里的存储空间图表某台Windows虚拟机所在的数据存储可用容量掉到了8%。但这台虚拟机我明明上个季度才清理过客户机里C盘总共才用了不到60GB可它的vmdk在数据存储上硬生生占了200多GB。之后我在客户机里删掉了将近50GB的临时文件和日志刷新了好几遍数据存储上的已用空间纹丝不动。那一刻我意识到不把VMware精简置备磁盘的容量回收机制彻底搞明白光靠“删文件”是治不了标更治不了本的。这篇文章就是那次排查和清理全过程的记录。我把它完整写下来是因为无论是生产环境里的ESXi管理员还是在自己电脑上用Workstation跑虚机的朋友都会撞见同一个坑精简置备的vmdk只会一点一点涨却从来不会因为你删了客户机里的数据就自动往回缩。本文会把这个现象背后的原理、动手前的检查项、Windows和Linux两种客户机的标准回收流程、处理过程中的常见坑以及我现在的例行维护节奏都交代清楚。如果你正在为“虚拟磁盘只涨不缩”的头疼这篇文章可以直接照着抄。1. 讲清楚“只涨不缩”这件事先看精简置备在宿主层的存储模型1.1 vmdk不是普通文件是带“欺骗性”的稀疏大文件很多人把虚拟磁盘想象成一个巨大的镜像文件虚拟机往里写多少数据文件就变大多少删除数据文件就变小。这个理解放在精简置备上前一半对后一半完全错。VMware里的精简置备thin provisioning磁盘概念上很像Linux里常见的稀疏文件sparse file。创建的时候vmdk的描述文件写明了磁盘最大容量但底层实际占据的块非常小可能只有几MB的文件头。之后客户机操作系统往盘里写数据虚拟磁盘层才按需从数据存储里申请新的块来存储。系统装的软件越多、写入的数据越多vmdk占用的物理空间就越大。关键就在“按需申请”这四个字上虚拟机只关心“我这张盘最大有100GB”数据存储则只关心“这个vmdk现在用了多少真实块”。两者之间没有一条能自动对账的通道。客户机里删了文件对vmdk来说那些块还老老实实躺在存储上呢。1.2 客户机的“删除”动作在vmdk层到底发生了什么在Windows的NTFS里删一个文件系统只是修改了文件系统元数据把那部分簇标记为“空闲可写”。在Linux的ext4或者xfs上删文件也是类似inode和位图更新一下数据块里的旧比特根本没被碰过。这些被标记为空闲的块在宿主机的vmdk文件里仍然是实实在在的物理空间里面还留着旧文件的数据残片。因为VMM虚拟机监视器只看得见虚拟SCSI设备上的逻辑块地址它不知道这些块在客户机文件系统的眼里已经是“垃圾”。我用一个集装箱仓库类比过很多次精简置备相当于你跟仓库管理员说“给我预留100个柜位的区域但我现在只放20箱”然后你往里面堆货堆多少收费多少。有一天你清理了仓库扔掉了30箱垃圾但垃圾实物还在原地没拖走管理员看了眼监控发现你占用的区域一点没少账单自然也不会降。1.3 最典型的一个故障现场说回我开头遇到的那个场景虚拟机Windows Server 2019系统盘精简置备配置容量为300GB客户机内C盘已用空间约60GBvmdk实际占用数据存储空间约230GB数据存储剩余空间只剩8%我在客户机里清掉临时文件、回收站、Windows更新缓存之后C盘“已用空间”确实降到了45GB左右但数据存储上那个vmdk没有任何变化。这个现场就是“只涨不缩”的标准形态。这里面还叠加了一个非常隐蔽的因素Windows的碎片整理、数据库日志、各种应用产生的随机IO会让块分布非常零散。对精简置备盘来说就算客户机内已经删了很多数据如果大量块散布在各处数据存储看来就像到处都被占用后续写入还会优先复用空闲块而不是让vmdk缩小。提示确定要回收精简置备盘的空间本质上不是“把vmdk文件压缩”而是“让vmdk里那些代表客户机空闲块的物理块变成真正的零块然后让存储层把零块摘出去”。2. 动手回收前这三个检查项比命令本身更决定成败第一次做容量回收时我直接在客户机删了文件关机后对着vmdk执行了收缩命令结果宿主机报错数据存储空间一点没少。排查了半天才发现我犯了一个新手很容易犯的错忘了处理快照。2.1 快照是所有回收操作的头号死敌只要虚拟机存在任何快照它的磁盘就由一个基础磁盘加一个或多个delta盘组成。客户机里写入的新数据跑到delta盘上去了基础vmdk是只读的。你想对基础盘做空间回收技术上就说不过去就算强行执行回收出来的也只是基础盘里那些本来就被“冻结”的块对当前运行状态没什么帮助。VMware官方对这种情况的建议也是先删除快照再谈回收。所以在执行清理动作前我一定先在vCenter里检查这台虚拟机是否带快照vCenter界面里选中虚拟机右键 → Snapshot → Manage Snapshots确认列表里没有任何快照条目如果确实有快照而且因为某种业务原因不能马上删除那这次回收就老实往后推。不要抱着侥幸心理直接冲你会得到一个既浪费感情又浪费时间的失败结果。2.2 虚拟机的电源状态关机是底线挂起不算数回收操作要求在虚拟机处于已关机Powered Off状态下进行。挂起Suspended状态虽然此刻没有磁盘写入但vmdk文件句柄可能仍被锁住而且内存状态文件也会干扰操作。这一点在ESXi上尤其明显。当你试图对一个已开机或已挂起的虚拟机的vmdk执行vmkfstools -K时大概率会收到类似“Device or resource busy”的报错。我后来给自己定了一条铁律无论多急先干净地Power Off再等vCenter里显示状态为“已关机”然后才开始后续命令。2.3 所需工具清点ESXi和Workstation的场景不一样在做任何操作之前把该准备的工具备齐。分两种场景ESXi/vSphere场景需要能够SSH登录ESXi主机或者通过ESXi ShellDCUI环境下的终端执行命令。核心工具是ESXi自带的vmkfstools不需要额外安装任何东西。Workstation场景目标是回收本地磁盘上的vmdk空间可以使用安装目录下的vmware-vdiskmanager.exe或者直接在虚拟机设置界面里用GUI的Compact功能。客户机内部准备Windows客户机建议准备微软Sysinternals工具包里的SDeletesdelete.exe。下载后建议直接放在C盘某个长期保留的目录比如C:\Tools。Linux客户机需要util-linux提供的fstrim命令大部分主流发行版都自带。没有的话用yum install util-linux或apt install util-linux补上即可。同样重要的还有一点准备一个准确的“回收前基线”。进到数据存储记下可用空间数值进到客户机记下分区使用率。否则清理完你根本说不清到底有没有效果。3. Windows虚拟机从删除到回收的完整操作流程3.1 第一步把客户机里的空闲块全部填成“零”Windows客户机里除了正常删文件最核心的动作是用SDelete对空闲空间做清零处理。SDelete的-z参数就是干这个的它会向卷的空闲空间区域写入全零数据把那些残留的旧数据覆盖掉这样宿主层的vmdk才会出现大量“干净的零块”。我的实操命令一般是cd C:\Tools sdelete.exe -z -nobanner C:几个重要细节-z代表对所有空闲空间写零-c代表clean用于安全覆写多次普通容量回收场景用-z就够了不用加-c否则时间会成倍往上翻。-nobanner可以跳过sdelete每次运行时弹出来的版权确认横幅适合在无人值守窗口里跑。如果这台虚拟机有多个分区D盘、E盘需要分别对每个盘符执行一次。盘符记得用管理员权限打开命令行否则会遇到权限不足的报错。页面文件pagefile.sys、休眠文件这些系统保留区域不算“空闲空间”SDelete不会动它们所以不会影响系统启动。这个步骤看起来只是往磁盘里写零实际上非常耗时。我的经验是普通HDD后端存储上一个60GB已用空间的Windows ServerSDelete跑完可能要一两个小时如果客户机本身磁盘繁忙时间更不可控。最好安排在业务低谷期开着任务管理器确认它确实在跑不要中途扛不住就关掉。3.2 第二步安全关机并在ESXi端执行vmkfstools -KSDelete写完零之后从客户机里正常关机。ESXi主机上的vmdk会自动flush缓存。然后通过SSH登录ESXi主机。先跑这条命令确认目标vmdk路径ls -lh /vmfs/volumes/datastore-name/虚拟机文件夹/输出里能看到虚拟机文件夹下有一长串文件我们要找的通常是类似Windows-Server-2019-000001.vmdk这种名字。注意看这个文件的“长度”列就是回收前的物理占用大小。执行回收命令vmkfstools -K /vmfs/volumes/datastore-name/虚拟机文件夹/Windows-Server-2019.vmdk这里有几个版本相关的细节值得说明在ESXi 6.x、7.x等主流版本上-K参数被官方文档描述为对精简置备磁盘做激进的零块回收。它的工作方式是扫描整个vmdk把所有内容全零的块从磁盘映射中摘除从而释放物理空间。如果执行时报“-K”参数不识别检查ESXi版本。很老或很新的版本可能出现参数差异。ESXi 8的某些迭代里VMware还引入了--punchzero这个类似用途的选项实现更细粒度的零块清除。如果你在较新的ESXi 8环境可以先执行vmkfstools --punchzero vmdk路径看看提示再决定用哪个参数。命令执行后没有输出不代表没效果。你可以再ls -lh一次看那个vmdk文件的“长度”是否明显缩小。同时回到vCenter的数据存储界面观察已用空间的变化。注意vmkfstools -K只对“已经包含大量全零块”的vmdk有立竿见影的效果。如果客户机没做清零就直接收缩盘里全是还带着旧数据的块回收效果会非常差。先清零再收缩顺序不能反。3.3 没有SSH环境时的替代办法克隆与vMotion有些环境出于安全策略SSH服务是禁用的ESXi Shell也没开放。这种情况可以走vCenter的功能性方案用vMotion把虚拟机迁移到另一个数据存储并在迁移向导中勾选“紧凑化”相关的磁盘处理选项或者用快照/克隆的方式生成一份“重组”后的磁盘从侧面上让空闲块不被复制到目标盘。这种做法的优点是全程走图形界面或PowerCLI缺点是它本质是“用空间挪腾换时间”对大批量虚拟机来说会延长迁移窗口而且如果源vmdk里满是未清零的旧数据块紧凑化的收益同样有限。所以哪怕走这条路客户机里的清零点零工作也还是要提前做。3.4 Workstation用户的独立简化版流程在VMware Workstation里流程可以简化到三步Windows客户机内删除无用数据同样用sdelete -z C:清零关闭虚拟机打开“虚拟机设置” → 硬盘 → Utilities → Compact如果你更习惯命令行也可以找到VMware Workstation安装目录下的vmware-vdiskmanager.exe执行cd C:\Program Files (x86)\VMware\VMware Workstation\ vmware-vdiskmanager.exe -k D:\VMs\MyWindows\Windows 10.vmdk这里-k就是shrink收缩动作。需要注意一点较新版本的Workstation安装目录里vmware-vdiskmanager.exe不一定随包提供如果找不到直接用GUI的Compact按钮。此外Workstation的虚拟磁盘若被快照占用也会遇到同样的尴尬先删Workstation里的Snapshots再操作。4. Linux虚拟机瘦身从文件系统Trim到宿主端回收4.1 先让文件系统自己说话fstrimLinux客户机和Windows的清理逻辑稍有差别。现代Linux文件系统支持TRIM/Discard机制ext4、xfs、btrfs等都能把已经标记为“空闲”的块地址告诉虚拟磁盘控制器供宿主层做回收。执行命令很简单sudo fstrim -av-a表示对所有挂载点执行-v表示输出详细信息。正常执行后你会看到类似/xxGiB被修剪的提示。这一步就把那些不需要清零操作的块提前做了“物理丢弃”。不过在实际测试中fstrim的回收效果与虚拟SCSI控制器、客户机内核以及ESXi主机版本都有关系。如果你跑完fstrim回到数据存储发现vmdk没怎么缩别急再用下一节的方法手动清零。4.2 对老文件系统或没有Trim支持的场景手动写零fstrim依赖文件系统的TRIM支持。一些老发行版、老内核、ext3文件系统或者关闭了discard功能的SCSI控制器就不吃这一套。这种场景我用的是最笨但最有效的办法创建一个全零大文件塞满剩余磁盘空间然后删掉它。全零文件写入的过程把文件系统里所有空闲块都覆盖成了零删除后这些块变成空闲且内容就是干干净净的零。宿主端再做一次收缩时就能识别并摘除这些零块。命令大概是sudo dd if/dev/zero of/zero.fill bs1M statusprogress等到输出提示No space left on device就说明磁盘已经写满然后删除sudo rm -f /zero.fill sync注意事项也不少千万别写到根分区把系统分区塞得完全没空间dd会在写满后自己失败退出一般不会影响系统但在生产系统上建议提前确认根分区有足够空间容纳这个临时文件。如果你有独立挂载的/var、/home、/data要在每个挂载点各自生成并删除一次/zero.fill目录里临时写这个文件即可。大内存环境下Linux页缓存可能导致dd看起来长时间不结束statusprogress可以实时观察进度。4.3 swap分区怎么处理交换分区是Linux瘦身时容易被忽略的一块。swap分区通常以裸分区或者swap文件的形式存在它的块内容不会是零。一个比较大的swap空间比如8GB会让vmdk回收不彻底。简单的做法是把swap分区减小或者暂时关闭swap清空swap再开启sudo swapoff -a sudo swapon -a关闭后swap里的旧数据并不会自动清零所以如果你希望回收swap多占的那些空间可以在swapoff后对swap分区执行blkdiscard或wipefs清零再重新mkswap。这一步骤在纯测试环境里可以跳过但对生产虚拟机而言能省出几个GB乃至十几个GB。4.4 Linux客户机完成后的宿主端动作不管是用fstrim还是dd写零的方式最终都要回到ESXi主机执行和Windows场景一样的收缩动作vmkfstools -K /vmfs/volumes/datastore-name/LinuxVM/LinuxVM.vmdk之后再对比一下ls -lh里的文件长度。需要注意Linux虚拟机的vmdk常常存在多个磁盘文件系统盘vmdk、数据盘vmdk、swap盘vmdk我需要根据实际分区结构逐个执行而不是只收缩一个就完事。我的习惯是先在客户机里执行df -h和lsblk看清每个虚拟磁盘对应的挂载点再逐一计划清理对象。5. 回收效果验证以及让磁盘不再“只涨不缩”的日常节奏5.1 如何判断回收真的成功执行完vmkfstools -K之后判断成功有三层指标第一层命令退出码是0没有报错。第二层vmdk文件显示的大小明显小于操作前。第三层vCenter里数据存储的“已用空间”数值回落。这里我要特别提醒一点vCenter的数据存储空间统计不是实时更新的可能有几分钟到十几分钟的延迟。我踩过一次坑刚执行完收缩回到vCenter发现容量没变化以为操作失败反复排查了半天才发现只是刷新得太快。建议等10分钟再刷新或者直接SSH到ESXi命令行下用df -h /vmfs/volumes/datastore-name/查看本机视角的空间。5.2 我在实际操作中踩过的坑总结几条反复出现的问题希望你能一眼避开快照没删干净就执行收缩。这在测试机里最典型某次我误以为“上一次快照已经删了”结果虚拟机列表里还有一个状态为“正在删除”的快照合并任务没完成收缩命令发出去后没有任何实际变化。正确做法是先在vCenter快照管理器里确认列表为空再执行收缩。在客户机清零后直接开机然后从宿主机试图执行vmkfstools -K结果报“Device or resource busy”。对我犯过这个低级错误。虚拟机只要处于开机状态无论有没有IOvmdk都被占用必须完整关机。SDelete在白天的繁忙时段跑跟数据库备份作业撞车慢到一个小时才推进10%。后来我把清零操作全部放到凌晨维护窗口并且先用计划任务方式把SDelete放到后台执行。对Linux客户机执行dd if/dev/zero of/zero.fill时没有先检查该挂载点所在文件系统的保留块大小。ext4的root保留空间默认5%所以无论怎么写都不可能把“全部”空闲块变成零。这是Linux文件系统的正常设计不需要强求100%回收。对多个vmdk一次性执行vmkfstools -K时我图省事放在同一个循环里跑结果其中一块盘因为正在被备份任务锁定中途报错退出。现在每块盘我都单独执行执行前先确认该盘是否被其他任务占用。5.3 我现在的例行维护节奏经历了那次存储告警之后我把“精简置备盘回收”从救火操作变成了例行操作。现在的节奏是这样每月第一个周末对重点虚拟机的客户机执行一次安全清理Windows清理临时文件、更新缓存、回收站Linux清包缓存、旧内核、journal日志。清理完成后选择窗口期内做一次清零收缩Windows用SDeleteLinux用fstrim优先、老系统用dd写零兜底。每条回收命令执行前后都把vmdk长度和数据存储容量记录下来攒成一个简单的Excel台账。这样能直观看到每个月回收了多少容量也能对未来容量规划提供依据。新建虚拟机时如果不是必须我会认真评估是否真的要选精简置备。精简置备在存储利用率上的优势很诱人但它需要持续的运维投入来维持“精简”状态如果团队没有月度清理的意识长时间跑下来反而会制造容量黑洞。如果你已经在用VMware虚拟化有一段时间我猜你也遇到过类似的“磁盘越用越大删了也不缩”的困惑。其实这套流程的名词听起来多真实施起来就是个标准三步曲客户机清理、客户机清零、宿主端收缩。只要把快照和电源状态这两条底线守住就算中途踩了坑也能很快定位原因。希望这些记录能帮你把数据存储上那些虚胖的空间都要回来。
返回列表