php-fpm进程数应根据总内存×0.7除以单个进程平均rss来设置,避免502错误和内存不足;mysql慢查多因缺失索引或类型转换;redis缓存击穿需用lua脚本原子操作防竞态;静态资源务必由nginx直送,禁用php中转。

PHP-FPM 进程数设多少才不拖垮服务器
设太多会吃光内存,设太少请求排队等死——关键看 pm.max_children 和实际并发量的匹配关系。
常见错误现象:502 Bad Gateway 频发、slowlog 里大量超时记录、free -h 显示可用内存持续低于 500MB。
- 用
ab -n 1000 -c 200 http://yoursite/模拟压测,观察pm.status_path输出的active processes峰值 -
pm.max_children≈ (总内存 × 0.7) ÷ 单个 PHP 进程平均 RSS(用ps aux --sort=-%mem | head -20看) - 别盲目开
pm = ondemand:冷启动延迟高,突发流量下反而更卡 - 如果用 Docker,记得在容器内限制内存并同步调低
pm.max_children,否则 cgroup 限制生效前进程已 OOM
MySQL 查询慢到怀疑人生?先查是不是没走索引
90% 的“高并发变慢”其实是单条请求耗时飙升,而根源常在没命中索引的 SELECT 或隐式类型转换上。
使用场景:用户登录、订单列表、搜索页加载——只要带 WHERE 或 JOIN 就得盯紧执行计划。
立即学习“PHP免费学习笔记(深入)”;
- 在慢查询日志里抓出
Query_time: 1.234567的语句,用EXPLAIN FORMAT=JSON看key字段是否为NULL - 警惕
WHERE status = '1'对 int 类型字段:字符串和数字比较会触发全表扫描 -
ORDER BY created_at DESC LIMIT 20如果created_at没索引,再小的数据量也扛不住并发 - 不要给大文本字段(如
TEXT)加普通索引,改用前缀索引或全文索引
Redis 缓存击穿让 DB 直接崩?不是加锁就能解决
用 SETNX 加锁再查 DB 是常见思路,但锁失效时间没对齐、客户端崩溃未释放锁,都会导致缓存长期不更新或雪崩。
性能影响:锁竞争本身就会拖慢响应,尤其在 Redis 单线程模型下,一个慢请求卡住整个队列。
- 缓存空值也要设 TTL(比如
SET user:123 "" EX 60),防恶意 ID 穷举击穿 - 用 Lua 脚本封装“查缓存 → 未命中 → 加锁 → 查 DB → 写缓存 → 解锁”全过程,避免网络往返导致的竞态
- 别依赖
DEL key解锁:万一锁过期了,删的是别人刚写的缓存——改用EVAL校验 value 再删 - 如果业务允许轻微陈旧,直接用
GETSET+ 后台异步更新,比强一致性更扛压
静态资源还在 PHP 动态吐?Nginx 别当摆设
图片、JS、CSS 经 PHP 中转一次,就多一次 FPM 进程占用、一次磁盘读、一次 PHP 解析开销——这比数据库慢还冤。
容易踩的坑:本地开发用 php -S 没问题,一上生产 Nginx 就忘了配 try_files,所有请求全打到 index.php。
- Nginx 配置必须含
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { try_files $uri =404; } - PHP 生成的 HTML 里,静态资源链接别写成
/index.php?file=xxx,要直出真实路径 - 启用
sendfile on和tcp_nopush on,减少内核态拷贝次数 - CDN 回源路径若仍指向 PHP 入口,等于白配——确认回源 Host 和路径规则绕过所有 PHP 路由
真正卡点往往不在代码多炫酷,而在某次没走缓存的查询、某个没配对的 Nginx 规则、或者一个被反复重写的锁逻辑。细节不抠,压测数据再好看也没用。











