HTTP 协议本身是“连接 - 请求 - 应答 - 关闭连接”的模式,是一种无状态协议;然而随着 web 动态化的需求,我们往往需要把两次连续的请求关联起来,从而使得客户端和服务端的会话变得有状态。Session 就是满足这种需求的一种实现方式。
它的基本原理是服务器端为每一个 session 管理一份会话信息数据。而客户端和服务器端依靠一个全局唯一标示符 —— sessionID 来访问会话信息数据。当用户访问 web 应用时,服务器端会先检查客户端的请求里是否包含 sessionID,如果没有或者检索不到,服务器端会自动创建一个新的 sessionID,同时开辟数据存储空间, 并且在本次响应中将 sessionID 返回给客户端保存。
当服务器端需要开辟数据存储空间时, 一般会在内存中创建相应的数据结构,但在访问量非常大的系统中,session 会占用大量的内存空间,而且系统一旦宕掉或者掉电,所有的会话数据就会丢失,这种事故在电子商务网站中会造成严重的后果。当然也可以将 session 内容存储在数据库中,从而在某种程度上实现持久化,但是这样会增加 I/O 开销,影响系统的性能。
在 IBM Websphere Application Server 中提供了两种不同的 session 持久化管理方案,如图 1 所示,分别是
1.使用数据库做 session 持久化管理 所有的 session 信息被集中存放于数据库中.
2.内存到内存的复制 所有 session 的信息会存放在各个应用服务器的内存中.
使用数据库存储 session 数据时需要对存储的信息作序列化操作,在某种程度上影响了响应的时间和效率,适用于 session 数据量大,并且对持久化要求比较高的应用场景。在内存到内存的复制方案里,session 管理者可以把最近经常使用的 session 保存在内存里面,极大地降低了获取 session 数据的时间开销,从而满足了对效率和响应时间要求高的应用需求。从内存到内存的 session 复制,一般适用于 session 数据量不大的应用场景。本文将详细介绍内存到内存复制的持久化管理方案。
内存到内存复制
内存到内存的 session 复制指的是将 sessions 复制到另一个 WebSphere Application Server 上。在这个模式下,sessions 可以被复制到一个或者多个应用服务器上,从而防止 HTTP Session 单点失败(single point of failure)的发生。
Session 复制的目的,是将 session 的信息进行备份保存,以便在服务器发生故障的情况下,session 状态不会丢失,实现 session 的高可用性,从而保证即使有故障发生,也不会影响到客户正在进行的业务,避免造成损失,进而提高客户满意度。
目前 WebSphere Application Server 提供了三种复制方式(如图 2 所示):
- 仅服务器模式: 所谓仅服务器,指的是该应用服务器只会存储其他应用服务器的 session 备份,而不会把自己创建的 session 分发并复制到其他应用服务器上。
- 仅客户机模式: 所谓仅客户机,指的是该应用服务器只会把自身的 session 分发并复制到其他应用服务器上,但不会存储其他应用服务器的 session 备份。
- 客户机和服务器模式: 所谓客户机和服务器,指的是该应用服务器既能作为服务器存储其他应用服务器的 session 备份,也能作为客户机把自身的 session 分发并复制到其他应用服务器上。
WebSphere Application Server 默认的是客户机和服务器模式。用户也可以根据需要选择合适的复制模式。目前 WebSphere Application Server 支持两种 session 复制拓扑结构,分别为:
- 客户机 / 服务器 (Client/Server)
- 点对点 (Peer-to-Peer)
针对这两种拓扑结构,我们将在余下的章节中作详细的介绍。
复制域
首先,内存到内存复制功能是通过应用服务器上的数据复制服务实例来实现的,我们要确保这些数据复制服务实例是属于同一个复制域的,否则这些实例相互间就不能进行复制,从而影响内存到内存复制功能的实现。
如图 3 所示 , 复制域 Domain1 包含三个成员 Server1,Server2 和 Server3,因此这三个 server 之间能相互进行复制。但是由于 Server4 并不属于复制域 Domain1 里面的成员,因此 Server4 上的 session 不能复制到复制域 Domain1 的成员上,同时也不能备份 Domain1 上成员的 session 信息。
其次,属于同一个复制域的所有会话复制都必须具有相同的拓扑结构。如果同一个复制域中的一个会话管理实例使用的是客户机 / 服务器拓扑结构,则其余所有的会话管理实例只能是“仅服务器”模式或者“仅客户机”模式。相反,如果有一个会话管理实例使用的是点对点的拓扑结构,则其余 所有的会话管理实例只能被配置成“客户机和服务器”模式。“仅服务器”模式或者“仅客户机”模式不能与“客户机和服务器”模式共存于同一个复制域里面。
在集群环境中,默认采用的是点对点的单备份复制,但是我们也可以在复制域里面修改复制的数量。如图 4 所示,如果副本数选择单个副本,那么 session 只会被备份到一个复制域成员上,如果选择整个域,则 session 就会备份到所有其他复制域成员。当然,我们也可以根据实际需要来指定复制的副本数目。
内存到内存复制拓扑结构:点对点
图 5 是一个点对点复制的拓扑结构图。在这个结构图中,每一个复制域成员都把 session 的信息保存在自己的内存中。同时它也会把 session 的备份信息发送并保存到其他复制域成员上,同时,它也从其他的复制域成员上获取 session 的信息。在这种情况下,每个复制域成员既可以作为一个客户端,从其他的复制域成员上获取 session 的信息;也可以作为服务端,把自身 session 的信息存储到其他复制域成员上。也就是说,每个复制域成员的复制模式都是“客户机和服务器”。
在这种配置方式下,不同的服务端之间的关系是平等的,而且需要最少的服务器进程,因此它代表了最牢固的拓扑结构。尤其当各个节点具有相同的性能(CPU,内存等等)和处理相同数量的工作时,该拓扑结构可以达到最稳定的实施。
点对点复制的拓扑结构的优势是不需要额外的进程和产品来避免单点失败,从而减少了配置和维持额外进程或产品的时间和费用的成本。但这个拓 扑结构的局限性就是它需要占用一定的内存空间,因为每个服务端都需要备份这个复制域里所有 session 的信息。假如一个 session 需要 10KB 的空间来存储信息,那么当 100 万个用户同时登陆到这个系统中时,每个应用服务器就需要花费 10GB 的内存空间来保存所有 session 的信息。它的另一个局限性是每一个 session 信息的修改都会被复制到其他所有的应用服务器上,这极大地影响了整个系统的性能。
在 Websphere Application Server V7 开始支持 session 热故障恢复 (session hot failover) 功能。这个功能只适用于点到点复制模式。在集群环境中,session affinity 会把客户的所有后续请求分发到同一台应用服务器上。启用这一特性之后,如果运行某个实例的服务端突然宕掉,那么 Websphere Application Server plug-in 就会把其后续请求转发到集群环境中其他合适的服务端上。
对于设置成点到点复制模式的集群来说,这个新特性可以触发插件程序,从而让保存这些 session 备份的复制域成员来直接接管宕掉的复制域成员的工作,这样可以减少从另一个复制域成员那里再次获取 session 备份的开销。
内存到内存复制拓扑结构:客户机 / 服务器
“客户机 / 服务器”拓扑就是把集群中的复制域成员分别设置成“仅服务器”模式或者“仅客户机”模式。这种拓扑可以把备份数据和本地数据分离开来,所有“仅客户机”成 员共享“仅服务器”成员上 session 备份,减少了单个复制域成员的复制开销。拿“仅客户机”成员来说,它就不用再负责为别的成员进行 session 备份,可以有更多的资源来运行业务;而对于“仅服务器”成员来说,它只负责备份 session,不需要处理业务,其上不需要部署任何应用程序。
图 6 描述的就是“客户机 / 服务器”拓扑结构。
这种拓扑结构的优势是它明确区分了客户机和服务器的角色。“仅服务器”成员将所有的 session 信息保存在内存中,而“仅客户机”成员专门处理业务。这样可以减少每个客户机的内存开销和性能影响。
所有“仅客户机”成员可以共享“仅服务器”成员,当有“仅服务器”成员且数据有多余两个以上的备份时,就可以实现故障恢复的目的。
在实际操作中,我们推荐使用多个备份服务器从而减少单点错误的发生。
两种复制拓扑的比较
在前面两个章节中,我们分别介绍了点到点和客户机 / 服务器两种复制拓扑结构的原理及其优势和局限性,在本章节中,我们将进一步比较这两种复制拓扑。
对比条目 客户机 / 服务器 点对点定义 |
通常来说,使用这种方式,是为了在 session 副职的情况下更好地保持 session affinity。在这种拓扑结构中,
|
缺省设置。每个复制域成员可以:
|
设置方法 | 每个复制域成员的复制方式,要么是“仅服务器”,要么是“仅客户机”。 | 所有复制域成员的复制方式是“客户机和服务器” |
复制域中各节点复制功能 | 每一个复制域成员,要么仅作为服务器,只为别的成员存储 session 备份,要么仅作为客户机,把自己的 session 发到服务器段进行备份。 | 每一个复制域成员既把自己的 session 发给其他所有成员进行备份,同时又为其他所有成员备份 session。 |
复制的方向性 | 成员到成员的 session 复制是单向的 | 成员到成员的 session 复制是双向的 |
局限性 | 需要额外的服务器单独作为复制服务器。需要先启动所有复制服务器,在启动复制客户机,这样才能保证客户机上的所有 session 都被成功复制到服务器上。 | 某一时刻,每个复制域中必须至少有两个活动的复制域成员,才能保证 session 的点对点复制正常进行。如果成员只有 1 个,没法进行点对店的复制。 |
Session 问题诊断
在实际应用中,管理员可以通过启动 DebugSessionCrossover 来查看每个复制域成员上 session 的信息,可以查看到该成员上针对每个应用的 session 统计信息。启动该功能的步骤如下:
点击 服务器 > 应用程序服务器 > 《服务器名字》 > Web 容器设置 > Web 容器 > 定制属性 > 新建
在相应的属性里填写如图 7 所示的值,然后点击确定。
图 7. 启动 DebugSessionCrossover 检测
通过启动该功能,管理员就可以通过访问 URL:http://<hostname>:<portnumber> /<your_app_context_root>/servlet/com.ibm.ws.webcontainer.httpsession.IBMTrackerDebug 来查看具体 session 信息,如清单 1 所示:
Session Tracking Internals J2EE NAME(AppName#WebModuleName):: tri-ear#tri-web.war cloneId : 15fm7sgs8 Number of sessions in memory: (for this webapp) : 9 Invalidation alarm poll interval (for this webapp) : 126 Max invalidation timeout (for this webapp) : 1800 Using Cookies : true Using URL Rewriting : false use SSLId : false URL Protocol Switch Rewriting : false Session Cookie Name : JSESSIONID Session Cookie Comment : SessionManagement Session Cookie Domain : Session Cookie Path : / Session Cookie MaxAge : -1 Session Cookie Secure : false Maximum in memory table size : 1000 current time : Thu Oct 28 15:26:29 GMT+08:00 2010 integrateWASSec :true Session locking : false Sessions Created:9 Active Count:0 Session Access Count:3707 Invalidated Sessions Count:0 Invalidated By SessionManager:0 SessionAffinity Breaks:0 Number of times invalidation alarm has run:38 Rejected Session creation requests(overflow off):0 Cache Discards:0 Attempts to access non-existent sessions:27 Number of binary reads from external store:27 Total time spent in reading from external store(ms):0 Total number of bytes read:-27 Number of binary writes to external store:939 Total time spent in writing to external store(ms):63 Total number of bytes wriiten out:-939 Session count 9 No of Replicated Sessions in the backup table(for this server) : 41 Total size of serializable objects in memory :42340 Total number objects in memory :9 Min size session object size:4687 Max size session object size :4826 |
在清单 1 里,我们可以看到目前在内存中针对名为 tri-web 的应用的 session 数目为 9,该服务器总共创建了 9 个 tri-web 应用的 session,同时备份表里面的 session 数目是 41。值得注意的是, 内存 (in-memory) 的 session 和备份表 (backup table) 里的 session 过一段时间后就会过时,这些过时的 session 会被服务器删除,一旦 session 被删除,以下两个数据统计值就被清零。
- No of sessions in memory: (for this webapp)
- No of Replicated Sessions in the backup table(for this server)
但是 created session 记录的是 session 创建的历史数据,只要服务器没有被重启,created session 里的数目只会随着 session 的创建而不断增加。
那么如何来诊断复制域成员的 session 复制服务是否正常工作?在下文中,我将分别介绍两种复制拓扑结构的实际用户场景,以及如何通过 DebugSessionCrossover 来诊断 session 的复制服务是否工作正常。
某用户创建了一个集群,该集群包含 3 个应用服务器,这 3 个应用服务器都是属于同一个复制域,并且该复制域的副本数选择“整个域”。然后用户把应用安装到这 3 个应用服务器上,并且把他们配置成“点对点”复制的拓扑结构。然后用户不断发送请求到这些应用服务器上,由于在 WebSphere Application Server 里默认的 session 超时时间为 30 分钟,为了避免超时以及 session 过期带来的干扰,我们简化场景,压力测试只跑 15 分钟,压力测试结束后等候几分钟以保证所有 session 处理完毕,最后再通过
http://<hostname>:<portnumber>/<your_app_context_root>/servlet/com.ibm.ws.webcontainer.httpsession.IBMTrackerDebug
来查看具体 session 信息。当然用户也可以通过控制台来更改 session 超时时间间隔,如图 8 所示,但是在实际应用中 session 超时时间不宜过长,否则 session 无法及时清除,占用大量内存空间,从而影响服务器的性能。
通过使用 IBMTrackerDebug.Servlet, 我们可以检查所有复制域成员备份表中的 session 数目,所有复制域成员创建的 session 数目和复制域成员数目,应该满足如下公式:
所有复制域成员备份表中的 session 数目总和 = 所有复制域成员创建 session 的数目总和 *(复制域成员数 – 1),也就是说,所有服务器创建的 session,在其他所有复制域成员有都有一份备份。
例如在上面的用户场景中,我们得到如下的统计数据:
3个复制域成员备份表的 session 数目总和为:15+17+16 = 48, 如清单 2 所示 .
*********************************************************************************** http://sndev03.cn.ibm.com:9080/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug No of Replicated Sessions in the backup table(for this server) : 15 http://sndev03.cn.ibm.com:9081/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug No of Replicated Sessions in the backup table(for this server) : 17 http://sndev03.cn.ibm.com:9082/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug No of Replicated Sessions in the backup table(for this server) : 16 *********************************************************************************** |
3 个复制域成员创建 session 的数目总和 *(复制域成员数 – 1)= (9+7+8)*(3-1)=48, 如清单 3 所示 .
*********************************************************************************** http://sndev03.cn.ibm.com:9080/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug Sessions Created: 9 http://sndev03.cn.ibm.com:9081/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug Sessions Created: 7 http://sndev03.cn.ibm.com:9082/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug Sessions Created: 8 *********************************************************************************** |
根据上面的数据,我们可以看到该集群所有复制域成员的 session 复制服务正常工作。
某用户创建了一个集群,该集群包含 3 个应用服务器,这 3 个应用服务器都是属于同一个复制域,并且该复制域的副本数选择“单个副本”。然后用户把应用安装到这 3 个应用服务器上,并且把他们配置成“客户机 / 服务器”复制的拓扑结构。同样用户不断发送请求到这些应用服务器上,一直到压力测试结束。然后通过
http://<hostname>:<portnumber>/<your_app_context_root>/servlet/com.ibm.ws.webcontainer.httpsession.IBMTrackerDebug
来查看具体 session 信息。如果“客户机 / 服务器”复制拓扑结构满足如下公式:
复制域成员备份表中的 session 数目总和 = 复制域成员创建 session 的数目总和
那么我们就认为该拓扑下的复制服务正常工作。否则用户就要重新检查自己的配置是否正确。
例如在上面的用户场景中,我们得到如下的统计数据:
3个复制域成员备份表的 session 数目总和为:20+21+17 = 58, 如清单 4 所示 .
清单 4. 客户机 / 服务器复制域成员备份表的 session 数目
*********************************************************************************** http://sndev03.cn.ibm.com:9080/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug No of Replicated Sessions in the backup table(for this server) : 20 http://sndev03.cn.ibm.com:9081/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug No of Replicated Sessions in the backup table(for this server) : 21 http://sndev03.cn.ibm.com:9082/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug No of Replicated Sessions in the backup table(for this server) : 17 *********************************************************************************** |
3 个复制域成员创建 session 的数目总和 =18+20+20 = 58, 如清单 5 所示 .
清单 5. 客户机 / 服务器复制域成员创建的 session 数目
*********************************************************************************** http://sndev03.cn.ibm.com:9080/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug Sessions Created: 18 http://sndev03.cn.ibm.com:9081/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug Sessions Created: 20 http://sndev03.cn.ibm.com:9082/TriBookStore/servlet/com.ibm.ws.webcontainer.httpsession .IBMTrackerDebug Sessions Created: 8 *********************************************************************************** |
根据上面的数据,我们可以看到“客户机 / 服务器”的复制拓扑工作正常。
值得注意的是,以上两个公式的使用都具有一定的局限性。它不适用于存在 session 过期的场景,因为 session 经常会过期,根据 session 复制原理,对于过期的 session,其备份也会被从其他复制域成员上删除,而这中间,复制域成员之间通信会有一定的延迟,所以造成某一时刻,这个公式不再适用。
结束语
本文主要介绍了在 WebSphere Application Server 集群环境下如何通过内存到内存的两种复制拓扑有效地管理 HTTP session。并对两种拓扑使用以及各自的优势和局限性作了进一步的阐述。最后,本文以示例的方式,向读者分享如何通过 DebugSessionCrossover 来查看复制域成员上的 session 统计信息。实际使用中,用户需要根据需要,选择合理的复制拓扑,从而达到其业务需求。