本文目录导读:

- 架构层面:反向代理与静态化
- 应用层:PHP-FPM 调优与 OpCache
- 数据库层面:减少冲击、使用缓存
- 业务逻辑层面:异步与削峰
- 代码层面:谨慎使用 Session
- 监控与快速扩容
- 🚨 常见误区
- 总结:典型高并发 PHP 系统架构
处理 PHP 项目的高并发请求,核心思路在于 PHP 只负责业务逻辑处理,而将“扛并发”的任务交给更合适的组件(如 Nginx、消息队列、Redis 等)。
PHP 本身是同步阻塞的脚本语言,一个进程一次只能处理一个请求,在高并发下,如果所有请求都直接打到 PHP-FPM 并执行复杂数据库操作,很容易导致资源耗尽、请求超时。
以下是处理 PHP 高并发的 6 大核心策略,从架构到代码层面逐步深入:
架构层面:反向代理与静态化
- 使用 Nginx / OpenResty 做反向代理
- 动静分离:Nginx 直接处理
.css、.js、图片等静态文件,完全不经过 PHP,极大减轻 PHP 负担。 - 负载均衡:Nginx 可以将请求分发到多个 PHP-FPM 服务器(集群)。
- 动静分离:Nginx 直接处理
- 静态化 / 缓存 HTML
- 对于不频繁变动的页面(如首页、新闻详情),使用 Nginx 的
fastcgi_cache或直接生成静态 HTML 文件。 - 用户请求直接由 Nginx 返回静态内容,QPS(每秒查询率)可从几百提升至上万。
- 对于不频繁变动的页面(如首页、新闻详情),使用 Nginx 的
应用层:PHP-FPM 调优与 OpCache
- PHP-FPM 配置优化
pm.max_children:不要设置太大,根据服务器内存计算(2G 内存服务器通常设为 50-100)。pm.max_requests:设置一个值(如 1000),让 PHP 进程在处理一定数量请求后自动重启,防止内存泄漏。
- 开启 OpCache
- PHP 每次请求都要编译源码,开启 OpCache 后,编译后的字节码会缓存到共享内存中。
- 在
php.ini中设置opcache.enable=1,opcache.memory_consumption=128。
数据库层面:减少冲击、使用缓存
这是高并发下最薄弱也最容易出问题的环节。
- 使用 Redis / Memcached 做缓存
- 缓存热点数据:把频繁查询的数据库结果(如用户信息、商品详情)缓存到 Redis。
- 缓存 SQL 查询结果:
$cacheKey = "article:{$id}",先从 Redis 拿,拿不到再查数据库。 - 代码示例:
function getArticle($id) { $cacheKey = 'article:'.$id; $article = Redis::get($cacheKey); if (!$article) { $article = DB::table('articles')->find($id); Redis::setex($cacheKey, 3600, $article); // 缓存1小时 } return $article; }
- 读写分离
使用主从数据库架构,读操作(SELECT)连接从库,写操作(INSERT/UPDATE)连接主库。
- SQL 优化
- 避免
SELECT *,使用索引,避免在WHERE子句中对字段进行函数操作(如WHERE DATE(create_time) = 'today')。
- 避免
业务逻辑层面:异步与削峰
PHP 是同步的,但可以通过中间件将耗时操作异步化。
- 消息队列(RabbitMQ / Redis List + Worker)
- 场景:下单后发邮件、发短信、更新积分,这些操作不需要用户立即得到结果。
- 做法:PHP 只把任务(消息)推送到队列中,立即返回“请求已接收”。
- 后台 Worker(另一个 PHP 脚本或 Go/Java 服务)从队列中消费任务,慢慢处理。
- 效果:原本需要 2 秒完成的请求,现在只需 10 毫秒,QPS 暴涨。
- 秒杀 / 抢购特殊处理
- 预减库存:用户点击“抢购”时,先在 Redis 中扣减库存(
DECR操作),而不是直接写数据库。 - 限流:使用 Redis 的
INCR和EXPIRE实现滑动窗口限流(例如每 IP 每秒 10 次)。
- 预减库存:用户点击“抢购”时,先在 Redis 中扣减库存(
代码层面:谨慎使用 Session
-
避免使用本地 Session 文件
- 默认的 PHP Session 存储方式是文件,且有文件锁,同一个用户并发请求时,后面的请求会等待前面的请求释放 Session 锁,导致阻塞。
- 解决方案:将 Session 存储到 Redis。
// php.ini 配置 session.save_handler = redis session.save_path = "tcp://127.0.0.1:6379"
-
减少文件锁与写操作
- 高并发下,
file_put_contents、flock等文件操作会成为瓶颈,尽量使用内存数据库(Redis/MySQL)代替文件。
- 高并发下,
监控与快速扩容
- 启用实时 PHP 监控
- 使用
php-fpm status page查看活动进程数。 - 使用工具(如 Prometheus + Grafana)监控请求延迟、错误率。
- 使用
- 水平扩容
当单机无法支撑时,增加服务器节点,PHP 应用代码保持无状态(Session 放 Redis,不依赖本地文件),即可轻松通过负载均衡器扩展。
🚨 常见误区
- 盲目升级硬件:单机性能提升有限,架构设计才是关键。
- 对所有请求都加缓存:应该只缓存热点数据,且设置合理的过期时间。
- 忽略 Nginx 层面:PHP 无法处理的高并发,Nginx 可以轻松处理静态文件或返回 503。
典型高并发 PHP 系统架构
用户请求
↓
Nginx / CDN (处理静态文件,负载均衡)
↓
Nginx 转发动态请求到 PHP-FPM (集群)
↓
PHP 业务逻辑 (先查 Redis 缓存)
↓
缓存未命中,查 MySQL 主库 (或从库)
↓
写入操作(数据一致性)→ 直接写库
复杂耗时操作(发邮件/通知)→ 写入 Redis 消息队列
↓ [后台 Worker 异步处理]
一句话总结:
用 Nginx 挡在前面,用 Redis 缓存热点数据,用 消息队列 消化突发流量,最后才让 PHP 和 MySQL 处理核心业务。