默认情况下,PHP 的 session 文件是保存在磁盘文件中。在php.ini配置文件中的配置项如下:
1 | session.save_handler = files |
第一个配置项是指定使用 files(文件形式) 存储session数据。
第二个参数指定保存的路径。N 表示生成多少级目录(不放到一个目录下,分散到多个磁盘目录中去)
所以我们可以知道,session 的数据默认是保存在磁盘文件中。
问题背景
伴随网站业务规模和访问量的逐步发展,原本由单台服务器、单个域名的迷你网站架构已经无法满足发展需要。
此时我们可能会购买更多服务器,并且启用多个二级子域名以频道化的方式,根据业务功能将网站分布部署在独立的服务器上;或通过负载均衡技术(如:DNS轮询、Radware、F5、LVS等)让多个频道共享一组服务器。
OK,头脑中我们已经构思了这样的解决方案,不过进入深入开发后新的技术问题又随之而来:
我们把网站程序分布部署到多台服务器上,而且独立为几个二级域名,由于 session 受实现原理的局限(PHP中session默认以文件的形式保存在本地服务器的硬盘),使得我们的网站用户不得不经常在几个频道间来回输入用户名、密码登入,导致用户体验大打折扣;另外,原本程序可以直接从用户 session 变量中读取的资料(如:昵称、积分、登入时间等),因为无法跨服务器同步更新 session 变量,迫使开发人员必须实时读写数据库,从而增加了数据库的负担。
于是,解决网站跨服务器之间的Session共享方案需求变得迫切起来。
解决方案
基于 Cookie 的 Session 共享
这个方案我们可能比较陌生,但它在大型网站中还是比较普遍被使用。原理是将全站用户的 session 信息加密、序列化后以cookie的方式,统一种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有 cookie 内容的特性,从而实现用户的 cookie 化 session 在多服务间的共享访问。
这个方案的优点无需额外的服务器资源;缺点是由于受 HTTP 协议头信心长度的限制,仅能够存储小部分的用户信息,同时cookie 化的 session 内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带宽资源,因为浏览器会在请求当前域名下任何资源时将本地 cookie 附加在 HTTP 头中传递到服务器。
基于数据库的 Session 共享
采用一台 MySQL 服务器做共享服务器,把所有的 session 的数据保存到 MySQL 服务器上,所有 web服务器都来这台MySQL 服务器来获取 session 数据,并且建议使用内存表Heap,提高session操作的读写效率。这个方案的实用性比较强,相信大家普遍在使用,它的缺点在于 session 的并发读写能力取决于 MySQL 数据库的性能,同时需要自己实现 session 淘汰逻辑,以便定时从数据表中更新、删除 session 记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储 session 还是有些杀鸡用牛刀的架势。
基于 NFS 的 Session 共享
这种方法和使用数据库类似,采用一台公共的 NFS 服务器做共享服务器,所有的 web服务器都把 session 数据写到共享存储介质上,也都要来这台服务器获取 session 数据,通过这样的方式来实现 session 数据的共享。这个方案实现最为简单,无需做过多的二次开发,仅需将共享目录服务器 mount 到各频道服务器的本地 session 目录即可,缺点是 NFS 依托于复杂的安全机制和文件系统,因此并发效率不高,尤其对于 session 这类高并发读写的小文件,会由于共享目录服务器的 io-wait过高,最终拖累前端 web 应用程序的执行效率。
基于缓存数据库的 Session 共享
这种方式可能是目前互联网中比较流行的一种用法。所有 web服务器都把 session 写入到 MemCache/Redis ,也都从MemCache/Redis 来获取。MemCache/Redis 本身就是一个分布式缓存,便于扩展。网络开销较小,几乎没有IO。性能也更好。缺点,受制于 MemCache/Redis 的容量,如果用户量突然增多, cache 由于容量的限制会将一些数据挤出缓存,另外 MemCache/Redis 故障或重启 session 会完全丢失掉。
利用组播实现 Session 共享
通过组播的方式进行集群间的共享,比如 tomcat 目前就具备这样的功能,优点是 web 容器自身支持,配置简单,适合小型网站。缺点是当一台机器的上的 session 变更后会将变更的数据以组播的形式分发给集群间的所有节点,对网络和所有的web 容器都是存在开销。集群越大浪费越严重。不能做到线性的扩展。
Read More:
如何在多台web服务器上共享session? 多服务器之间Session共享 如何解决 cluster 中应用中 session 共享问题?都有那些方案,各有什么优缺点?