一次 Windows XAMPP Apache CPU 100% 排查实录:三个被否掉的假设

Windows Apache 最终配置清单与性能账:为什么一个字都不用再改

验收三件事全过:Syntax OK、两个 httpd.exe 父子链干净、CPU 与内存回落。下面是这份配置的逐条解读,以及它到底让网站变快了还是变慢了。

一、最终生效的配置

文件 指令 值 作用
httpd.conf 第 535 行 Include "conf/extra/httpd-default.conf" 生效 加载默认参数文件;第 531 行带 # 的那份不生效,别被它骗了
httpd-default.conf Timeout 30 本次真正止血的一条:中止永不返回的活跃请求
httpd-default.conf KeepAlive / MaxKeepAliveRequests / KeepAliveTimeout On / 100 / 3 接近默认值,空闲连接早释放,省线程
httpd.conf 第 559-560 行 AcceptFilter http none
AcceptFilter https none
none 避开防火墙、杀软、云锁类 agent 干扰 AcceptEx 导致的连接挂起
httpd-mpm.conf ThreadsPerChild 64 并发上限,唯一有实质性能影响的改动
httpd-mpm.conf MaxConnectionsPerChild 2000 非零回收,对付 PHP/第三方模块的内存泄漏
httpd-mpm.conf MaxMemFree 2048 对 winnt 生效,与本次故障无关

二、看着像要改、其实都不用动

  • prefork / worker / event / NetWare / OS2 五段:全部被 <IfModule> 跳过,Windows 下是摆设,不用删。
  • MaxConnectionsPerChild 改 800?不改。800 与 2000 是同一味药、只差 2.5 倍剂量;Windows 每次回收都要等 TimeOut 宽限、重建 64 个线程期间不接客,回收越频繁,撞上卡住请求的机会越多。官方对 Windows 的默认建议本来就是 0,非零只用于对付内存泄漏。
  • 开 mod_reqtimeout?不开。LoadModule reqtimeout_module 被注释,RequestReadTimeout 不生效;它管的是客户端慢速发请求头,管不了服务端 PHP 等后端不返回。
  • AcceptFilter 的出处:依据在 Apache 官方 mpm_winnt 文档,不是 XAMPP 官方 FAQ;2.4 起用 AcceptFilter ... none 取代 2.0/2.2 的 Win32DisableAcceptEx,把老指令抄进 2.4 会直接起不来。
  • 指令名:文件里已是新名 MaxConnectionsPerChild,不用换回旧名;真实配置中也没有行尾 # 注释这种语法坑。

三、正确的重启姿势

别用面板 Restart,也别用 httpd -k restart,Windows 服务模式下容易留下孤儿进程。用「停服务 → 确认清空 → 单入口启动」:

$f = 'C:\xampp\apache\conf\httpd.conf'
if (-not (Select-String -Path $f -Pattern '^\s*AcceptFilter')) {
    Add-Content $f "`nAcceptFilter http none`nAcceptFilter https none"
}
& C:\xampp\apache\bin\httpd.exe -t
$s = (Get-Service | Where-Object Name -Match 'apache' | Select-Object -First 1).Name
Stop-Service $s -Force
taskkill /F /IM httpd.exe /T 2>$null
Start-Service $s
Get-CimInstance Win32_Process -Filter "Name='httpd.exe'" | Select-Object ProcessId,ParentProcessId
最后应输出 2 行:7384 ← 560、1680 ← 7384。PID 与上一次不同,说明旧进程确实清干净后全新启动。

四、会不会影响网页访问速度

改动 对速度的影响 什么时候才感觉得到
Timeout 30 正常页面零影响 慢网上传、大文件下载停顿超过 30 秒会被断
KeepAlive 三项 几乎无感,反而省线程 基本感觉不到
AcceptFilter none 理论有细微开销:改用 accept()、不复用 socket 高并发短连接场景;换来不被网络层干扰而挂起
ThreadsPerChild 150 → 64 唯一实质影响 并发上限降低 同一瞬间请求超过 64 个开始排队、TTFB 变长;低流量站点无感
MaxConnectionsPerChild 2000 每 2000 连接一次极短空窗 流量大时偶发;若又碰到卡住的请求会等满宽限,那时才明显
两次重启 一次性中断,已结束 无
整体账:牺牲了峰值吞吐和一点点连接接受效率,换来不再 100% CPU、不再疯狂换页、不再出现攥着 1 GB 退不掉的旧子进程。故障期间 100% CPU + 98% 内存才是真的慢,现在 4% / 49%,实际打开速度大概率比之前还快。对这台内存本就被吃到 98% 的机器,这笔买卖划算。

五、唯一需要回头动参数的情况

高峰期页面明显变慢或冒 503,同时任务管理器里内存还宽松 → 把 ThreadsPerChild 调到 100(别一步跳回 150),走上面那套完整 stop → 确认清空 → start。除此之外一个字别改。

别为了「提速」做这三件蠢事:把 AcceptFilter 删回去、把 MaxConnectionsPerChild 改成 800 或 0、去开 mod_reqtimeout。都跟这次的速度无关。

最后一句:这些全是容量和超时,不是业务代码。那个会让 worker 线程不返回的请求还在,它回来时照样会卡,只是现在有 30 秒兜底,不会再把机器拖到 98% 内存。复发就翻 access.log 找耗时几十秒的 URL。

分享到:

用微信扫一扫,分享给朋友


发布日期:

所属分类: Apache/Nginx 标签:   



下一篇:

没有了,已经是最新文章