1.2.2 Session共享和会话保持
首先我们得了解什么是Session,即会话。
Session在网络应用中被称为“会话”,借助它可为服务器端与客户端系统之间提供必要的交互。因为HTTP本身是无状态的,所以经常需要通过Session来解决服务器端和浏览器端的保持状态问题。Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,该SessionID被作为标识符来存取服务器端的Session存储空间。
SessionID这一数据是保存到客户端的,用cookie保存,用户提交页面时会将这一SessionID提交到服务器端,以存取Session数据。服务器也会通过URL重写的方式来传递SessionID的值,因此它不是完全依赖于cookie的。如果客户端cookie禁用,则服务器可以自动通过重写URL的方式来保存Session的值,并且这个过程对程序员透明。
1.什么是Session共享
随着网站业务规模和访问量的逐步增大,原本由单台服务器、单个域名组成的迷你网站架构可能已经无法满足发展需要。此时我们可能会购买更多的服务器,并且以频道化的方式启用多个二级子域名,然后根据业务功能将网站分别部署在独立的服务器上,或者通过负载均衡技术(如HAProxy、Nginx)让多个频道共享一组服务器。
如果我们把网站程序分别部署到多台服务器上,而且独立为几个二级域名,由于Session存在实现原理上的局限性(PHP中Session默认以文件的形式保存在本地服务器的硬盘上),这使得网站用户不得不经常在几个频道间来回输入用户名和密码,导致用户体验大打折扣;另外,原本程序可以直接从用户Session变量中读取的资料(如昵称、积分、登入时间等),因为无法跨服务器同步更新Session变量,迫使开发人员必须实时读写数据库,从而增加了数据库的负担。于是,解决网站跨服务器的Session共享问题的需求变得迫切起来,最终催生了多种解决方案,下面列举4种较为可行的方案来进行对比和探讨。
(1)Session复制
熟悉Tomcat或Weblogic的读者对Session复制应该是非常了解的。Session复制就是将用户的Session复制到Web集群内的所有服务器上,Tomcat或Weblogic自身都带了这种处理机制。但它的缺点也很明显,Session复制是基于IP组播的,随着机器数量的增加,网络负担呈指数级上升,性能随着服务器数量的增加而急剧下降,而且很容易引起网络风暴。所以目前基本上不会考虑采用此种方案。
(2)基于cookie的Session共享
这个方案部分读者可能比较陌生,但它在大型网站中是被普遍使用了的。其原理是将全站用户的Session信息加密、序列化后以cookie的方式统一种植在根域名下(如.host.com)。当浏览器访问该根域名下的所有二级域名站点时,会将与域名相对应的所有cookie内容的特性传递给它,从而实现用户的cookie化Session在多服务间的共享访问。
这个方案的优点是无须额外的服务器资源,缺点是受HTTP协议头信息长度的限制,仅能够存储小部分的用户信息,同时cookie化的Session内容需要进行安全加解密(如采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带宽资源,因为浏览器会在请求当前域名下的任何资源时将本地cookie附加在HTTP头中传递到服务器上。
(3)基于数据库的Session共享
首选当然是MySQL数据库,建议使用内存表Heap,以提高Session操作的读写效率。这个方案的实用性比较强,它的缺点在于Session的并发读写能力取决于MySQL数据库的性能,同时需要我们自己来实现Session淘汰逻辑,以便定时地从数据表中更新、删除Session记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储Session还是有些杀鸡用牛刀的架势。
(4)基于Memcached/Redis的Session共享
Memcached是一款基于Libevent的多路异步I/O技术的内存共享系统,简单的Key+Value数据存储模式使其代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势。
另外值得一提的是,Memcached的内存Hash表所特有的数据过期淘汰机制,正好与Session的过期机制不谋而合,这就降低了删除过期Session数据的代码复杂度。但对比“基于数据库的存储方案”,仅逻辑这块就给数据表带来了巨大的查询压力。
Redis作为NoSQL的后起之秀,经常被拿来与Memcached作对比。Redis作为一种缓存,或者干脆称为NoSQL数据库,提供了丰富的数据类型(list、set等),可以将大量数据的排序从单机内存解放到Redis集群中处理,并可以用以实现轻量级消息中间件。在Memcached和Redis的性能比较上,Redis在小于100KB的数据读写上速度优于Memcached。在笔者的很多线上系统中,Redis已经取代Memcached存放Session数据了。
2.什么是会话保持
会话保持并非Session共享。
在大多数电子商务应用系统中,或者在需要进行用户身份认证的在线系统中,一个客户与服务器经常会经过好几次的交互过程才能完成一笔交易或一个请求。由于这几次交互过程是密切相关的,服务器在进行这些交互的过程中,要完成某一个交互步骤往往需要了解上一次交互的处理结果,或者上几步的交互结果,这就要求所有相关的交互过程都由一台服务器完成,而不能被负载均衡器分散到不同的服务器上。
而这一系列相关的交互过程可能是由客户到服务器的一个连接的多次会话完成的,也可能是在客户与服务器之间由多个不同连接里的多次会话完成的。关于不同连接的多次会话,最典型的例子就是基于HTTP的访问,一个客户完成一笔交易可能需要多次点击,而一个新的点击产生的请求,可能会重用上一次点击建立起来的连接,也可能是一个新建的连接。
会话保持就是指在负载均衡器上有这样一种机制,可以识别客户与服务器之间交互过程的关联性,在做负载均衡的同时,还能保证一系列相关联的访问请求被分配到同一台服务器上。