从0搭一个扛得住流量的站:LNMP调优清单
常用教程 2026-11-08 20:43 2

「网站一上量就 502」「后台点一下转三秒」「大促当天数据库把 CPU 吃满」——这些问题八成不是配置不够,而是默认参数没调。一台 4 核 4G 的机器,用默认的 Nginx + PHP-FPM + MySQL 配置,撑两三千 PV/天就开始喘;同样的机器把参数调对,稳定跑两三万 PV/天是正常的。

这篇是一份可以直接照着改的调优清单,按「系统层 → Nginx → PHP-FPM → MySQL → 缓存与静态化 → 观测」六层。每条都给判断依据和参考值,具体数值要按你的机器规格调整,不要照抄。改配置前先备份,逐项改、逐项压测——一次改十个参数,出了问题你分不清是哪个。

第一步:先量一遍基线,别凭感觉调

没有基线就没有优化。上线前记录这五个数字,后面每次改动都对比:

  • ab -n 2000 -c 50 https://你的站点/ 或 wrk -t4 -c50 -d30s https://你的站点/:看 QPS 与 P99 延迟
  • vmstat 1:看 r(运行队列)与 wa(IO 等待)
  • ss -s:看 TIME_WAIT 与 ESTAB 数量
  • top -Hp $(pgrep -f php-fpm | head -1):看 PHP-FPM 子进程 CPU 分布
  • mysqladmin ext -i1 | grep -E "Threads_|Questions|Innodb_buffer":看数据库压力

合格线参考:轻量站的 P99 应低于 500ms,动态接口低于 800ms;r 值持续大于 CPU 核数说明排队;wa 超过 10% 说明磁盘是瓶颈,优先级要先解决 IO 再谈调参。

系统层:五个必须改的默认项

Linux 默认参数是为通用场景设计的,做 Web 服务要改五处:

  • 文件句柄数:ulimit -n 默认 1024,几千并发就不够。/etc/security/limits.conf 里设 nofile 65535,同时改 /etc/systemd/system.conf 的 DefaultLimitNOFILE,否则 systemd 启动的服务不生效。
  • TCP 连接队列:net.core.somaxconn=32768、net.ipv4.tcp_max_syn_backlog=8192,配合 Nginx 的 backlog。
  • TIME_WAIT 复用:net.ipv4.tcp_tw_reuse=1、net.ipv4.tcp_fin_timeout=15。注意不要开 tcp_tw_recycle,新版内核已移除,开了反而出问题。
  • 拥塞控制:net.ipv4.tcp_congestion_control=bbr,跨境链路上比 cubic 提升明显,尤其有丢包时。
  • 文件系统挂载:数据盘加 noatime,减少无意义的元数据写入。

改完 sysctl -p,再 sysctl net.ipv4.tcp_congestion_control 确认生效。

Nginx:让静态和动态各走各的路

Nginx 是入口,它省下来的每一个连接都是 PHP 的救命稻草。四处最值得改:

  • worker 与连接数:worker_processes auto;、worker_connections 10240;、worker_rlimit_nofile 65535;。理论并发上限 = worker 数 × worker_connections,实际按一半估。
  • keepalive:keepalive_timeout 30;、keepalive_requests 1000;。太短会频繁握手,太长会占连接。
  • gzip:gzip on; gzip_min_length 1k; gzip_comp_level 5; gzip_types text/css application/javascript application/json image/svg+xml;。别再压图片,纯浪费 CPU。
  • 静态缓存:带指纹的文件(app.a1b2c3.js)用 expires 1y + immutable;不带指纹的用 expires 7d。

三件事常被忽略但影响很大:

  • client_body_buffer_size 和 client_max_body_size 影响上传,后台上传大图报 413 就是这个。
  • fastcgi_buffers 太小会导致大页面反复写临时文件,看到 an upstream response is buffered to a temporary file 就调大。
  • 开 access_log 的 buffer,或对静态资源关日志。高并发下写日志的 IO 很可观。

PHP-FPM:pm 参数决定能扛多少并发

PHP-FPM 的进程模型是「一个请求一个进程」,所以进程数就是并发上限,内存是硬约束。三种 pm 模式:

模式适用参数建议
static流量稳定、内存充足pm.max_children = 内存 / 单进程内存(约 40–80MB)
dynamic流量有峰谷max_children 同上,start_servers 取 1/4,min_spare 取 1/8,max_spare 取 1/2
ondemand低频访问、内存紧张idle_timeout 10s,代价是冷启动慢

算法很直接:4G 内存的机器,单进程实测 60MB,留 1G 给系统和数据库,剩下的 3G 能开 50 个进程左右。max_children 设成 200 是常见事故——超出内存就会 OOM,然后整台机器一起挂,比 502 更严重。

另外三个参数值得调:

  • request_terminate_timeout = 60:防止某个慢请求把所有进程占死。
  • pm.max_requests = 500:进程处理若干请求后重启,规避内存泄漏。
  • slowlog:一定要开,request_slowlog_timeout = 3,慢请求的调用栈会写进日志,排查性能问题全靠它。

还有一项容易被忽略的:OPcache。生产环境必须开,命中率能到 99%,PHP 执行时间直接砍掉一半。

  • opcache.enable=1、opcache.memory_consumption=256、opcache.max_accelerated_files=20000
  • opcache.validate_timestamps=0:改代码要重启 FPM 才生效,但省掉每次请求的文件检查,收益明显。
  • opcache.interned_strings_buffer=16:字符串多的项目能再省一截内存。

MySQL:三个参数管住 80% 的问题

数据库调优听起来复杂,实际上中小站点把三件事做好就够:

  • 缓冲池:innodb_buffer_pool_size 设为物理内存的 50%–70%。这是最重要的一项,数据量小于缓冲池时,读操作基本不落盘。
  • 日志提交:innodb_flush_log_at_trx_commit=1 最安全;如果业务能容忍极端情况下丢 1 秒数据,用 2 能显著提升写入性能。金融类业务不要动这个。
  • 连接数与超时:max_connections 按「并发进程数 + 余量」设,别设 1000 空占内存;wait_timeout 降到 60–120,避免大量空闲连接。

判断是否要加索引,看慢查询日志,别看感觉:

  • 开 slow_query_log=1、long_query_time=0.5
  • 用 mysqldumpslow -s t -t 20 slow.log 找最耗时的 20 条
  • 对每条做 EXPLAIN,重点看 type(出现 ALL 是全表扫)、rows(扫描行数)、Extra(Using filesort / Using temporary 都要处理)

经验规则:单表超过 500 万行、或某个查询扫描行数超过总行数 10%,就该考虑索引或分表了。索引不是越多越好,每个索引都会拖慢写入。

能静态就静态,能缓存就缓存

调参的天花板是硬件,缓存的天花板是架构。三层缓存按性价比排:

  • 页面缓存:WordPress 用插件把页面存成静态 HTML,Nginx 直接返回,动态请求数能降 90%。这是性价比最高的一步。
  • 对象缓存:Redis 存数据库查询结果与会话,命中率 80% 以上时数据库压力接近减半。
  • CDN 缓存:图片、CSS、JS 全量走 CDN,回源只保留 HTML 与接口。带宽成本也会降。

要注意缓存失效策略:更新文章后要主动清对应缓存,否则用户看到旧内容。全站清缓存是最省事但最伤性能的做法,尽量按 URL 或按分类清。

观测:出问题时能 30 秒定位

调优做完如果没有监控,等于没做。最少要有四个视图:

  • 机器:CPU、内存、磁盘 IO、网络,1 分钟粒度,保留 30 天。
  • Nginx:QPS、5xx 比例、上游响应时间(P50/P95/P99)。5xx 突增是最早的预警。
  • PHP:进程池使用率(active/max_children)、慢请求数。使用率长期 80% 以上说明该扩容了。
  • 数据库:连接数、慢查询数、缓冲池命中率(低于 95% 要加内存)。

再加一条告警规则就够用:5xx 比例连续 3 分钟超过 1%,或者 P95 响应时间超过基线 2 倍,直接推送到手机。别做几十条告警,最后没人看。

常见问题

Q:调完参数反而更慢了,为什么?
最常见的是 max_children 超过内存承受范围,系统开始用 swap。free -h 看 swap 有没有被用,vmstat 1 看 si/so 是否非零。有 swap 交换就说明内存超了,把进程数降回去。

Q:OPcache 开了但没感觉?
看 opcache_get_status() 的命中率。如果命中率低,通常是 max_accelerated_files 太小导致缓存被反复清空,调到 20000 以上再看。

Q:要不要上 Redis?
看数据库是不是瓶颈。如果 Threads_running 经常超过 CPU 核数、慢查询多,上 Redis 收益明显;如果瓶颈在 PHP 进程数不够,上 Redis 帮助有限,先加机器或减进程开销。

Q:4 核 4G 到底能扛多少 PV?
纯动态页面、无缓存,大约 5000–10000 PV/天;开启页面缓存后能到 5 万 PV/天以上;再加 CDN 与对象缓存,跑到十万量级也不奇怪。差别全在架构,不在硬件。

Q:什么时候该加机器而不是继续调参?
两个信号:一是所有参数都到了合理区间,QPS 仍上不去;二是单机故障会导致全站不可用。前者是容量问题,后者是可用性问题,都该往上加一层。

小结

调优的优先级排下来:先量基线 → 改系统参数(句柄、连接队列、BBR)→ Nginx 静态与压缩 → PHP-FPM 进程数与 OPcache → MySQL 缓冲池与慢查询 → 上缓存 → 补监控。前四步都是半小时内能做完的事,收益却最大。

最后提醒一句:所有数值都是起点不是终点。同样的 4 核 4G,跑 WordPress 和跑自研框架的最优参数不一样。改一项、压一次、记一次,三轮之后你会得到一份只属于你这套业务的参数表,那比任何模板都值钱。

相关阅读:买服务器前必须测的 5 个指标、外贸独立站用什么服务器:配置清单、服务器性能自测脚本合集、中小企业上云第一步:三种形态怎么选。

本站深度稿系列:网站速度优化:从3秒到1秒的12个动作、Linux磁盘与IO排查:四类故障的定位路径、Docker上生产:从镜像到升级的16项设置。

Powered by ©智简魔方