Apache一上量就慢甚至打不开?MPM选型、PHP-FPM解耦与高并发调优实战

张文保 25 分钟阅读 4,768 阅读
本文目录
  1. 为什么Apache平时好好的,一上量就慢、甚至直接打不开?
  2. MPM是什么,prefork、worker、event到底该选哪个?
  3. 为什么要把PHP从Apache里拆出来,交给PHP-FPM?
  4. MaxRequestWorkers到底设多少,才不会一压就OOM?
  5. KeepAlive开还是关,超时到底设多久?
  6. mod_http2和压缩,对性能和SEO到底有多大帮助?
  7. 站点偶发慢请求和502,到底该怎么定位排查?
  8. Apache调优的落地顺序,和最容易踩的5个坑是什么?
  9. 常见问题解答
  10. 我的Apache站平时挺快,为什么一到促销或被爬虫扎堆就变慢甚至打不开?
  11. prefork、worker、event这三种MPM,到底该选哪个?
  12. 为什么要费劲把PHP从Apache里拆出来,交给PHP-FPM?
  13. MaxRequestWorkers到底设多少才合适,我看网上有人设几百几千?
  14. KeepAlive到底该开还是关,超时设多久?
  15. Apache调优和SEO有关系吗,这不是纯运维的事?
  16. 权威参考资料

Apache开箱默认那套配置,平时跑着没事,一旦流量上来、或者爬虫扎堆抓,就开始变慢、卡顿,严重的直接内存爆掉、站点打不开。

问题十有八九不在Apache本身慢,而在三件没调对的事:MPM还在用吃内存的prefork、PHP还塞在Apache进程里没拆出去、MaxRequestWorkers拍脑袋设了个大数结果一压就把内存撑爆引发OOM。保哥这篇不堆参数表,只把这几件真正决定Apache能不能扛住量的事讲清楚:MPM怎么选、为什么要把PHP交给PHP-FPM、并发数到底按什么算、KeepAlive和HTTP/2怎么配,以及站点偶发卡顿、502该怎么定位。

为什么Apache平时好好的,一上量就慢、甚至直接打不开?

保哥帮人排查过不少独立站的卡顿事故,有个模式反复出现:站点平时跑得飞快,老板正得意,结果一到大促放量、或者赶上几家爬虫同时密集抓取,页面就开始越转越慢,再严重一点,整个站直接502、打不开,等流量退潮又自己好了。第二天复盘,服务器配置没动过,CPU也没满,老板百思不得其解。

这种平时没事、一放量就崩的现象,几乎都指向同一个根因:Apache的默认配置压根没为高并发设计过。它出厂那套参数是为通用、保守、能在小内存机器上跑起来准备的,不是为你大促时的并发洪峰准备的。平时访问量低,怎么配都看不出问题;并发一旦冲过它能同时处理的上限,后果立刻显现。

具体怎么崩的?请求多到一定程度,Apache同时能处理的工作单元被占满,多出来的请求只能排队,用户端就是转圈、变慢。如果你用的还是老式的prefork加mod_php组合,问题更狠——每个请求都占着一个内嵌了完整PHP解释器的重进程,动辄吃掉几十上百兆内存,并发一高内存迅速见底,系统被迫频繁换页,再撑不住就触发OOM(内存不足),内核直接把进程杀掉,站点彻底躺平。

所以治这个病,不能靠加内存硬扛,得从配置下手。这篇文章保哥不打算甩一张密密麻麻的参数表让你照抄——照抄最危险,因为每台机器的内存、业务、流量都不一样。我们只把真正决定Apache能不能扛住量的几件事讲透:MPM怎么选、PHP为什么要拆出去、并发数按什么算、连接和压缩怎么配、崩了怎么查。把这几件想明白,参数你自己就会算了。

MPM是什么,prefork、worker、event到底该选哪个?

调Apache性能,绕不开第一个概念叫MPM——多处理模块(Multi-Processing Module)。它决定了Apache用什么方式去同时处理多个请求:用多进程、还是多线程、还是两者混着来。Apache 2.4主要有三种MPM,选错了,后面参数调得再细都是白费。

prefork是最老最稳的一种,多进程、每个进程只跑一个线程。好处是进程之间完全隔离、不存在线程安全问题,所以它能配合非线程安全的老模块——最典型的就是把PHP以mod_php方式内嵌进来。代价是极其吃内存:每个进程都是独立的一大坨,并发上去内存消耗线性暴涨。它现在基本只剩一个存在理由:你被迫用mod_php。

worker是多进程加多线程,每个进程里跑多个线程。同样的并发量下,线程比进程轻得多,内存省下一大截。它的短板在keep-alive长连接——浏览器为了复用连接,会让连接保持一会儿,这段时间线程被这个其实没在干活的闲置连接占着,并发高时白白浪费。

event是在worker基础上的改进,也是Apache 2.4现在的默认推荐。它最大的改进就是专门解决了worker那个痛点:把keep-alive这类闲置连接交给一个单独的监听线程去管,工作线程处理完请求立刻被释放出来接新活,不再被闲置连接占着。

高并发下,event的吞吐和内存利用率都明显更好。Apache官方对event的设计原理有专门的说明Apache HTTP Server官方文档 — Apache MPM event(event多处理模块),想搞清它和worker的差别值得读一遍。

保哥的结论很干脆:现代独立站,闭眼选event,配PHP-FPM跑PHP。除非你有非mod_php不可的历史包袱(比如某个老插件强依赖),否则没有任何理由抱着prefork加mod_php这套又重又慢的老组合不放。下面就说为什么event一定要搭PHP-FPM。

MPM模型内存适合
prefork多进程单线程最高被迫用mod_php等非线程安全模块
worker多进程多线程线程安全环境、无event时的次选
event多进程多线程加独立管连接现代站默认首选,配PHP-FPM

为什么要把PHP从Apache里拆出来,交给PHP-FPM?

很多人装环境图省事,一路默认下来就是prefork加mod_php,PHP直接内嵌在Apache进程里。这套跑小站没问题,但要做性能,第一件事就是把它拆开。mod_php有两个绕不过去的硬伤。

第一个硬伤:它把你锁死在prefork上。mod_php不是线程安全的,所以只要用它,你就只能配prefork MPM,享受不到worker、event的多线程高并发优势。等于为了内嵌PHP的方便,放弃了整个现代并发模型,这笔账怎么算都不划算。

第二个硬伤:它让每个Apache进程都背着一整个PHP。哪怕这个请求只是来取一张图片、一个CSS文件——这种静态请求根本用不到PHP——进程里那坨PHP解释器照样占着内存。站点静态资源越多,这种浪费越夸张。

把PHP拆给PHP-FPM(FastCGI Process Manager)之后,世界就清爽了:Apache用轻量的event MPM专心处理连接和静态文件,遇到动态PHP请求,再通过proxy_fcgi模块转发给独立运行的PHP-FPM进程池去执行。两边解耦、各管各的——Apache的连接数和PHP-FPM的进程数可以分别调,PHP-FPM自己的max_children、内存上限、慢日志、超时都能独立设置,互不打架。

一个最小化的event加proxy_fcgi配置骨架长这样,核心就是把 .php请求交给本地FPM套接字:

<FilesMatch \.php$>
    SetHandler "proxy:unix:/run/php/php-fpm.sock|fcgi://localhost"
</FilesMatch>

# MPM event 核心并发参数(按机器内存调整数值)
<IfModule mpm_event_module>
    StartServers           2
    ServerLimit            8
    ThreadsPerChild        32
    MaxRequestWorkers      256
    MaxConnectionsPerChild 10000
</IfModule>

这套解耦是现在主流LAMP栈的标准姿势,性能和稳定性都比mod_php强一大截。如果你的站还涉及反向代理、HTTPS卸载、WebSocket这些场景,Apache作为前置代理怎么配,Apache反向代理生产实战那篇讲得很全,可以和这套FPM解耦配合着看。

MaxRequestWorkers到底设多少,才不会一压就OOM?

这是整篇里最该算清楚的一个数,也是最多人栽跟头的地方。保哥见过太多站,MaxRequestWorkers照着网上某篇文章抄了个几百上千的大数,平时没事,一放量直接内存爆掉、站点崩溃,运维还以为是被攻击了。

这个值的本质,是Apache允许同时处理的请求数上限。它绝不能拍脑袋设,正确的算法只有一条:拿服务器留给Web服务的可用内存,除以单个工作单元的平均内存占用。

举个实在的例子。一台8G内存的机器,操作系统、数据库、缓存等占掉一半,剩下大约4G留给Apache和PHP-FPM。假设你的PHP进程平均每个吃60M,那么4G除以60M,同时能安全跑的PHP进程也就六七十个。这意味着PHP-FPM的max_children就该卡在六七十这个量级,而Apache的MaxRequestWorkers要和它匹配,别让Apache放进来的并发远超FPM能消化的数量。

设大了的后果特别反直觉,保哥得专门强调:设小了,顶多请求排队、用户觉得慢;设大了,是直接崩。因为并发真上来时,Apache会真的去开那么多工作单元,内存瞬间被榨干,系统疯狂换页(swap),磁盘IO被打满,最后触发OOM把进程杀掉。慢只是难受,崩是致命。所以这个值的原则是宁可保守:先按内存算出理论上限,再往下留点余量,上线后用压测工具实测,确认峰值内存不爆,再小步往上调。

Apache官方的性能调优文档专门强调过这一点——必须控制MaxRequestWorkers,别让服务器开出多到开始换页的子进程,并给出了按内存估算的方法Apache HTTP Server官方文档 — Apache Performance Tuning(性能调优指南)。这页是调并发参数前的必读,保哥建议对着它把自己机器的数算一遍。

和MaxRequestWorkers配套要想的,是PHP-FPM的进程管理模式(pm)。它有三种:static固定开够数量的进程、dynamic按负载在上下限之间动态增减、ondemand有请求才拉起进程。内存紧张的小机器适合ondemand或保守的dynamic,省内存;流量稳定、内存充裕的生产机用static反而更稳,省去频繁拉起进程的开销。频繁创建销毁进程本身也是开销,static把这笔开销在启动时一次性付清,运行期就稳定了。

关键是pm.max_children这个值,逻辑和MaxRequestWorkers完全一样——还是拿可用内存除以单进程内存,两个值要对齐,别一个放得宽、一个卡得死,否则要么Apache放进来的请求FPM接不住、要么FPM开的进程把内存吃爆。保哥的经验是,这两个值得放在一起算、一起调,把它们当成一根绳上的两端,单独调任何一个都容易顾此失彼。

KeepAlive开还是关,超时到底设多久?

KeepAlive是另一个被反复误配的参数。有人听说它占资源就一刀切关掉,有人开了又把超时设成几分钟,两种都不对。先说它是干嘛的:KeepAlive让浏览器用同一条TCP连接连续请求多个资源,省掉为每张图、每个CSS反复握手建连接的开销。

对一个有不少静态资源的正常网站,KeepAlive应该开——它实打实地减少连接开销,对页面加载速度和TTFB都有正面帮助,尤其首屏要拉一堆资源的页面,差别很明显。问题不在开不开,在超时设多久。

KeepAliveTimeout设的是一条连接在没有新请求时还保持多久才关闭。设太长是有代价的:连接在空等期间是占着资源的,一堆用户开着连接却不发请求,这些闲置连接会白白消耗服务器的连接处理能力。所以Apache官方建议这个值保持在低位,默认的5秒就是个合理起点,一般没必要超过几十秒。

这里又一次体现出event MPM的价值。前面说过,event专门用独立线程管这些keep-alive闲置连接,工作线程不会被它们占住。所以在event下开KeepAlive,对并发能力的冲击远小于prefork——prefork下一个闲置keep-alive连接就占着一整个重进程,那才叫浪费。保哥的标准配法是:event MPM下开KeepAlive、超时设在5秒上下,既吃到连接复用的红利,又不让闲置连接拖累并发,两头的好处都拿到。

mod_http2和压缩,对性能和SEO到底有多大帮助?

调完进程模型和并发,再往上是协议层和传输层的优化,主要是HTTP/2和内容压缩。这两块投入不大,但对真实加载速度和SEO的帮助很实在。

先说HTTP/2。相比HTTP/1.1,它最大的好处是多路复用——同一条连接上可以并行传多个资源,不用像HTTP/1.1那样一个个排队,对资源多的页面提速明显,还能减少连接数、降低服务器压力。Apache用mod_http2模块开启,配合HTTPS一起上。

值得注意的是,HTTP/2官方更推荐配event MPM而不是prefork——这又是一个该上event的理由。Apache的HTTP/2指南Apache HTTP Server官方文档 — HTTP/2 guide(mod_http2配置指南)把开启步骤、MPM搭配建议、调试工具都写清楚了,配之前照着走一遍最稳。

再说压缩。用mod_deflate(gzip)或更高效的brotli,把HTML、CSS、JS这类文本资源压缩后再传,体积能砍掉一大半,传输更快、也省带宽。注意压缩主要针对文本,图片、视频这些本身已经是压缩格式的别再压,白费CPU还可能更大。配的时候按MIME类型圈定要压的文本类型即可。

这些优化为什么和SEO挂钩?因为它们直接缩短了TTFB和整体加载时间,而TTFB是LCP的起跑线,LCP又是谷歌明确的Core Web Vitals排名信号。服务器层把响应压下去,前端优化的天花板才能更高。TTFB和多层缓存怎么协同影响Core Web Vitals与抓取,TTFB与多层缓存那篇拆得很透;页面速度作为SEO信号的完整盘点,可以看页面速度SEO实战指南。Apache这层调好,是给这一切打地基。

站点偶发慢请求和502,到底该怎么定位排查?

调优不是一锤子买卖,上线后总会遇到偶发的慢、偶发的502,这时候得会查。盲目改参数是大忌,得先看清楚到底卡在哪。保哥排查Apache性能问题,有一套固定的看图顺序。

第一件事是打开mod_status,看实时的工作单元状态(scoreboard)。它能告诉你此刻有多少工作单元在忙、多少空闲、有没有被占满。如果高峰时几乎全满、还有大量请求在等,那就是并发上限不够,回头去看MaxRequestWorkers和PHP-FPM的max_children是不是卡得太低;如果工作单元没满却还慢,问题多半在后端PHP或数据库,不在Apache。

第二件事是分清502到底是谁的锅。event加PHP-FPM这套架构下,502 Bad Gateway通常意味着Apache把请求转给PHP-FPM,但FPM没接住或没及时返回——可能是FPM的进程池被打满(pm.max_children不够)、可能是某个PHP请求执行太久超了时、也可能是FPM进程崩了。这时候要去看PHP-FPM自己的日志和慢日志(slowlog),而不是埋头调Apache,方向错了越调越乱。

保哥印象很深的一次排查:一个外贸站每天上午十点准时变慢几分钟,老板一口咬定是被同行攻击。打开mod_status一看,那几分钟工作单元根本没占满,CPU也闲着,问题压根不在并发;再翻PHP-FPM的慢日志,发现是一个定时跑的库存同步脚本卡在一条没建索引的数据库大查询上,把FPM进程占住了,新请求只能等。根子在数据库,不在Apache,也不在什么攻击。这件事保哥常拿来提醒人:先看图、先定位,再动手,别一上来就凭直觉怪服务器、怪攻击,那样十有八九越改越偏。

第三件事是区分慢在建连接、还是慢在处理。如果是TTFB高、首字节迟迟不来,多半是后端处理慢或排队;如果是连接阶段慢,可能和KeepAlive、TLS握手、网络有关。把慢拆到具体环节,才能对症下药。保哥的经验是,性能问题九成是被某一个环节卡住的,先用mod_status和各层日志定位到那个环节,再动参数,比凭感觉一通乱调高效得多。

Apache调优的落地顺序,和最容易踩的5个坑是什么?

把上面的点串成一条能照着做的线。保哥调Apache性能的顺序是固定的,每一步都为下一步打底,跳着做容易白忙。

顺序上,先选对模型、再拆PHP、然后算并发、最后上协议优化与监控。第一步把MPM换成event;第二步把PHP从mod_php拆成PHP-FPM,用proxy_fcgi对接;第三步按可用内存除以单进程内存,算准MaxRequestWorkers和FPM的max_children。

第四步配好KeepAlive、HTTP/2、压缩这些传输层优化;第五步打开mod_status和各层日志,建立能随时定位问题的监控。地基(模型和并发)没打牢就去抠协议层的小优化,是本末倒置。

再说5个最容易踩的坑,都是保哥见过最多的翻车点:

坑一:抱着prefork加mod_php不放。这套又重又吃内存、还锁死多线程,是大多数高并发崩溃的根源。能换event加PHP-FPM就赶紧换。

坑二:MaxRequestWorkers照抄网上的大数。不按自己机器内存算,并发一上来就OOM。这个值必须用可用内存除以单进程内存自己算,宁可保守。

坑三:KeepAliveTimeout设太长。一堆闲置连接占着资源,把并发能力悄悄吃掉。开KeepAlive没错,但超时控制在5秒上下。

坑四:把502当成Apache的问题埋头调Apache。event加FPM架构下502多半是PHP-FPM那头的锅,先去看FPM的进程池和慢日志,别搞错方向。

坑五:只调Apache,忘了它只是SEO地基的一层。服务器调快了,还得配合缓存层、CDN、前端优化一起做,TTFB才能真正压到位,单靠Apache一层使不上全力。

把这条顺序和这5个坑当成调优的自查清单。Apache其实是个很能打的服务器,所谓的Apache慢,绝大多数是没调对,而不是它真的不行。把MPM、PHP-FPM、并发数这三件地基打牢,再叠上协议和缓存优化,一台普通配置的机器扛住相当可观的并发完全不成问题。性能这件事,从来不是堆硬件,是把每一层都调到位。配置层之外的索引、伪静态、缓存这些和SEO直接相关的部分,可以接着看Apache .htaccess SEO 6层综合治理,把性能层和SEO层拼成完整的一套。

常见问题解答

我的Apache站平时挺快,为什么一到促销或被爬虫扎堆就变慢甚至打不开?

这是最典型的并发撑爆场景。平时访问量低,Apache默认配置怎么跑都没事;可一旦并发请求数超过它能同时处理的上限,多出来的请求就得排队等待,用户感受到的就是越来越慢;如果你用的还是prefork加mod_php这套老组合,每个请求都占着一个内嵌完整PHP的重进程、吃几十上百兆内存,并发一高内存很快见底,系统开始用交换分区甚至触发OOM,把进程杀掉,站点就彻底打不开了。保哥的判断是,只要你遇到过促销或爬虫高峰时站点变慢崩溃,基本可以断定MPM选型和并发上限没调对。换成event MPM、把PHP拆给PHP-FPM、再把MaxRequestWorkers按真实内存算准,绝大多数这类崩溃都能根治。

prefork、worker、event这三种MPM,到底该选哪个?

先说结论:现代站绝大多数情况选event,配PHP-FPM跑PHP。三者的区别在于怎么用进程和线程处理并发。prefork是多进程、每进程单线程,最稳但最吃内存,唯一还需要它的场景是必须用非线程安全的老模块(典型就是把PHP以mod_php内嵌进Apache)。worker是多进程多线程,内存省得多,但处理keep-alive长连接时线程会被闲置连接占着。event在worker基础上做了优化,专门把keep-alive这类闲置连接交给单独的线程管,让工作线程腾出来处理真正的请求,所以高并发下吞吐最好、内存也省。保哥的默认配方就是event MPM加PHP-FPM,除非你有非用prefork不可的历史包袱,否则没理由抱着老组合不放。

为什么要费劲把PHP从Apache里拆出来,交给PHP-FPM?

因为mod_php这种把PHP解释器内嵌进Apache进程的老做法,有两个硬伤。一是它逼着你只能用prefork MPM,享受不到event的高并发优势——因为mod_php不是线程安全的。二是它让每一个Apache进程都背着一个完整的PHP解释器,哪怕只是在传一张图片这种根本用不到PHP的静态请求,内存照样被它占着,极其浪费。把PHP拆给PHP-FPM之后,Apache用轻量的event MPM专心处理连接和静态文件,动态请求才通过proxy_fcgi转给PHP-FPM的进程池去跑。两边各管各的,PHP-FPM的进程数、内存、超时都能单独调。这套解耦是现代LAMP栈的标准姿势,性能和稳定性都比mod_php强一大截。

MaxRequestWorkers到底设多少才合适,我看网上有人设几百几千?

千万别照抄网上的大数,这个值设错是OOM的头号原因。正确的算法是:用服务器留给Web服务的可用内存,除以单个工作单元的平均内存占用,得出的才是你能安全支撑的并发上限。比如机器有8G、留给系统和数据库等一半、剩4G给Apache和PHP-FPM,而你的PHP进程平均吃60M,那同时能跑的PHP进程也就六七十个,MaxRequestWorkers和PHP-FPM的max_children就得卡在这个量级附近,而不是拍脑袋设几百。设大了的后果很反直觉:并发一上来,Apache真的去开那么多进程,内存瞬间被榨干,系统疯狂换页甚至OOM——设小了顶多请求排队变慢,设大了是直接崩。保哥的铁律是这个值宁可保守,先按内存算出上限再留点余量,压测验证后再微调。

KeepAlive到底该开还是关,超时设多久?

对大多数有不少静态资源(图片、CSS、JS)的网站,KeepAlive应该开。它让浏览器用一条TCP连接连续取多个资源,省掉反复建连接的开销,对页面加载速度和TTFB都有帮助。但KeepAliveTimeout不能设太长——连接在等待复用期间是占着资源的,设太长会让一堆闲置连接白白占用工作线程或进程。Apache官方建议这个值保持在较低的水平,默认5秒就是个合理起点,一般不要超过几十秒。这里又能看出event MPM的好处:它专门用独立线程管这些keep-alive闲置连接,开KeepAlive对event的并发冲击远小于prefork。保哥的配法是event下开KeepAlive、超时设5秒上下,既拿到连接复用的好处,又不让闲置连接拖累并发。

Apache调优和SEO有关系吗,这不是纯运维的事?

关系很直接,只是隔了一层。Apache调得好不好,决定了服务器响应快不快,也就是TTFB(首字节时间)短不短。TTFB虽然本身不是Core Web Vitals的指标,却是LCP(最大内容绘制)的起跑线——服务器响应慢,后面再怎么优化前端,LCP都快不了,而LCP是谷歌明确的排名信号之一。另一头,服务器响应快、稳定不崩,谷歌爬虫单位时间能抓的页面就多,抓取预算的利用率更高,新页面收录更快;反过来,服务器一慢一崩,爬虫会自动降低抓取频率,收录就拖。所以Apache性能调优不是孤立的运维活,它是SEO的地基——地基塌了,上面的内容和外链做得再好也撑不住。保哥常说,技术SEO的第一课就是让服务器先快起来、稳下来。

权威参考资料

FAQPage + Article AI 引用友好版

TL;DR · 60–80 字摘要 · 适用 ChatGPT / Perplexity / Gemini / 文心 引用

Apache开箱默认配置一上并发就慢、甚至内存爆掉打不开。保哥这篇讲怎么调:MPM选event、把PHP拆给PHP-FPM、MaxRequestWorkers按内存算防OOM、KeepAlive与HTTP/2怎么配,以及慢请求和502怎么排查。

关键实体 · Key Entities

  • PHP-FPM
  • Apache
  • 服务器运维
  • 性能调优
  • 高并发

引用元数据 · Citation Metadata

title:       Apache一上量就慢甚至打不开?MPM选型、PHP-FPM解耦与高并发调优实战
author:      张文保 (Paul Zhang) — PatPat SEO 经理
url:         https://zhangwenbao.com/apache-performance-tuning-mpm-event-php-fpm-maxrequestworkers-high-concurrency.html
published:   2026-03-14
modified:    2026-03-14
source-type: First-hand expert commentary
language:    zh-CN
license:     CC BY-NC-SA 4.0 (要求保留原文链接与作者归属)
分享到
标签
版权声明

本文标题:《Apache一上量就慢甚至打不开?MPM选型、PHP-FPM解耦与高并发调优实战》

本文链接:https://zhangwenbao.com/apache-performance-tuning-mpm-event-php-fpm-maxrequestworkers-high-concurrency.html

版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交