单机跑得好好的站,一上负载均衡就出怪事:用户登录着,刷新一下变成未登录;购物车里的东西随机消失。十有八九是Session的问题——Session默认存在本机文件里,用户第一次请求落在A机,Session写在A机,第二次请求被分到B机,B机根本没这个Session,可不就掉线了。
解决思路就一句话:Session别存本机,存到一个所有机器都能访问的地方。小站用NFS共享目录也行,但性能和稳定性都不如直接存Redis,读写快,Redis挂了重启数据也还在(开了持久化的话)。
; php.ini 三行配置换掉文件存储
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=你的密码&database=2"
; 注意:database参数指定用2号库,别和缓存数据混在一起
用宝塔或LNMP一键包的注意,php.ini可能有多个(CLI和FPM各一份),改完要重启的是php-fpm,不是重启机器。改完写个phpinfo()页面看session.save_handler那行是不是已经变成redis,这是第一步验证。
第二步验证跨机器登录:登录之后看Redis里的key,键名是PHPREDIS_SESSION:开头加SessionID。两台机器的php.ini里session.save_path必须一字不差,包括database编号,之前见过有人一台用0号库一台用2号库,查了半天。
# 在Redis里确认Session写入成功
redis-cli -a 你的密码
> select 2
> keys PHPREDIS_SESSION:*
> ttl PHPREDIS_SESSION:abc123xyz
3600 # 剩余生存时间,跟session.gc_maxlifetime对得上
还有个容易被忽略的点:Session存Redis后,gc_maxlifetime到了Redis自动删,但如果你代码里用session_set_cookie_params设了很长的客户端cookie有效期,两边时间要匹配,不然cookie还在Session没了,照样掉线。
这套方案上线后,负载均衡那边的策略随便选,轮询也好ip_hash也好,Session都能对上。唯一的单点就是Redis本身,记得把持久化和主从配上,Redis挂一分钟,所有在线用户都得重新登录,这个代价不小。
数据来源:PHP官方手册
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!



