Session的原理、存储与共享
一、Session的原理
原理很简单,假设你访问网页时就像逛澡堂,第一次进去你是没有钥匙的,这个时候你交了钱服务台就分配一把钥匙给你,你走到哪里都要带上,因为这是你身份的唯一标识,接下来你用这把钥匙可以去打开一个专有的储物柜存储你的衣物,游完泳,你再用钥匙去打开柜子拿出衣物,最后离开游泳池时,把钥匙归还,你的这次游泳的过程就是一次Session,或者叫做会话,在这个例子中,钥匙就是Session的Key,而储物柜可以理解为存储用户会话信息的介质。
Cookie是将数据保存到客户端计算机之中,Session则是将数据保存到服务器系统之下,用户可以阻止Cookie的使用,但是却无法停止Session的使用。首先,在客户端仅需要保存由服务器为用户创建的一个Session标识符,称之为Session ID,而在服务器端(文件/数据库/MemCache中)保存Session变量的值。Session ID会保存在客户端的Cookie里,如果用户阻止Cookie的使用,则可以将Session ID保存在用户浏览器地址栏的URL中,当用户请求Web服务器时,就会把Session ID发送给服务器,再通过Session ID提取保存在服务器中的Session变量。当用户向Web服务器发送请求的时候,服务器首先会检查这个客户端的请求里是否包含了Session ID,如果有,则说明之前创建过,直接检索出来使用即可,如果没有,则创建一个Session,并生成一个与此相关联的Session ID,在本次响应中被传给客户端保存。
二、Session的存储
在PHP中,Session是保存在服务器上的,是默认以文件的形式存储的,例如:在Windows下wamp中查看到wamp安装目录下有tmp目录,其中session数据保存的文件以”sess_”作为前缀命名。在CentOS中nginx+php-fpm环境中,配置session的保存路径(在php.ini中配置session.save_path的值,注意这个路径需要Web服务器进程所属用户有权操作-读写操作)后,保存的session文件同样以“sess_”作为前缀命名。
但是,session也可以以内存的方式来存储,比如存放到redis、memcache中,这样相对于从文件中获取来讲,更加便捷、迅速,这里需要说明的是,redis会定期将内存中的数据写到硬盘中,所以,你在redis中的.rdb文件重也可以查看到对应的session信息!
三、Session的共享
首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。
1. 基于NFS的Session共享
NFS是Net FileSystem的简称,最早由Sun公司为解决Unix网络主机间的目录共享而研发。
这个方案实现最为简单,无需做过多的二次开发,仅需将共享目录服务器mount到各频道服务器的本地session目录即可,缺点是NFS依托于复杂的安全机制和文件系统,因此并发效率不高,尤其对于session这类高并发读写的小文件,会由于共享目录服务器的io-wait过高,最终拖累前端WEB应用程序的执行效率。
2. 基于数据库的Session共享
首选当然是大名鼎鼎的MySQL数据库,并且建议使用内存表Heap,提高session操作的读写效率。这个方案的实用性比较强,相信大家普遍在使用,它的缺点在于session的并发读写能力取决于mysql数据库的性能,同时需要自己实现session淘汰逻辑,以便定时从数据表中更新、删除 session记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储Session还是有些杀鸡用牛刀的架势。
3. 基于Cookie的Session共享
这个方案我们可能比较陌生,但它在大型网站中还是比较普遍被使用。原理是将全站用户的Session信息加密、序列化后以Cookie的方式,统一种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现用户的Cookie化Session 在多服务间的共享访问。
这个方案的优点无需额外的服务器资源;缺点是由于受http协议头信息长度的限制,仅能够存储小部分的用户信息,同时Cookie化的 Session内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带宽资源,因为浏览器会在请求当前域名下任何资源时将本地Cookie附加在http头中传递到服务器。
4. 基于Memcache【或者Redis】的Session共享
Memcache由于是一款基于Libevent多路异步I/O技术的内存共享系统,简单的Key + Value数据存储模式使得代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势,目前本人所经历的项目达到2000/秒 平均查询,并且服务器CPU消耗依然不到10%。
另外值得一提的是Memcache的内存hash表所特有的Expires数据过期淘汰机制,正好和Session的过期机制不谋而合,降低了过期Session数据删除的代码复杂度,对比“基于数据库的存储方案”,仅这块逻辑就给数据表产生巨大的查询压力。
5、服务器间同步
还有一个简单的办法可以用于会话信息不会频繁变更的情况,在机器a设置用户会话的时候,把会话数据post到机器b的一个cgi,机器b的cgi把会话数据存下来,这样机器a和b都会有同一份session数据的拷贝。
基于Memcache 的存储是这几个方案中推荐选用的!其它方案依然有其使用的场合,具体选用哪套需要开发人员的根据当前的服务器资源、网站并发压力等综合评估。
参照:http://blog.sina.com.cn/s/blog_5f3d71430100jv7q.html