☰
Windows Server 2016启动慢且SQL服务起不来?磁盘空间不足排查与扩容指南
2026/10/18 11:00:11 网站建设 项目流程

先说结论:如果你在超融合或虚拟化平台上遇到一台 Windows Server 2016 虚拟机,开机特别慢,进系统后 SQL 数据库服务死活起不来,手动启动任何自动启动服务都提示磁盘空间不足,连关个服务器管理器都弹“不具备用户权限和可用空间来保存用户关系”,不用怀疑,九成是虚拟磁盘空间被耗尽,剩下那一成是底层存储满了拖垮了整台机器。这组症状我最近在客户现场连续碰了好几次,每次排查到最后都绕回到“空间”两个字上。与其让你一个一个试,不如把我这次的完整排查过程和解决思路写出来。

1. 故障现象全解析:四个看似无关的报错,指向同一个根因

1.1 为什么启动缓慢、SQL 起不来、服务报磁盘不足会同时爆发

很多人第一次遇到这种组合问题时,第一反应是系统中毒了、或者 SQL Server 配置坏了,实际上这几个症状有非常清晰的因果链。

Windows Server 2016 开机缓慢,最常见的原因是系统盘剩余空间接近零。系统在启动阶段需要初始化页面文件(pagefile.sys)、加载用户配置文件(NTUSER.DAT)、给各项服务创建运行时状态。这些操作都要写盘,磁盘满了以后系统会反复重试、超时、回滚,表现出来就是开机转圈转很久,进了登录界面后又卡半天。

SQL 数据库服务无法启动,本质也是写盘失败。SQL Server 启动时要做三件事:读取 master 数据库、初始化 tempdb 临时库、写入错误日志(ERRORLOG)。tempdb 默认在系统盘的 SQL 安装目录下,错误日志也在 C 盘,C 盘满了以后 tempdb 自动增长失败,错误日志写不进去,服务就会在 SCM(服务控制管理器)里反复启动、反复失败。事件日志里大概率能看到 SQL Server 报“Operating system error 112”,这个错误码就是磁盘空间不足。

任意自动启动服务提示磁盘空间不足,同样是 SCM 层的问题。Windows 服务在启动过程中要加载 DLL、写日志、创建缓存文件,一旦磁盘空间不足,服务启动时就会返回 0x80070070(ERROR_DISK_FULL)。你有印象的话,系统日志里会刷大量 Event ID 7000、7023、7009,后面附带的服务错误码基本都是磁盘满。

关闭服务器管理器提示不具备用户权限和可用空间来保存用户关系,这个报错最容易让人走弯路。说白了,服务器管理器本质上是 MMC 管理控制台,关闭时会把你选的服务器列表、窗口布局、会话状态写进当前用户的 %APPDATA%\Microsoft\Windows\Server Manager 目录。这个目录默认在 C 盘用户文件夹下面,磁盘满了或者用户配置文件权限异常,保存就会失败。它不是权限策略问题,很多时候空间腾出来就自动好了。

1.2 根因只有两类:虚机内系统盘满,或底层数据存储满

我在处理这类故障时,会把排查方向分成两路,省得在虚拟机里瞎折腾。

第一路是虚机内部系统盘空间不足。C 盘可用空间见底,可能是 Windows 更新缓存堆积、SQL 日志膨胀、卷影副本残留、页面文件设置过大,或者是某个服务疯狂写日志。这类问题进入系统后用磁盘管理工具就能确认。

第二路是底层存储空间不足。超融合平台或虚拟化平台如果开启了磁盘精简配置(thin provisioning),虚拟磁盘在虚机里显示 100GB,实际底层可能只占 30GB。但存储池整体如果快满了,虚拟磁盘的每一次写入都会受影响。这时候奇怪的现象就来了:虚机里查 C 盘还有几个 GB 空闲,但所有写入都卡住,服务照样启动失败。这类问题必须到虚拟化平台的管理界面看数据存储水位,不能只在虚拟机里查。

还有一种容易被忽略的情况:虚拟机的快照文件堆积。超融合平台上如果虚拟机残留了多层快照,每个快照都是一个差异盘文件,底层存储占用持续膨胀。虚机里空间检查全是正常的,但底层存储早就被快照占满了。

2. 排查链路:从事件日志到存储层的定位方法

2.1 第一反应不是重装,而是先看事件日志

故障机如果还能正常登录,哪怕慢一点也优先进系统,打开事件查看器(eventvwr.msc),重点看三个日志位置:Windows 日志 -> 系统、Windows 日志 -> 应用程序、应用程序和服务日志 -> Microsoft -> Windows -> 存储诊断。系统日志里如果出现大量 Event ID 33(“磁盘空间不足”)、Event ID 7000/7023(服务启动失败)、Event ID 153(卷影复制相关),基本就能确认方向。

SQL Server 的具体原因要去它的错误日志里找。路径一般在 C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log\ERRORLOG。用文本编辑器打开最后几行,如果看到类似“Could not allocate a new page for database tempdb”或“File 'templog' cannot be expanded to size”这类字眼,那就不是 SQL 配置坏了,而是空间不够。

如果虚拟机已经慢到连登录都困难,我建议通过虚拟化平台的控制台(而不是 RDP)进去,先把系统日志导出,或者直接在平台上把虚拟机的磁盘以只读方式挂载到另一台正常虚拟机上去检查,避免在故障机上反复登录加重 IO 负担。

2.2 磁盘空间体检:虚机内三板斧

登录进系统后,第一件事不是删文件,而是做空间盘点。我固定用三条命令并行看:

Get-PSDrive C Get-ChildItem -Path C:\Windows\Temp,C:\Users,C:\Windows\SoftwareDistribution -Recurse -File -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object -First 20 FullName,@{Name='SizeMB';Expression={[math]::Round($_.Length/1MB,2)}} vssadmin list shadows

第一条命令看 C 盘剩余空间,第二条快速找出大文件,第三条看卷影副本占用。实际处理中,卷影副本常背锅:系统保护(System Protection)默认开启,如果快照点积累得多,C 盘上会出现一堆隐藏的 System Volume Information 文件,占掉几十 GB。这类文件你在资源管理器里看不到,不查 vssadmin 就永远找不到。

还要注意 C:\Windows\MEMORY.DMP 和 Minidump 目录。如果这台机器之前蓝屏过,崩溃转储文件可能占了几个 GB,而且默认设置下每次崩溃都会覆盖写一个新文件,磁盘压力更大。

另外别忘了一个隐蔽大头:页面文件。如果虚拟内存配置成“由系统管理”,C 盘满时系统会尝试扩展 pagefile.sys,结果空间不足又触发新的一轮错误。适当把页面文件改成固定值,或者移到数据盘,能有效缓解 C 盘压力。

2.3 底层存储水位也要查,虚机内空间充足不代表安全

虚拟机内部查完空间之后,无论如何都要去虚拟化平台或者超融合管理界面看一眼数据存储剩余容量。我排障时习惯按以下顺序检查:

  1. 查看所有数据存储的剩余空间百分比,重点盯是否超过 85%;
  2. 查看故障虚拟机的磁盘文件实际占用,对比配置容量,确认是不是精简配置超分过多;
  3. 确认这台虚拟机有没有快照,快照链长度和快照文件大小;
  4. 如果超融合平台可以看到节点存储健康度,再确认是否有硬盘故障重建或数据同步任务在跑。

为什么这么重视底层?因为底层存储满会导致所有虚拟机的 IO 变慢,不只是你正在修的这台。虚机里查空间一切正常,但复制一个 1GB 的文件都卡到超时,那多半是底层问题。之前遇到过一个案例,虚机 C 盘还有 100 多个 GB 空闲,但所有服务启动都报磁盘空间不足,最后发现是其他系统占满了存储池,故障机的虚拟磁盘每次写入都超时,表现从外部看就是“磁盘已满”。这就是我强调要看底层的理由。

3. 应急与根治:清理空间和扩容虚拟磁盘的完整实操

3.1 还能登录时,先做一轮应急清理

只要能进系统,我第一轮先做无风险清理,把阻塞服务的空间挤出来。以下命令按顺序跑,成本低、见效快:

net stop wuauserv rd /s /q C:\Windows\SoftwareDistribution\Download net start wuauserv

这是 Windows Update 缓存清理,通常能释放几个 GB。

vssadmin delete shadows /all /quiet

这个命令删除所有卷影副本,释放量取决于系统保护设置,经常能放出 10-30GB。注意,如果你依赖系统还原点做恢复,执行前要确认是否可接受,生产环境请先和客户确认。

powercfg /h off

关闭休眠文件。服务器本来就不太用休眠,这个文件默认占物理内存的 40%。虚拟机给了 64GB 内存的话,光这一下就能释放 25GB 左右。

del /q /f /s C:\Windows\Temp\*.* rd /s /q C:\Windows\Temp md C:\Windows\Temp del /q /f /s C:\Users\*\AppData\Local\Temp\*.* 2>nul

临时目录清理,属于常规操作。

然后看 C:\Windows\MEMORY.DMP、C:\inetpub\logs\LogFiles、SQL 的错误日志和历史备份文件。很多客户会把数据库备份直接写到 C 盘,一个 bak 文件几十 GB,这种是最容易清理出来的空间。

3.2 空间清得动就清,清不动就扩容虚拟磁盘

如果应急清理后 C 盘可用空间恢复到了 10% 以上,服务大概率能手动启动,这时可以慢慢找根因。如果清理完还是捉襟见肘,或者空间被数据库文件占死动不了,我的建议是直接扩容虚拟磁盘,这是最无损、最彻底的方案。

在虚拟化平台上的操作基本一致:编辑虚拟机设置 -> 硬盘 -> 把容量从原有大小往上加。以某个超融合平台为例,给一台 100GB 系统盘的虚机扩容到 160GB,填写目标大小后保存,磁盘在虚机内部会被识别为一块更大的磁盘,但分区不会自动变大,需要到 Windows 里做扩展卷操作。

Windows 2016 里的扩展步骤:

打开磁盘管理(diskmgmt.msc),右键左下角磁盘 -> 重新扫描磁盘,或者用 diskpart 执行 rescan:

diskpart rescan list disk select disk 0 list volume select volume 2 extend

如果 C 盘分区后面直接跟着未分配空间,extend会一次性把分区扩展到最大。如果 C 盘后面有恢复分区(Windows RE)或者厂商的分区挡着,“扩展卷”会变灰,这时不能暴力删除,要么用支持分区移动的第三方工具,要么先记下来单独处理。

用 PowerShell 也可以完成同样操作:

Resize-Partition -DriveLetter C -Size 160GB

说实话我在生产环境更习惯 PowerShell 的写法,因为可以脚本化,几条命令批量处理多台虚机。执行成功后进资源管理器确认 C 盘容量,再顺手重启一次,让 SCM 和 SQL 服务全部重新初始化。

3.3 底层存储不足时的处置:先腾挪,再扩容

如果问题是底层数据存储满导致的,你在虚机里扩容磁盘只会雪上加霜,因为扩展出来的空间同样要占用底层存储。正确顺序是:先给底层存储腾出空间,再做虚拟磁盘扩容。

常见腾挪手段有三个:

  1. 删除过期的虚拟机快照,特别是快照链已经很深的;
  2. 把占用较大的、业务相对不敏感的虚拟机在线迁移到其他还能用的数据存储;
  3. 把一些冷数据虚拟磁盘从全闪存或高性能池迁移到大容量池。

删除快照这件事要特别小心。快照链越长,删除时后台合并数据量越大,可能持续很长时间,这个时候存储压力不降反升。所以我会选择在业务低峰期操作,并且在超融合管理平台观察存储 IO 是否异常。

如果存储池容量已经达到硬件上限,腾挪空间不够,那就只能对超融合集群进行节点扩容或加磁盘。这个动作需要更多时间,但是常理上不能一边存储满着一边强行扩展虚拟磁盘,那是火上浇油。

4. 服务恢复与专项排错:SQL 和服务器管理器要单独处理

4.1 SQL Server 启动失败的针对性修复

空间恢复后,SQL Server 大多数情况下可以通过常规重启恢复,但有几个专项细节必须检查。

第一,确认 tempdb 的数据文件和日志文件路径是否被设置在 C 盘。如果被设置到 C 盘,哪怕现在空间够了,下次磁盘紧张仍然会复发。我的建议是把 tempdb 以及用户数据库的日志文件都迁移到独立的数据盘,比如 D 盘或 E 盘,数据库和数据盘分开是常规操作。路径迁移方法很简单:SQL Server Management Studio 里实例属性 -> 数据库设置 -> 数据库默认位置,或者在新建数据库时指定路径。如果是已有库的日志迁移,用 ALTER DATABASE 配合 MODIFY FILE 调整逻辑文件名对应的物理路径。

第二,检查 SQL Server 错误日志是否异常膨胀。ERRORLOG 会在 SQL 服务每次重启时生成新文件,旧文件会按序号留存。如果服务反复启动失败,ErrorLog 里会堆积大量启动信息,手动清理老日志可以把安装目录下的占用释放掉。

第三,看一下 SQL 服务账户。如果此前磁盘满的时候,服务账户的 Windows profile 没有成功创建,服务启动可能会报“此服务无法启动指定的服务”或者拒绝访问。这时候要确认服务账户具备“作为服务登录”的权限,必要时在本地安全策略里重新赋权,然后重启 SQL 服务。

启动顺序也有讲究。恢复空间后我一般是:先启动 Event Log 相关服务,再启动 SQL Server 服务,确认启动成功后立即执行:

DBCC CHECKDB(temptdb) WITH NO_INFOMSGS;

如果连不上 SQL,也可以直接在命令行用 sqlservr -f 以最低配置启动,观察启动输出有没有新的空间类错误。

4.1.1 补充:SQL 日志文件增长的“刹车”设置

我见过的生产事故里,SQL 出问题多半不是数据文件不够,而是日志文件无限增长。建议把日志文件自动增长从“按百分比”改成“按 MB 固定增长”,并设置合理的最大上限,比如 maxsize 限制到 100GB,就比“不限制”安全得多。这一步在平时做好,能有效减少 SQL 因为磁盘满罢工的概率。

4.2 服务器管理器报错的完整分析

重启完服务之后,别急着以为所有问题都自动好了。服务器管理器关闭时的报错“不具备用户权限和可用空间来保存用户关系”,有时候是磁盘空间十足的情况下依旧存在,这时候要往用户配置文件方向查。

先用以下命令确认当前用户是不是临时配置文件登录:

whoami /user echo %APPDATA%

如果 %APPDATA% 路径后面跟着 .tmp 字样,比如 C:\Users\Administrator.TMP\AppData\Roaming,说明系统用的是临时配置文件。磁盘满的时候非常容易触发这种情况:用户登录时系统试图加载原配置文件失败,自动创建了一个临时配置文件。此时服务器管理器保存状态失败、桌面设置丢失,都是因为这个会话的配置文件是临时的,关闭时没有真实目录可写。

解决方法是:让管理员注销,确认磁盘空间充足后重新登录。如果重新登录还是临时配置文件,就到“系统属性 -> 高级 -> 用户配置文件”里查看当前配置文件是否异常,删除有问题的配置文件记录后让用户重新登录生成新的。

另外,可以手动清空服务器管理器状态目录,让它重建:

rd /s /q %APPDATA%\Microsoft\Windows\Server Manager

清理后再打开服务器管理器,关闭时就不会再报保存状态失败。

这里说句题外话:这个报错一般不影响服务器管理器的日常使用,但如果反复出现,说明系统在用户配置文件的读写上有隐患,不能完全忽略,还是要按上面的步骤把配置文件和磁盘空间都检查干净。

4.3 恢复后的完整验证清单

故障处理完成后,不能看 SQL 服务起来了就宣布结束。我每次都会跑一遍完整验证,确保没有暗伤。

  1. 查看系统日志,确认没有新的 Event ID 33(磁盘空间不足)和 7000(服务启动失败);
  2. 检查自动启动服务列表,确保之前失败的服务都处于“正在运行”状态;
  3. 手动执行一次数据库备份和事务日志备份,确认写入正常;
  4. 重启虚拟机一次,测量从开机到可登录的时间,确认启动缓慢问题是否解决;
  5. 在虚拟化平台观察底层存储水位,确认是否还在安全线以下。

这些验证做完,才算真正闭环。很多运维朋友只把服务拉起就不管了,结果一周后又出现同样问题,就是因为没有把监控和容量规划补上。

5. 常见问题速查与避坑记录

5.1 问题速查表

症状常见原因优先处理动作
Windows 2016 开机极慢C 盘空间不足、页面文件无法初始化、卷影副本膨胀查 C 盘空间,vssadmin 清卷影,必要时扩容
SQL 服务启动失败,报 Operating system error 112tempdb 或错误日志所在盘满释放空间,迁移 tempdb/日志到独立数据盘
自动启动服务全部报磁盘空间不足系统盘或底层存储已满,SCM 写状态失败应急清理,扩容分区,检查底层存储
关闭服务器管理器提示无权限/无空间保存用户关系用户配置文件损坏或 APPDATA 写入失败检查空间,确认非临时配置文件,重建状态目录
虚机内空间充足但写入卡死底层数据存储满、快照膨胀或存储重建管理平台查看存储水位,删快照、迁移 VM
扩容后 C 盘看不到新空间分区未扩展、MBR 2TB 上限、恢复分区阻挡扩展rescan 后扩展卷,必要时转换 GPT
删了一大堆文件,空间没释放文件被进程占用或属于系统保护/卷影用进程占用工具定位,检查 System Volume Information

5.2 几个容易让人翻车的关键点

系统盘扩容前先做快照,但要评估快照时效。快照本身会占用存储,如果底层空间已经很紧张,创建快照可能直接导致存储满上加满。个人经验是:底层存储低于 15% 空闲时,不要创建新快照,优先清空间。

MBR 磁盘容量上限是 2TB。很多老虚拟机的系统盘用的是 MBR 分区表,磁盘容量改为超过 2TB 后,Windows 内会看到未分配空间出现在 2TB 之后,但 C 盘永远无法扩展。这时候必须先把分区表转换为 GPT,再做扩展分区操作。转换前确认服务器和引导方式兼容,Windows Server 2016 对 GPT 引导支持良好,但操作仍然有风险,务必离线或做好备份。

页面文件位置和大小要一起看。有些管理员图省事把页面文件设为“无”,一些应用会因此报内存不足;有的把页面文件放到 C 盘并且设为“系统管理”,磁盘满时反而加剧问题。我的习惯是页面文件固定在非系统盘,设一个合理的初始值和最大值,避免它成为 C 盘空间的隐形杀手。

SQL 数据库文件和备份不能放在系统盘。这是老生常谈,但实际现场中还是能看到把数据文件放在 C 盘的案例。一旦系统盘空间告急,数据库文件又是无法随便移动的大块头,只能扩容,操作时间全耗在等待磁盘重新扫描上。

5.3 防复发:监控阈值和容量规划

处理完这轮故障后,建议做三层防护:

第一层,在虚拟化平台侧设置数据存储空间告警,把使用率超过 85% 或剩余容量低于 500GB 设为告警条件。很多超融合平台自带容量报表,顺手把每周容量趋势截图发给相关负责人,比事后救火有效得多。

第二层,在 Windows 虚机里安装监控代理或写一个定时脚本,检查 C 盘剩余空间,低于 10% 就发告警。我常用一个简单的 PowerShell 脚本,配合任务计划程序每天凌晨跑一次:

$d = Get-PSDrive C if ($d.Free / $d.Used -lt 0.1) { Write-Host "C drive space below 10%, attention needed" }

第三层,容量规划上,单台 Windows Server 2016 虚机系统盘建议至少 80-100GB,C 盘至少保留 20% 的空闲余量。数据库服务器独立的数据盘单独规划,不要把日志文件和临时库放在同一个盘里。

这三层防护做好,这类“启动缓慢 + SQL 无法启动 + 满屏磁盘不足”的组合故障基本不会在同一台机器上出现第二次。

说到底,这种故障最磨人的不是技术难度,而是现象太散、太吓人。SQL 起不来像数据库坏了,服务器管理器报权限像系统被改了策略,服务全部提示磁盘不足像中了勒索病毒。但只要沉住气看完事件日志、查完空间,把问题收敛到存储这一条线上,解决起来并不复杂。我每次处理完这类案例都会跟身边的人强调一句:遇到可疑故障,先看空间,再查配置,多数 Windows 服务“集体罢工”的问题都能少走一大半弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询