必须用Redis集中存储替代PHP默认文件型Session,所有PHP-FPM节点统一配置session.save_handler=redis与session.save_path指向同一Redis实例,确保跨服务器会话一致性,避免登录失效、购物车丢失等问题。
在 Nginx + PHP-FPM 集群环境下,PHP 默认的文件型 Session 无法跨服务器共享,会导致用户登录后刷新跳转、购物车丢失、表单重复提交等问题。根本原因在于:每个 PHP-FPM 实例默认把 Session 存在本地磁盘(如 /var/lib/php/sessions),而 Nginx 轮询分发请求时,同一用户的后续请求可能落到不同服务器上,找不到原来的 Session 数据。
要解决这个问题,核心思路是 把 Session 存储从“本地文件”升级为“集中式存储”,让所有 PHP-FPM 节点读写同一个 Session 源。
Redis 响应快、支持自动过期、天然适合 Session 场景,且与 PHP-FPM 集成简单。
操作步骤如下:
php-redis 扩展# Ubuntu/Debiansudo apt install php-redis# CentOS/RHELsudo yum install php-pecl-redis
/etc/php/8.1/fpm/pool.d/www.conf),添加或修改以下几行:; 关闭默认文件存储php_flag[session.save_handler] = redisphp_flag[session.save_path] = "tcp://192.168.1.50:6379?database=2"; 可选:统一 session cookie 域名,避免子域冲突php_admin_value[session.cookie_domain] = ".yourdomain.com"php_admin_value[session.cookie_httponly] = onphp_admin_value[session.cookie_secure] = off; 生产环境建议设为 on(配合 HTTPS)
systemctl restart php8.1-fpm
效果:所有 PHP-FPM 实例都向同一个 Redis 写入和读取 Session,Nginx 无论把请求分到哪台后端,Session 数据都一致。
Memcached
支持简单键值存取和过期,但不支持持久化、无命名空间隔离,故障恢复能力弱于 Redis,适合轻量级场景。
MySQL / PostgreSQL
可靠性高、便于审计,但 I/O 开销大、延迟高,不推荐用于高频 Session 读写。
NFS 共享 Session 目录(不推荐)
所有 PHP-FPM 挂载同一 NFS 目录作为 session.save_path。存在文件锁竞争、网络延迟、单点故障等严重问题,实际生产极少采用。
Sticky Session(会话粘滞)
在 Nginx 的 upstream 中启用 ip_hash 或 hash $cookie_PHPSESSID,强制同一用户始终打到同一台 PHP-FPM。
缺点明显:破坏负载均衡弹性;节点宕机时 Session 丢失;无法水平扩容新节点承接老用户流量。
session.cookie_path)配置统一,否则浏览器可能发送多个不同 Cookie。php.ini 或 pool 配置中设置超时与重试:php_admin_value[redis.session.lock_retries] = 10php_admin_value[redis.session.lock_wait_min] = 1000php_admin_value[redis.session.lock_wait_max] = 3000
HttpOnly、Secure、SameSite=Lax;定期清理过期 Session(Redis 默认 TTL 自动清理,无需额外脚本)。本质上,这不是 Nginx 的责任,而是 PHP 运行时层的存储策略问题。Nginx 只负责转发请求,真正的 Session 同步由 PHP-FPM 的 session.save_handler 和后端存储共同决定。