根本原因是PHP默认文件存储引擎在高并发下因文件锁阻塞导致Session读写失败,且Nginx+PHP-FPM配置不当易引发Session覆盖;改用Redis可彻底解决,因其支持高并发、原子操作与自动过期。

Session在高并发下为什么突然失效
根本原因不是PHP本身,而是默认的文件存储引擎(files)遇到大量并发读写时,会触发文件锁阻塞,导致后续请求读不到完整或最新的$_SESSION数据,甚至返回空数组。更隐蔽的是,Nginx + PHP-FPM 配置不当(比如session.save_handler = files + 多个worker共享同一session.save_path目录但无权限隔离),会让不同用户的Session文件互相覆盖。
用Redis替代files存储Session
这是最直接有效的解法。Redis天生支持高并发读写、原子操作和过期自动清理,且不依赖文件系统锁。
- 确认PHP已启用
redis扩展(非phpredis旧名,检查php -m | grep redis) - 修改
php.ini或运行时设置:session.save_handler = redissession.save_path = "tcp://127.0.0.1:6379?database=2&auth=mypass"(注意&是HTML实体,配置中应为&) - 若使用
phpredis扩展,也可用ini_set('session.save_handler', 'redis')+ini_set('session.save_path', '127.0.0.1:6379')动态设置,但需确保session_start()前完成 - Redis数据库号建议固定(如
database=2),避免和业务缓存混用;密码必须URL编码(如@要写成%40)
Session ID没传过去?检查Cookie与Header
并发场景下,常见表象是session_id()为空或每次刷新都变,实际是客户端根本没收到Set-Cookie响应,或发请求时没带Cookie头。
- 用浏览器DevTools的Network面板查看响应头,确认是否存在
Set-Cookie: PHPSESSID=xxx; path=/; HttpOnly - 检查是否启用了
session.cookie_secure = 1但网站走HTTP(未配HTTPS),导致浏览器拒存Cookie - 前端AJAX请求需显式开启凭证:
fetch('/api/login', { credentials: 'include' })或 jQuery 中设xhrFields: { withCredentials: true } - 反向代理(如Nginx)若配置了
proxy_cookie_path或清除了Set-Cookie头,也会截断Session ID传递
多个子域名共享Session的坑
比如app.example.com和api.example.com需要共用一套Session,光靠session_set_cookie_params(['domain' => '.example.com'])还不够。
立即学习“PHP免费学习笔记(深入)”;
- 必须在
session_start()前调用session_set_cookie_params(),且domain值以点开头(.example.com),否则无效 - Redis作为后端时,不同子域的Session数据天然可共享;但若仍用
files,需确保所有子域指向同一session.save_path目录且有统一读写权限 - 如果用了
session_name('MYSESS')自定义名称,所有子域代码里都得先调用它,否则会各自创建不同名称的Cookie - 注意
SameSite策略:PHP 7.3+ 默认session.cookie_samesite = Lax,跨子域可能被浏览器拦截,临时调试可设为None,但必须同时开启session.cookie_secure = 1
proxy_buffering开启时,可能延迟或吞掉Set-Cookie头。











