前几天去奔波面试,投的都是 PHP开发实习,大一下还是大二上自学PHP,这样算来也自学了两年之久;平时做点小项目或者其他兴趣之类的也都用PHP,CI框架也挺熟练,至少源码读过一大部分(当初为了给一个项目挂马来着)。所以自以为水平不说不错至少找得到一个实习吧。结果呵呵,虽没有惨不忍睹也是相当不尽如人意(在这里就不想吐槽拉勾网了)。
话不多说,Session大家都用,新手呢一般就是session_start()然后开始赋值啊检查啊之类。一位面试官问我,Session和Cookies的区别,这个很简单,了解过web基础的都应该清楚,一个服务器端一个浏览器端嘛,然后就是安全啊服务器压力之类;之后他又问我默认时间,这个我还真没注意过。后来又聊了点别的,总之后来就是被刷掉咯,通知我说我基础不够扎实。
现在在实习的公司比较清闲(我也不想清闲,可就是闲的不行不行),我又深入了解了一下PHP的Session机制,才发现,原来一切都没我们想的那么简单.....
我们都知道Session的存在意义就是为了让服务器端知道无状态的HTTP请求都是谁的,Session存储方式一般都是通过Cookies存储一个PHPSESSID在浏览器;有些情况可能会附加在URL上,我们暂不考虑。
那么第一个问题来了:
Session究竟存储多久?
Session的时间可以通过session.gc_maxlifetime 设置,默认1440秒,24分钟;但是官方手册又说了:
session.gc_maxlifetime 指定过了多少秒之后数据就会被视为“垃圾”并被清除。 垃圾搜集可能会在 session 启动的时候开始( 取决于session.gc_probability 和 session.gc_divisor)。
session.gc_probability 与 session.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。session.gc_probability默认为 1,session.gc_divisor 默认为 100;此概率用 gc_probability/gc_divisor 计算得来。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程。
对的,坑就这在里,24分钟之后也不一定会清理,就算gc启动了也只有1%的概率被清除;也许你会想,把概率调整为100%,但是我没有测试过100%的情况下gc频繁启动遍历各种文件会不会对速度有较大影响。我不禁想起了面试官问这个问题时候狡黠的笑容。
之后又在官网的Note上看到如下:
无论是通过调用函数 session_start() 手动开启会话, 还是使用配置项 session.auto_start 自动开启会话, 对于基于文件的会话数据保存(PHP 的默认行为)而言, 在会话开始的时候都会给会话数据文件加锁, 直到 PHP 脚本执行完毕或者显式调用 session_write_close() 来保存会话数据。 在此期间,其他脚本不可以访问同一个会话数据文件。
也就说对于同一个用户的同时我只能第一个session进行操作,如果我网站大量用到Ajax这样的请求,那么肯定会造成阻塞。官网的Note建议如下:
对于大量使用 Ajax 或者并发请求的网站而言,这可能是一个严重的问题。 解决这个问题最简单的做法是如果修改了会话中的变量, 那么应该尽快调用 session_write_close() 来保存会话数据并释放文件锁。 还有一种选择就是使用支持并发操作的会话保存管理器来替代文件会话保存管理器。
但是我调用session_write_close()是不是又要调用session_start(),是不是很麻烦。
所以,放弃PHP 自带的内置文件会话保存管理器吧。
那用什么存储和管理Session?
我目前在二次开发的CMDB是用的MySql,就麻烦在了不断检查时间然后删除。每一个逻辑背后都要检查一遍,非常 麻烦,我第一个想到的是memcached,毕竟设定时间就好了,应该非常方便。结果看到了这篇文章:
于是就有了:
如何使用 Redis 作为 PHP Session handler
还看到了:鸟哥的如何设置一个严格30分钟过期的Session;要么用第三方的存储方式存储;要么设置Cookie过期时间Session的过期时间,并且自己加个时间戳,每次访问都做判断。
最后,本人博客移到本人个人域名的博客下http://www.ebwill.com