写在前面:升级完成不等于结束
把 Windows Server 2012 R2 顺利升到 2019 Datacenter 之后,我以为最难的部分已经过去了。结果第二天发现:WordPress 后台要等半天,前台首页经常转圈五六秒,连远程桌面里的操作都一卡一卡的。
更奇怪的是,升级前这台机器是"秒开"的。硬件没变、网站代码没变、数据库也没动,只是换了系统,怎么就慢成这样?
这篇文章记录完整的排查和优化过程。结论有点出乎意料:拖垮整台机器的不是配置,是 Windows Defender。
一、先量,别猜
遇到"变慢",最忌讳的就是凭感觉一个个改配置。先用两条命令把现象量化。
第一条,看真实响应时间:
curl.exe -k -o NUL -s -w "首字节:%{time_starttransfer}s 总计:%{time_total}s HTTP:%{http_code}\n" https://www.511yj.com/
我这边的结果是首字节 6.4 秒、总计 6.4 秒。正常应该在 1 秒以内。
连续测三次,排除冷启动的干扰:
for /L %i in (1,1,3) do curl.exe -k -o NUL -s -w "第%i次 首字节:%{time_starttransfer}s HTTP:%{http_code}\n" https://www.511yj.com/
三次分别是 6.4s / 3.7s / 6.4s,不是冷启动问题,是真的慢。
第二条,看谁在吃资源:
Get-Process | Sort-Object WS -Descending | Select-Object -First 10 Name,@{n='内存MB';e={[int]($_.WS/1MB)}},CPU | Format-Table -AutoSize
输出里有两个数字很刺眼:httpd 占了 721MB,MsMpEng 的 CPU 累计到了 5389 秒。
二、真凶:Windows Defender
日志里的两条硬证据
翻 Apache 的错误日志:
powershell -c "Get-Content C:\xampp\apache\logs\error.log -Tail 25"
看到了这些:
[mpm_winnt:error] AH00326: Server ran out of threads to serve requests. Consider raising the ThreadsPerChild setting [php:error] PHP Fatal error: Maximum execution time of 120 seconds exceeded in C:\xampp\phpMyAdmin\vendor\composer\ClassLoader.php on line 429
线程被耗尽、PHP 请求跑满 120 秒超时——这不是"配置没调优",是有大量请求被卡住不释放。
为什么 2019 上特别明显
2012 R2 上 Defender 的行为和 2019 不同。升完级之后,所有文件对它来说都是"新面孔",于是每次访问网站,它都要把 WordPress 那几千个 PHP 文件实时扫一遍。
而我的机器是 2 核 4GB,Apache 一个子进程就要几十 MB,再叠加 Defender 持续占用 CPU 做扫描,结果就是整台机器(包括远程桌面)一起卡死。
三、关闭 Defender(三步走)
第 1 步:临时关闭,先验证
别一步到位永久禁用。先"临时关"验证一下是不是它,确认了再永久关;万一判断错,一条命令就能恢复。
在 PowerShell 里执行:
Set-MpPreference -DisableRealtimeMonitoring $true
重启 Apache,再跑一次 curl 计时。我这边从 6.4 秒直接降到 1 秒以内,确认就是它。
如果不是它,用这条恢复:
Set-MpPreference -DisableRealtimeMonitoring $false
第 2 步:永久禁用
两种方法任选,我两个都做了。
方法 A:组策略
Win + R输入gpedit.msc回车- 展开:计算机配置 → 管理模板 → Windows 组件 → Microsoft Defender 防病毒
- 找到「关闭 Microsoft Defender 防病毒」,双击,选已启用
- 同层进入「实时保护」,把「关闭实时保护」也设为已启用
注意:策略列表最右边一列显示"否"是组策略的显示习惯,不代表没生效,别被它绕进去。
方法 B:注册表(组策略打不开时用)
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows Defender" /v DisableAntiSpyware /t REG_DWORD /d 1 /f reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection" /v DisableRealtimeMonitoring /t REG_DWORD /d 1 /f
改完重启服务器生效。
第 3 步:验证
Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled
两项都是 False 就成了。如果报 MI RESULT 16 之类"无法执行外部方法"的错误,反而是好事——说明 Defender 的 WMI 接口已经不响应了,正是它被关掉的表现。
再确认进程没了:
Get-Process MsMpEng -ErrorAction SilentlyContinue
无输出即为彻底停止。
四、精简服务清单
全部用 sc config 改成禁用,不删服务,随时能开回来。执行前先备份当前状态:
sc query type= service state= all > C:\services_before.txt
第一梯队:IO 和 CPU 大户
sc config SysMain start= disabled sc config WSearch start= disabled sc config DiagTrack start= disabled
SysMain:Superfetch 超级预读。服务器上没有"常用软件"要预读,纯吃内存和磁盘WSearch:Windows Search 索引。持续后台索引全盘,吃 IO 和 CPUDiagTrack:遥测(连接用户体验),持续收集上传数据
还有一个隐藏大户 DoSvc(传递优化),它会把你的机器当成更新分发节点,偷偷上传下载吃带宽。但它属于受保护服务,直接改会失败:
sc config DoSvc start= disabled [SC] ChangeServiceConfig 失败 5: 拒绝访问。
这不是操作失误,是微软给它加了特殊 ACL,连管理员都改不了启动类型。绕开办法是走注册表,把下载模式设成"绕过":
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\DeliveryOptimization" /v DODownloadMode /t REG_DWORD /d 100 /f
(100 = 只从官方源下载,不参与对等分发)
第二梯队:服务器用不上的功能
sc config Spooler start= disabled sc config MapsBroker start= disabled sc config RetailDemo start= disabled sc config WerSvc start= disabled sc config TrkWks start= disabled sc config Fax start= disabled sc config PcaSvc start= disabled sc config WpnService start= disabled sc config dmwappushservice start= disabled
其中 Spooler(打印后台处理)在没有打印机的服务器上必关,它还是 PrintNightmare 漏洞的源头。
这几个千万别关
TermService:远程桌面服务,关了你就进不去了Schedule:任务计划程序,证书自动续订靠它RpcSs、Dnscache、Dhcp、EventLog、SENS、LanmanServer
Windows Update 建议设成"手动"而不是禁用——安全补丁还要,但不希望它半夜偷偷下载把 4GB 的机器拖垮:
sc config wuauserv start= demand五、两个系统级调优
电源计划改高性能(2 核机器上感知明显):
powercfg -setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c powercfg -getactivescheme
视觉效果改最佳性能:
SystemPropertiesPerformance.exe
打开后选「调整为最佳性能」→ 确定。服务器不需要动画和阴影。
六、效果与提醒
优化完之后,同一个 curl 测试:首字节 0.63 秒,从 6.4 秒降了一个数量级。WordPress 后台、前台、远程桌面全部恢复正常。
两个必须记住的提醒
- 关掉 Defender 之后,机器就没有任何实时防护了。如果装了云锁之类的第三方 WAF,一定要尽快开起来,并且给
wp-content\uploads\、mysql\data\、/wp-admin/admin-ajax.php加白名单,否则发文章带图片会被 WAF 误拦。 - 先量再调。如果一上来就去改 php.ini、调 MySQL 参数、加内存,可能折腾一整天也找不到 Defender 这个真凶。运维里最值钱的往往不是"加什么",而是"发现谁在偷东西"。