1. 先搞清楚卡在哪一环——并发访问慢的定位思路
WAMP 下的 Apache 人一多就卡,这个问题我前后帮人排查过不少回,现象基本都长一个样:本地单机访问飞快,一放到局域网或者正式服务器上,几十个人同时点一下页面,马上就变成“点击之后转圈三秒、五秒”,严重的时候直接超时连不上。很多人第一反应是“服务器配置太低”“带宽不够”,但实际查下来,绝大多数情况都是 Apache 的并发模型和 WAMP 默认参数压根没有为多人访问做过优化,属于典型的“能用,但不扛压”。
先说一个我总结多年的结论:WAMP 这类集成环境,默认配置是为单机开发场景设计的,追求的是“装上就能跑、配置简单”,而不是“高并发下稳定”。所以你在本地开几个标签页觉得飞快,一上真实访问压力就露馅,这是必然的。要解决,必须先定位瓶颈在哪,再针对性调参数,而不是盲目在网上抄一堆配置贴进去,那样反而容易把环境搞挂。这篇文章我会按照实际排查顺序,从定位、原理、配置、验证四个维度把这个事彻底讲透。
1.1 并发变慢的四种表现,对应四个排查方向
“卡”不是一种卡法。同样是“人多了变慢”,背后可能有完全不同的瓶颈。我习惯把并发访问变慢分成四种典型表现,每一种指向不同的排查方向:
| 表现特征 | 最可能的瓶颈 | 优先排查项 |
|---|---|---|
| CPU 持续接近 100%,页面很慢但能打开 | Apache 处理能力不够,或 PHP 执行时间长 | 线程数、PHP 代码效率、MySQL 慢查询 |
| 内存占用飙高,机器开始读硬盘 | Apache 线程/进程堆积过多,每个连接占内存 | ThreadsPerChild、KeepAlive 参数 |
| 图片、JS、CSS 加载特别慢,点一下半天不出图 | 带宽/静态资源反复传输 | 压缩、缓存、静态资源分流 |
| 数据库报“连接数过多”,或 SQL 执行特别慢 | MySQL 连接数满、慢查询、缺索引 | max_connections、慢查询日志、索引优化 |
这里要特别说一句:表面上现象都是“Apache 很卡”,但真正拖后腿的往往是 PHP 脚本或 SQL 查询。Apache 只是服务员,人一多它就跑不过来,可如果每个客人都点了一堆需要现炒的菜(慢查询、无缓存),那再多的服务员也白搭。所以定位阶段一定要把“Apache 并发能力不足”和“业务代码执行太慢”这两件事分开看,否则容易调了半天 Apache,反而没解决实际问题。
1.2 动手前先“看现场”:两条命令加一个状态页
不排查就直接改配置,等于闭着眼睛开车。我每次接到这类问题,第一件事不是打开配置文件,而是先收集现场信息。WAMP 环境里,三样东西能帮你快速定位:Apache 自带的命令行工具、状态页面、错误日志。
首先用命令行确认当前 Apache 的编译信息和加载的模块。在 WAMP 的 Apache bin 目录下打开命令行,依次执行:
httpd -V httpd -M httpd -thttpd -V会显示 Server MPM 是什么,Windows 下一般显示为 WinNT,这决定了你后面改的是线程参数而不是进程参数;httpd -M列出所有已加载模块,方便你检查哪些模块是多余的;httpd -t用来检查配置语法,这个每次改完配置都必须跑一遍,可以有效避免改错导致 Apache 起不来。
然后开启 Apache 的 server-status 页面,实时观察并发连接状态。在 httpd.conf 中找到LoadModule status_module modules/mod_status.so,确认没被注释,再找到或者新增一段配置:
<Location /server-status> SetHandler server-status Require local </Location>Require local表示只能本机访问,如果你需要从局域网另一台机器看,可以改成Require ip 192.168.1.0/24,但注意生产环境不要直接Require all granted,这个页面会暴露当前请求明细,公网开放很危险。改完重启 Apache,浏览器访问http://localhost/server-status,就能看到当前一共有多少工作线程、多少空闲线程、正在处理哪些请求。
还有一条非常重要的指令,那就是看 Apache 的 error.log。并发打满时日志里通常会留下明确的报错字样,比如server reached MaxRequestWorkers,一旦看到这句,基本就可以断定是线程池满了,新请求进不来,表现就是访问极其缓慢甚至拒绝连接。这个日志文件在 WAMP 的 Apache logs 目录下,Windows 机器上路径一般是C:\wamp64\bin\apache\apache2.4.x\logs\error.log。
最后建议用 Apache 自带的 ab 工具做一次简单的压力测试,确认“卡”的量化指标。比如对首页做 1000 个请求、50 个并发:
ab -n 1000 -c 50 http://localhost/输出结果里重点看三个地方:Requests per second(每秒处理请求数)、Failed requests(失败请求数)、Time per request(平均每个请求耗时)。改配置前后各跑一次,对比数据,才能判断你的调整是否真的有效。
2. 默认配置为什么扛不住——并发模型里的三个坑
定位完现场,下一步要理解 WAMP 的 Apache 为什么天生不擅长高并发。很多人以为“卡就是配置低”,加内存换 CPU 就完事了,但不对。Apache 在 Windows 下的并发模型、默认的连接保持策略、以及 WAMP 默认加载的模块,这三个因素叠加在一起,才是真正的根因。
2.1 Windows 下 Apache 是“一连接一线程”,线程池是有上限的
Apache 在 Windows 上默认使用 mpm_winnt 多线程模型,核心逻辑是:每个 TCP 连接到达时,Apache 会从线程池里分配一个线程去处理这个连接,处理期间这个线程就被独占,直到连接关闭才释放。Windows 下 Apache 不会一个进程开多个子进程(这是 Linux 上 prefork 模型的做法),而是单进程 + 多线程,所有线程共享一个进程的内存空间。
WAMP 默认配置里,ThreadsPerChild一般是 150,意思是这个 Apache 进程最多同时开 150 个线程,同时只能服务 150 个连接。一旦并发连接数超过这个值,多余的请求就会在队列里排队等待,表现就是用户点击后页面转圈、迟迟不加载。
这里有个生活化的类比:你开了一家理发店,店里一共 150 把理发椅,每来一个客人就占一把椅子,理完发才空出来。如果同时来了 200 个人,后 50 个只能坐在门口等。问题在于,理发椅坐满之后,哪怕只是等待配钥匙的客人(比如一个长连接、一个慢请求)也占着椅子不走,后面真正想理发的客人就一直进不来。
更要命的是,Windows 上每个 Apache 线程会占用一定内存,实际比例大约每个线程 1~3MB 的虚拟内存,再加上 PHP 脚本执行时的内存开销,如果你把线程数盲目调高到 300 甚至 500,内存直接吃满,机器开始疯狂读硬盘,那比排队更严重,整个系统都可能卡死。
2.2 KeepAlive 是隐藏最深的“椅子占位者”
很多人调了半天线程数,发现还是卡,其实问题出在 KeepAlive 上。KeepAlive 原本是个好机制,它允许同一个 TCP 连接上发送多个 HTTP 请求,减少重复握手开销。Apache 默认是开启的,KeepAliveTimeout默认 5 秒,意思是请求处理完之后,这个连接还会再保持 5 秒,等待同一个客户端继续发请求。
本地单机调试时,KeepAlive 作用不明显,因为只有一个用户在访问。但人一多,情况就完全不同了:假设 100 个用户同时访问,每个人打开你的页面后,浏览器发起 HTML、CSS、JS、图片等多个请求,这些请求都走同一个 KeepAlive 连接;可请求间隙 Apache 要维持这个连接 5 秒不释放。在并发高峰期,150 个线程里有很大一部分其实处于“连接保持但啥事没干”的状态,真正能处理新请求的线程所剩无几。
我见过最夸张的一个案例,对方 Windows 服务器上 150 个线程全被 KeepAlive 空闲连接占满,error.log 里疯狂刷server reached MaxRequestWorkers,但 CPU 和内存都非常低,因为线程都闲着。这种“看似资源充足,实际无线程可用”的假象非常迷惑人,不熟的人很容易往内存、CPU 方向排查,浪费时间。
既然 KeepAlive 有占用线程的缺点,那是不是直接关掉最好?也不一定。关掉 KeepAlive 会让每个 HTTP 请求都重新走一次 TCP 三次握手,短连接开销明显,尤其页面里有大量静态资源时反而更慢。正确做法是:开启 KeepAlive,但把 KeepAliveTimeout 压短、把 MaxKeepAliveRequests 适当调大,让连接只在“确实还需要复用”时保持,而不是无脑占位 5 秒。具体调法在下一章详细说。
2.3 模块冗余和 PHP 执行方式,把问题进一步放大
第三个坑是 WAMP 默认加载了一堆你用不到的模块。Apache 是多模块架构,每次请求进来,各模块都会参与处理,哪怕只是做个检查。默认配置里像mod_autoindex(目录列表)、mod_info、mod_status(如果生产环境不打算用可以先关掉)、mod_negotiation(内容协商)、mod_userdir这类模块,在很多业务场景里根本用不上,但每个请求都会被它们“过一遍”,白白消耗 CPU。
更关键的是 PHP 的执行方式。WAMP 默认通过 Apache 的 mod_php 方式加载 PHP,也就是 PHP 解释器直接嵌在 Apache 进程里。这种方式单机开发很方便,不需要单独启动 PHP 进程,但副作用是:如果一个 PHP 脚本执行得慢(比如死循环、复杂的正则、没加缓存的接口),它会一直占着 Apache 的一个工作线程,别的请求就得等。
再加上 Windows 上很多 WAMP 环境默认没有正确开启 Opcache(PHP 字节码缓存),每个 PHP 文件每次请求都要重新解析编译一遍,性能开销非常大。这一环套一环,Apache 的线程池本身就不宽裕,PHP 执行又慢,连接还被 KeepAlive 占着,三重叠加,人一多当然卡。
3. Apache 配置调整实操——把并发指标调到健康值
理解了原理,接下来就是动手改配置。这一章我给出可以直接抄作业的参数组合,同时会解释每个参数为什么要这么设,避免你只是机械地复制粘贴。所有修改都基于一个原则:让 Apache 在有足够线程处理请求的同时,不让内存和连接占用失控。
3.1 动手前先备份、弄清配置文件结构
改配置之前,务必先备份。WAMP 的 Apache 配置文件一般在C:\wamp64\bin\apache\apache2.4.x\conf\httpd.conf,还有一个重要的附加文件是conf\extra\httpd-mpm.conf,多线程相关参数通常放在那里,但默认可能在 httpd.conf 里被注释掉了 Include。
我建议先执行一次httpd -M确认当前加载的 MPM 模块是mpm_winnt_module,然后在 httpd.conf 里搜索mpm_winnt_module,找到类似这样的段落:
<IfModule mpm_winnt_module> ThreadsPerChild 150 MaxConnectionsPerChild 0 </IfModule>这是线程参数的“主战场”。如果 httpd.conf 里没有这一段,就去httpd-mpm.conf里找,并检查 httpd.conf 尾部是否包含Include conf/extra/httpd-mpm.conf,没有就取消注释。改之前把原文件复制一份,命名为httpd.conf.bak,改完用httpd -t验证语法,确认无误再重启。
3.2 核心参数:线程数、超时时间、KeepAlive 的正确调法
以一台 8GB 内存的 Windows 机器为例,我给出一个经过验证、比较稳的配置组合:
<IfModule mpm_winnt_module> ThreadsPerChild 128 MaxConnectionsPerChild 10000 </IfModule> KeepAlive On MaxKeepAliveRequests 200 KeepAliveTimeout 2 Timeout 30一个个解释。ThreadsPerChild 128意思是 Apache 最多同时开 128 个工作线程。为什么不是默认的 150,也不是更大的 256?因为 Windows 下线程数不是越大越好,每个线程都会占内存,8GB 机器如果跑 PHP 业务,128 是兼顾并发能力和稳定性的平衡点。如果你机器只有 4GB 内存,可以降到 64;如果内存 16GB 以上,日常业务都是简单接口,可以调到 150 甚至 200。
MaxConnectionsPerChild 10000是让每个线程在处理完 10000 个连接后自动退出重建。Windows 上长期运行的内存碎片问题很常见,设置这个值可以让 Apache 定期“换血”,避免内存泄漏累积到把系统拖垮。如果你发现 Apache 的内存占用随运行时间一直往上涨,这个参数就是最大的救星。
KeepAliveTimeout 2是我反复强调的重点。默认 5 秒在并发高的时候太长,改成 2 秒意味着一个请求处理完后,连接最多再为空闲等待 2 秒,超过就释放线程。配合MaxKeepAliveRequests 200,对同一客户端的连续请求依然有效,但不会让线程长时间占着不动。Timeout 30是单个请求的最大处理时间,超过 30 秒直接断开,防止某个慢请求把线程拖死。
不同内存档位的参考配置,我也整理了一张表:
| 物理内存 | ThreadsPerChild 建议 | 适合场景 |
|---|---|---|
| 4GB | 64 | 静态页为主,或简单 PHP 页面 |
| 8GB | 128 | 动态 PHP 业务,访问量中小型 |
| 16GB | 150~200 | 并发较多,业务稍复杂 |
注意,这个表是经验值,不是绝对标准。调整完一定要观察任务管理器里 httpd.exe 的实际内存,如果进程内存持续飙升至接近物理内存上限,就说明线程开多了,需要降下来。线程数不是追求大,而是追求“够用且不爆内存”。
3.3 顺手做的几个小优化:模块裁剪、日志、压缩与缓存
核心参数调完,还有几个成本极低但收益明显的优化项,我每次都会一起做。
第一是裁模块。打开 httpd.conf,搜索LoadModule,把用不到的行注释掉。以常见业务为例,mod_autoindex(如果不提供目录下载服务)、mod_info(信息泄露风险)、mod_negotiation、mod_userdir这几项通常可以关。但注意,mod_deflate、mod_expires、mod_headers、mod_rewrite这些常用功能千万别关,关了反而影响业务。
第二是关闭反向 DNS 解析。搜索HostnameLookups,改成:
HostnameLookups Off默认就是 Off,但如果之前被改成了 On,每个请求都会做一次域名反查,那是非常拖慢速度的操作,务必确认。
第三是开启 gzip 压缩。编辑 httpd.conf 确认LoadModule deflate_module modules/mod_deflate.so已加载,然后加一段:
AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/json image/svg+xmlHTML、CSS、JS 这类文本资源压缩后能省掉大量传输流量,尤其对带宽紧张的网络环境效果显著。图片不要压缩,jpg/png 本身已经压缩过,强行压缩只会增加 CPU 负担。
第四是开启静态资源缓存。加载mod_expires后加一段:
ExpiresActive On ExpiresByType image/jpeg "access plus 7 days" ExpiresByType image/png "access plus 7 days" ExpiresByType text/css "access plus 7 days" ExpiresByType application/javascript "access plus 7 days"这样浏览器访问过一次后,JS/CSS/图片就会在本地缓存,下次访问不再向服务器发起请求,能明显减轻 Apache 的压力。如果你对缓存更新有顾虑,可以在文件名上加版本号来强制刷新。
最后提一下访问日志。Windows 环境下的磁盘 I/O 本身不如 Linux,如果每来一个请求都往 access.log 里写一行,高并发时磁盘写入会成为瓶颈。如果业务不需要详细访问日志做分析,可以注释掉CustomLog那行,或者保留但改写到非系统盘。这个优化在并发提升后的效果非常明显,我实测过把日志关掉后,同样压力下响应时间能缩短将近四分之一。
4. 配套优化:PHP、MySQL 与静态资源一个都不能少
Apache 配置调完之后,如果还卡,那问题大概率不在 Apache,而在它背后跑的 PHP 和 MySQL。这一章讲的是和 Apache 优化配套的“组合拳”,也是我反复强调的“别让 Apache 单独背锅”的关键环节。
4.1 PHP 层:开启 Opcache 是最快最省的提速方式
WAMP 的 PHP 配置文件是C:\wamp64\bin\php\php版本\php.ini。很多 WAMP 环境虽然带了 Opcache 扩展,但默认并没有正确启用,导致每次请求都要重新编译 PHP 脚本,CPU 白白烧掉一大半。
检查并开启的方式很简单,用文本编辑器打开 php.ini,搜索opcache,确保以下几个配置生效:
[opcache] zend_extension=php_opcache.dll opcache.enable=1 opcache.memory_consumption=128 opcache.max_accelerated_files=4000 opcache.revalidate_freq=60opcache.memory_consumption=128表示给字节码缓存分配 128MB 内存,一般项目够用;opcache.revalidate_freq=60是每 60 秒检查一次 PHP 文件是否变动,开发环境可以改成 0,但生产环境建议设成 60 以上,能减少文件检查开销。
开启 Opcache 的效果我可以直接告诉你:同样的 PHP 页面,开启前后压测数据经常是翻倍的差距。原理很简单,PHP 是解释型语言,每次请求都要把源码读出来、解析、编译成字节码再执行,Opcache 就是把编译好的字节码缓存起来,下次直接执行,省掉了前面一大段重复劳动。类比就是你每天上班不用重新学习怎么做表格,直接打开模板就能干活。
除了 Opcache,PHP 代码层面的习惯也很重要。最常见的两个坑:一是在循环里反复查数据库,比如查一个列表,每条记录又执行一次 SELECT,几百条数据就是几百次数据库请求,直接把 MySQL 连接数打满;二是没加任何缓存地执行复杂计算或正则匹配,一个请求耗掉好几秒。这类问题不是调 Apache 能解决的,必须回到代码层面优化,比如把循环里的查询改成一次 JOIN 查出来。
4.2 MySQL 层:连接数、慢查询、索引三板斧
人一多就卡,另一个高频瓶颈是 MySQL。WAMP 自带的 MySQL 配置文件在C:\wamp64\bin\mysql\mysql版本\my.ini,但默认的max_connections并不高,一旦 Apache 的并发线程都来查数据库,连接数瞬间就被占满。
先执行一条 SQL 看看当前数据库的压力情况:
SHOW STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';如果Threads_connected经常接近max_connections,说明连接数不够,可以在 my.ini 的[mysqld]段调大:
max_connections=256注意不要盲目调得太大,每个 MySQL 连接都会占用内存,256 在大多数中小型项目里已经足够。调完后重启 MySQL 服务。
然后是慢查询日志。很多人以为数据库卡是机器慢,其实八成是 SQL 没索引。在 my.ini 里开启慢查询日志:
slow_query_log=ON slow_query_log_file=C:/wamp64/logs/mysql-slow.log long_query_time=2执行超过 2 秒的 SQL 都会被记录下来。过一段时间打开这个日志,你会发现,活跃的慢查询往往集中在几个表,原因基本都是一个:WHERE 条件里的字段没建索引。解决方式很简单:
EXPLAIN SELECT * FROM orders WHERE order_no = 'xxx'; ALTER TABLE orders ADD INDEX idx_order_no (order_no);EXPLAIN会告诉你这个查询走了全表扫描还是索引查找,如果 type 列是ALL,就说明全表扫了,数据量大时自然慢。加个索引通常能把查询时间从几百毫秒降到几毫秒,效果立竿见影。这个三板斧——连接数、慢查询日志、索引优化——能解决绝大多数 MySQL 层面的并发卡顿。
4.3 静态资源与整体架构的“疏导”思路
最后是静态资源。Apache 本身处理静态文件并不差,但架不住页面里图片一堆、每次刷新都重新下载。除了前面提到的 Expires 缓存,还有几招值得做。
如果项目允许,把图片、CSS、JS 放到独立域名或者子目录下,通过 Nginx、CDN 或对象存储来分发,本机 Apache 只处理动态请求。这样 Apache 的线程池几乎全部留给 PHP 接口,并发能力直接翻倍。即便是局域网环境,也可以用一台专门的静态资源服务器来分流。
如果暂时不想引入新的服务器,至少要做到:图片使用现代格式(WebP)、体积压缩,页面减少不必要的请求数量。一个页面 60 个请求和 20 个请求,对并发的影响差异巨大,相当于 60 个人同时挤门 和 20 个人同时挤门的区别。
这一章的核心思路是:Apache 优化只是“把接待能力提升”,但要真正快起来,得让每个请求执行时间变短——PHP 缓存缩短计算时间,MySQL 索引缩短查询时间,静态缓存缩短传输时间。三管齐下,人多了才不卡。
5. 改完怎么验证——压测、日志与常见问题实录
改配置不是终点,验证才算是真正做完。很多人改完觉得“好像快了”,但没有数据支撑,也不知道是不是某个参数起的作用。这一章教你如何用最简单的方式验证效果,同时把我遇到过的典型问题整理成速查表。
5.1 用 ab 做一次“前后对比压测”
Apache 自带的 ab 工具是验证并发性能最方便的工具,不用额外安装。改配置前,我已经让你跑过一次基线数据;改完配置、重启 Apache 之后,再跑一次完全相同的命令:
ab -n 1000 -c 50 http://localhost/前后对比时注意保持条件一致:同一个 URL、同一个并发数、同一台机器、尽量在同一时段。如果改完配置后Requests per second提升明显、Failed requests归零、Time per request下降,说明调整有效。如果数据反而变差,回头检查是不是某个参数设得太激进,比如线程数开太高导致频繁上下文切换,或者 KeepAliveTimeout 设太长占用了线程。
我做过一次比较典型的优化:一台 8GB 内存的 Windows 服务器,WAMP 跑一个中小型 PHP 项目,50 并发压首页,优化前 Requests per second 只有 38,响应时间平均 1.3 秒;优化后同样压力下 Requests per second 到了 115,平均响应时间降到 0.43 秒。差距在哪里?主要就是 OPCache 开启 + KeepAliveTimeout 从 5 降到 2 + 模块裁剪。
如果 ab 的并发模拟还不够细腻,可以装 Apache JMeter,创建一个线程组,模拟几百个并发用户跑一段时间,看聚合报告里的吞吐量、响应时间、错误率。JMeter 配置稍微复杂一些,但对“模拟真实用户操作”的场景更准确。
5.2 从日志和状态页抓“铁证”
验证之后,日常运行中还要持续监控。Apache 的 error.log 和 server-status 页面是判断并发是否健康最直接的窗口。
打开http://localhost/server-status,重点看几个数字:BusyWorkers(忙碌线程数)、IdleWorkers(空闲线程数)。如果BusyWorkers长期接近你配置的ThreadsPerChild数值,说明服务器压力很大,已经接近瓶颈;如果大部分时间IdleWorkers比较多,说明还有余量。结合 error.log 里有没有server reached MaxRequestWorkers的报错,能准确判断是不是线程池不够用。
另外,access.log 里的状态码也能看出端倪。如果大量请求返回 503,说明 Apache 在拒绝请求,通常就是线程池满了;如果 500 多,那就是 PHP 代码报错,需要看 PHP 错误日志。这两类问题处理方向完全不同,别混为一谈。
5.3 常见问题速查表
最后把我在处理 WAMP 并发卡顿过程中遇到的高频问题整理成一张速查表,方便你按图索骥:
| 现象 | 可能原因 | 排查与解决 |
|---|---|---|
| 改完 httpd.conf 后 Apache 起不来 | 语法错误或端口被占用 | 执行httpd -t检查语法;`netstat -ano |
| 打开 server-status 页面 403 | 访问控制过严 | 将Require local改为Require ip 192.168.1.0/24,仅限内网访问 |
| 浏览器访问出现 Apache Server at port 443 提示 | 地址栏自动走了 https,而 Apache 没配 SSL | 改用http://访问;如需 https 再配置证书 |
| 访问 phpMyAdmin 打不开 | MySQL 没启动,或 80 端口被其他程序占用 | 确认 wampmanager 菜单里 MySQL 服务已启动;检查端口冲突 |
| 调完参数后压测反而更慢 | 线程数开太高/KeepAliveTimeout 不合理 | 适当降低 ThreadsPerChild,KeepAliveTimeout 压到 2~3 秒 |
| 内存持续上涨,过几天 Apache 变卡 | 内存泄漏或碎片累积 | 设置MaxConnectionsPerChild为 10000,定期重建线程 |
这里有一个极易忽略的坑:修改 php.ini 或 my.ini 之后,很多人只重启了 Apache,没有重启对应的 PHP 或 MySQL 服务。WAMP 的图形控制面板里,左键点托盘图标,可以分别重启 Apache、MySQL、PHP 服务,改哪个配置就重启哪个服务,这个细节卡住过不少人。
5.4 改完配置一定要“验证重启生效”
再补充一个实操细节:WAMP 里有 “重启所有服务” 的按钮,但有时候因为它自带的缓存机制,改完配置后不会立刻生效。稳妥的做法是手动在命令行里重启:
net stop wampapache64 net start wampapache64实际服务名可能因 WAMP 版本不同略有差异,可以在命令行执行net start | findstr -i "wamp"查看。重启后用httpd -V或直接访问一个页面确认配置已生效,再开始压测。否则你改了配置,但服务跑的还是旧参数,压测结果自然没有参考价值。
6. 关于这套配置,我踩过的坑和后续建议
6.1 踩了几个版本才明白的取舍
这个方案我帮不同团队落地过很多次,也踩过不少坑。最大的一个教训是:不要一次性把所有参数都改掉。每改一个参数,跑一次压测,确认没有副作用,再改下一个。否则一旦性能变差,你根本不知道是哪个参数引起的,回滚时也无从下手。我自己的操作顺序是:先开 OPCache(收益最大、风险最低),再调 KeepAliveTimeout 和 MaxKeepAliveRequests,最后根据压测结果微调 ThreadsPerChild。
另一个深刻体会是,Windows 下的 Apache 并发能力上限就在那里。线程模型 + mod_php 的架构决定了它适合中小规模访问,硬要往 500、1000 并发调,内存会先撑不住。一个 8GB 内存的 Windows 机器,Apache + PHP + MySQL 三个服务全跑,稳定支撑 100 左右的并发连接已经是比较理想的成绩。如果你的业务确实需要更高并发,那就不要想着靠调参数硬撑,换架构才是正道。
6.2 如果项目流量再往上涨,怎么过渡
当并发压力持续增大,我的建议是逐步分离服务。最简单的一步是把数据库单独放到一台机器,让 Apache 所在的服务器专注处理 Web 请求,MySQL 不再抢占内存。再进一步,把静态资源迁移到 CDN 或对象存储,让 Apache 只处理动态接口。到了这一步,Apache 的并发压力已经降下来了。
如果流量还是不够扛,那就需要考虑把 WAMP 替换成更专业的组合,比如 Linux + Nginx 或 Apache event MPM + PHP-FPM + Redis。PHP-FPM 相比 mod_php,最大的优势是 PHP 进程和 Web 进程分离,单个慢脚本不会拖垮所有请求,并发能力和稳定性都上一个台阶。但这是后话,在项目真正成长到那个阶段之前,把 WAMP 这套环境按照本文的方法调优到位,应对中小型项目的日常访问是绰绰有余的。
最后再分享一个小技巧:每次调整完配置,记得把改动记录写在一个文本文件里,标清楚日期、改了哪项、压测数据是什么。别嫌麻烦,这不仅是你的知识沉淀,下次再遇到卡顿问题时,这份记录能让你在五分钟内判断出“上次优化已经做到什么程度、这次瓶颈可能出在哪”。我在实际操作中的体会是,绝大多数“诡异的卡顿”,最后翻出来都是某次改动没记录、后来忘了才导致的。所以,这次把每一步都记下来,比调好参数本身更有价值。