一、为什么负载均衡之后还会出现登录反复失效¶
原笔记指出,用户登录请求经过负载均衡之后,可能先落到 web01,下一次又落到 web02。
如果登录状态只保存在单台 Web 本地,那么用户就会遇到:
- 一会儿是已登录
- 一会儿又要求重新登录
这就是典型的会话不一致问题。
原笔记把这个目标总结为:
- 会话保持
- 会话共享
本质上就是要让不同 Web 节点读到同一份登录状态。
二、先分清 Cookie 和 Session 的职责¶
原笔记在进入方案之前,先做了一个概念铺垫。
| 技术点 | 共同点 | 区别 |
|---|---|---|
| Cookie | 都能和用户登录信息有关 | 保存在客户端浏览器 |
| Session | 都能存放用户状态信息 | 保存在服务端 |
可以把它简单理解成:
- Cookie 更像浏览器侧随请求携带的小标识
- Session 更像服务端真正保存状态的地方
很多应用场景里,两者是配合使用的:
- 浏览器带着 Cookie 来
- 服务端根据 Cookie 找到对应的 Session
一旦后端是多节点,Session 就不能再只存在某一台本地机器上。
三、原笔记为什么选择 phpMyAdmin 做会话保持实验¶
原笔记选择的是 phpMyAdmin,而不是 WordPress。
原因也很清楚:
- phpMyAdmin 是典型的 PHP 动态应用
- 登录态明显,容易观察会话问题
- 不需要额外创建复杂业务数据模型
同时这套实验环境仍沿用前面的多主机架构:
web01web02lbdbnfs
这样就可以在真实的负载均衡环境里验证会话共享。
四、先把 phpMyAdmin 的数据库账号准备好¶
原笔记先在数据库主机上创建了一个权限较大的账号:
mysql -uroot -p123456
然后授权:
grant all on *.* to 'phpmyadmin'@'172.16.1.%' identified by '1';
这里的重点不是业务库本身,而是让 phpMyAdmin 这个管理工具能从 Web 节点连接到数据库。
五、两台 Web 上的 phpMyAdmin 要怎么部署¶
原笔记先在 web01 部署 phpMyAdmin,再复制到 web02。
5.1 web01 上的站点配置¶
站点配置如下:
server {
listen 80;
server_name admin.oldboylinux.cn;
root /app/code/admin;
error_log /var/log/nginx/admin-error.log notice;
access_log /var/log/nginx/admin-access.log main;
location / {
index index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_buffering on;
fastcgi_buffers 64 64k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
然后部署代码:
unzip phpMyAdmin-5.2.1-all-languages.zip
mkdir -p /app/code/admin
chown -R www.www /app/code/admin/
mv phpMyAdmin-5.2.1-all-languages/* /app/code/admin/
再复制配置模板并做必要调整:
cp config.sample.inc.php config.inc.php
原笔记还单独给 /var/lib/php/session 做了授权:
chown -R www.www /var/lib/php/session
5.2 web02 上快速复用 web01 成果¶
原笔记在 web02 上先创建好目录:
mkdir -p /app/code/admin/
chown -R www.www /app/code/admin/
再从 web01 复制代码目录和 Nginx 配置:
scp -r admin/ 192.168.1.22:`pwd`
scp admin.oldboylinux.cn.conf 192.168.1.22:`pwd`
之后在 web02 上执行:
nginx -t
systemctl reload nginx
chown -R www.www /var/lib/php/session
这样两台 Web 就有了相同的 phpMyAdmin 站点。
六、LB 层如何把 phpMyAdmin 接入集群¶
原笔记在 LB 上新建 admin.oldboylinux.cn 配置:
upstream admin_pools {
server 192.168.1.20:80;
server 192.168.1.22:80;
}
server {
listen 80;
server_name admin.oldboylinux.cn;
error_log /var/log/nginx/admin-error.log notice;
access_log /var/log/nginx/admin-access.log main;
location / {
proxy_pass http://admin_pools;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
从这一刻开始,登录请求就会被轮流打到不同 Web 节点,也正因此会暴露出会话共享问题。
七、Redis 为什么能解决会话共享¶
原笔记的解决思路是:
- 不把 Session 放在各自 Web 本地
- 而是把 Session 统一存到 Redis
这样无论用户下一次被分发到哪台 Web,只要两台机器都连接同一个 Redis,就能读到同一份会话状态。
7.1 先在 DB 主机上部署 Redis¶
原笔记步骤如下:
yum install -y redis
然后修改 /etc/redis.conf,让它同时监听本地和内网地址:
bind 127.0.0.1 172.16.1.23
最后启动:
systemctl enable --now redis
并检查:
ss -lntup | grep redis
7.2 为什么又新建了一个 php-fpm 端口池¶
原笔记没有直接修改原来的 www 池,而是新建了 /etc/php-fpm.d/session.conf:
[session]
user = www
group = www
listen = 127.0.0.1:9001
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = redis
php_value[session.save_path] = tcp://172.16.1.23:6379
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
这份配置的关键有两个:
- 单独监听
127.0.0.1:9001 - 把
session.save_handler改成redis
也就是说,原笔记是把“需要 Redis 会话”的业务,单独放到新的 PHP-FPM 池里处理。
八、为什么 Nginx 里还要把 fastcgi_pass 改到 9001¶
因为新的会话池监听的是 127.0.0.1:9001,所以两台 Web 上的 phpMyAdmin Nginx 配置都要改成:
fastcgi_pass 127.0.0.1:9001;
原笔记强调,这一步需要在 web01 和 web02 都做,并在修改后执行:
nginx -t
systemctl reload nginx
这样 phpMyAdmin 的 PHP 请求就不再走原来的 9000 池,而是专门走会话存 Redis 的 9001 池。
九、如何确认 Session 已经写进 Redis¶
完成改造后,原笔记的验证方式是:
1、在浏览器访问 http://admin.oldboylinux.cn/
2、正常登录 phpMyAdmin
3、到 Redis 里查看键值
示例:
redis-cli
KEYS *
如果能看到类似:
PHPREDIS_SESSION:fa85f7fa9af6ccbaaad545b300495ebd
就说明 PHP Session 已经不在本地文件,而是统一进了 Redis。
十、小结¶
负载均衡环境下,会话共享的核心不是“尽量让用户总落到同一台机器”,而是“让所有机器都能看到同一份会话数据”。
原笔记通过 phpMyAdmin + Redis + 新建 PHP-FPM 会话池的方式,把这个思路演示得很完整:
- 前端 LB 负责分发请求
- 后端双 Web 负责处理应用
- Redis 负责统一保存 Session
这正是很多 PHP 多节点场景里非常经典的一种会话保持做法。