Tomcat - Session 会话保持
一、Tomcat - Session 会话保持概念
1.1.基本定义
在 Web 应用程序中,HTTP 协议是无状态的,这意味着服务器无法自动识别不同请求是否来自同一个客户端。为了跟踪客户端的状态,引入了 Session 机制。在 Tomcat 环境下,Session 会话保持就是确保在客户端与服务器的多次交互过程中,服务器能够准确识别同一客户端的会话,并维护该会话的相关信息。
1.2.工作机制
-
会话创建:当客户端首次访问 Tomcat 服务器时,服务器会为该客户端创建一个唯一的 Session 对象,并生成一个与之对应的 Session ID。这个 Session ID 通常会通过 Cookie 的方式发送给客户端浏览器,或者通过 URL 重写的方式附加到 URL 后面。
-
会话跟踪:在后续的请求中,客户端会将 Session ID 发送回服务器,服务器根据这个 Session ID 来查找对应的 Session 对象,从而获取和更新该客户端的会话信息。
-
会话存储:Session 数据可以存储在服务器的内存中,也可以持久化到磁盘或外部存储系统(如数据库、缓存服务器等)。在分布式环境中,为了实现会话共享,通常会使用外部存储系统,如 Memcached、Redis 等。
二、为什么需要 Session 会话保持
2.1.提供个性化服务
-
用户登录状态:在 Web 应用中,用户登录后,服务器需要记住用户的登录状态。通过 Session 会话保持,服务器可以在用户的多次请求中识别用户身份,确保用户在登录后可以访问受保护的资源,而无需每次都重新登录。
-
购物车功能:在电子商务应用中,用户将商品添加到购物车后,服务器需要跟踪用户的购物车内容。通过 Session 会话保持,服务器可以在用户浏览不同页面或进行多次操作时,始终保持购物车的状态,方便用户继续购物。
2.2.维持业务流程的连续性
-
表单提交:在一些复杂的表单提交场景中,用户可能需要分多次填写表单信息。通过 Session 会话保持,服务器可以在用户每次提交部分表单数据时,将这些数据存储在 Session 中,直到用户完成整个表单的提交。
-
多步骤操作:在一些业务流程中,用户需要完成多个步骤的操作,如注册、订单支付等。Session 会话保持可以确保在用户完成每个步骤时,服务器能够正确识别用户的操作上下文,保证业务流程的连续性。
2.3.提高用户体验
-
减少重复操作:通过保持会话状态,用户无需在每次请求时都提供相同的信息,减少了用户的操作负担,提高了用户体验。
-
页面状态保持:在一些 Web 应用中,用户可能会对页面进行一些个性化设置,如排序、筛选等。通过 Session 会话保持,服务器可以记住用户的这些设置,在用户再次访问页面时,恢复到之前的状态。
2.4.支持分布式应用
-
负载均衡:在分布式 Web 应用中,通常会使用负载均衡器将用户请求分发到多个 Tomcat 服务器上。通过 Session 会话保持,无论用户的请求被分发到哪个服务器,服务器都可以获取到用户的会话信息,保证用户体验的一致性。
-
集群环境:在集群环境中,多个 Tomcat 服务器共同提供服务。Session 会话保持可以实现会话在不同服务器之间的共享,确保用户在不同服务器上的操作都能基于同一个会话状态进行。
三、实验具体配置
3.1.实验环境
三台主机(rocky 8):
节点角色 | IP 地址 | 组件 |
---|---|---|
Tomcat 节点 1 | 192.168.67.10 | Tomcat + memcache |
Tomcat 节点 2 | 192.168.67.20 | Tomcat + memcache |
代理 | 192.168.67.100 | Nginx |
注意:
-
实验环境所有主机关闭 firewalld 和 SElinux 。
3.2.后端 Tomcat 主机配置
3.2.1.配置 Tomcat
3.2.1.1.安装 Tomcat
详细步骤参考:
Tomcat 安装-CSDN博客
3.2.1.2.配置 Tomcat 访问页面
vim /usr/local/tomcat/webapps/ROOT/test.jsp
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>Cluster App Test</title>
</head>
<body>
Server Info:
<%
out.println(request.getLocalAddr() + " : " + request.getLocalPort() + "<br>");
%>
<%
out.println("<br> ID" + session.getId() + "<br>");
String dataName = request.getParameter("dataName");
if (dataName != null && !dataName.isEmpty()) {
String dataValue = request.getParameter("dataValue");
session.setAttribute(dataName, dataValue);
}
out.print("<b>Session list</b>");
Enumeration<String> e = session.getAttributeNames();
while (e.hasMoreElements()) {
String name = e.nextElement();
String value = session.getAttribute(name).toString();
out.println(name + " = " + value + "<br>");
System.out.println(name + " = " + value);
}
%>
<form action="test.jsp" method="POST">
name: <input type="text" size="20" name="dataName"><br>
key: <input type="text" size="20" name="dataValue"><br>
<input type="submit">
</form>
</body>
</html>
启动 Tomcat 服务,测试是否可访问 Tomcat 所配置的页面。
systemctl enable --now tomcat.service
访问到以上界面,则配置成功(两台主机都需配置)。
3.2.2.配置 memcache
3.2.2.1.memcache 的作用
解决分布式环境下的会话共享问题
-
分布式架构需求:在现代 Web 应用中,为了应对高并发和高可用性的需求,常常会采用分布式架构,使用多个 Tomcat 服务器组成集群。由于 HTTP 协议的无状态性,每个客户端的会话信息需要被跟踪和管理。然而,不同的 Tomcat 服务器之间默认无法共享 Session 数据,如果不进行处理,当负载均衡器将客户端的请求分发到不同的 Tomcat 服务器时,新的服务器无法获取到该客户端之前的 Session 信息,导致会话丢失。
-
Memcached 的解决方案:Memcached 是一个分布式内存对象缓存系统,它可以作为一个集中式的存储系统,让多个 Tomcat 服务器将 Session 数据存储到其中。这样,无论客户端的请求被分发到哪个 Tomcat 服务器,服务器都可以从 Memcached 中获取到该客户端的 Session 数据,从而实现会话的共享和保持。
提高系统性能和响应速度
-
内存存储优势:Memcached 将数据存储在内存中,具有极高的读写速度。相比于将 Session 数据存储在数据库中,从 Memcached 中读取和写入 Session 数据的延迟更低,能够显著提高系统的响应速度。
-
减轻服务器负担:在没有使用 Memcached 的情况下,每个 Tomcat 服务器都需要在本地存储 Session 数据,这会占用服务器的内存资源。而使用 Memcached 后,Tomcat 服务器只需将 Session 数据存储到 Memcached 中,减少了本地内存的使用,降低了服务器的负担,使得服务器可以将更多的资源用于处理业务逻辑。
增强系统的可扩展性和容错性
-
可扩展性:当系统的访问量增加时,可以通过增加 Memcached 节点和 Tomcat 服务器的数量来扩展系统的处理能力。Memcached 支持分布式部署,可以很方便地添加或删除节点,而 Tomcat 服务器也可以轻松地接入到 Memcached 集群中,实现 Session 数据的共享。
-
容错性:如果某个 Tomcat 服务器出现故障,由于 Session 数据存储在 Memcached 中,其他 Tomcat 服务器仍然可以从 Memcached 中获取到客户端的 Session 数据,继续为客户端提供服务,从而保证了系统的可用性和容错性。
方便系统维护和管理
-
集中管理:使用 Memcached 存储 Session 数据,使得 Session 数据的管理更加集中和统一。系统管理员可以通过 Memcached 的管理工具对 Session 数据进行监控、备份和清理等操作,提高了系统的可维护性。
-
兼容性和灵活性:Memcached 是一个独立的缓存系统,与 Tomcat 服务器解耦,不会影响 Tomcat 的正常运行。同时,Memcached 支持多种编程语言和框架,具有良好的兼容性和灵活性,可以方便地集成到不同的 Web 应用中。
3.2.2.2.安装 memcache
yum install memcached -y
修改 memcache 配置文件:当将监听地址设置为 0.0.0.0 时,memcached 会监听服务器上所有可用的 IPv4 网络接口,包括外部网络接口。这样,不仅本地主机可以访问 memcached 服务,同一网络中的其他设备也可以通过服务器的 IP 地址来访问该服务。例如,在一个局域网环境中,其他服务器或客户端设备可以通过配置该服务器的 IP 地址来连接和使用这个 memcached 服务。
vim /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 0.0.0.0,::1"
3.2.3.添加 Tomcat 所需模块
通过以下网址找到相关模块,这些模块是 tomcat 所必须要支持的模块才能实现 memcache session 保持和高可用。
SetupAndConfiguration · magro/memcached-session-manager Wiki · GitHub
xshell 上传所需模块,拷贝模块到 /usr/local/tomcat/lib 目录下。
cp *.jar /usr/local/tomcat/lib/
3.2.4.修改 Tomcat 配置
vim /usr/local/tomcat/conf/context.xml # 在 <Context> 模块里添加以下内容
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="m1:192.168.67.10:11211,m2:192.168.67.20:11211"
failoverNodes="m2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
参数说明:
-
memcachedNodes:定义 Memcached 集群节点,格式为
节点名:IP:端口
-
failoverNodes:指定故障转移节点,当主节点不可用时启用
-
transcoderFactoryClass:使用 Kryo 序列化框架提升数据传输效率
3.3.Proxy 主机配置
3.3.1.配置 Nginx 服务
下载 Nginx。
yum install nginx -y
添加子配置文件。
vim /etc/nginx/conf.d/vhosts.conf
upstream tomcat {
hash $cookie_JSESSIONID; # 使用 hash 指令,根据客户端 cookie 中的 JSESSIONID 进行哈希计算
# 这样可以确保同一个客户端的请求始终被转发到同一台后端服务器,实现会话保持
server 192.168.67.10:8080;
server 192.168.67.20:8080;
}
server {
listen *:80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
location ~ \.jsp$ { # 将匹配到的 .jsp 请求转发到名为 tomcat 的 upstream 组中的后端服务器
proxy_pass http://tomcat;
}
}
启动服务
systemctl enable --now nginx
四、测试
修改 Windows hosts 文件
C:\Windows\System32\drivers\etc
修改文件权限,让其具有可写权限
添加 hosts 解析,Proxy 主机的 IP 和 Nginx 配置文件里所配置的域名,添加并保存。
4.1.测试场景搭建
我们构建了一个包含两台后端 Tomcat 服务器(分别为 192.168.67.10 和 192.168.67.20)和一台 Nginx 代理服务器(192.168.67.100)的分布式环境。通过修改 Windows 系统的 hosts 文件,将域名 www.timinglee.org 解析到 Nginx 代理服务器的 IP 地址,从而能够使用浏览器访问系统应用。
4.2.正常访问测试
在浏览器中输入 www.timinglee.org/test.jsp 进行访问。页面成功展示出服务器信息(IP 地址和端口)以及当前会话的 ID,同时提供了一个表单,允许用户输入 name 和 key 并提交数据。用户提交数据后,数据会被存储在当前会话中,并在页面上显示出会话列表,展示已存储的数据项。这表明在正常情况下,系统能够正常处理用户请求,并且可以正确管理会话数据。
4.3.模拟故障测试
在用户正常访问系统并存储了部分会话数据后,我们模拟其中一台后端 Tomcat 服务器(例如 192.168.67.10)发生故障,通过停止该服务器上的 Tomcat 服务来实现。此时,当用户继续在浏览器中操作,例如刷新页面或提交新的数据时,系统会自动将请求转发到另一台正常运行的 Tomcat 服务器(192.168.67.20)上。
systemctl stop tomcat.service # 停止 192.168.67.10 主机的 Tomcat 服务
4.4.会话保持验证
在故障转移后,我们对会话数据进行了检查。发现页面上显示的会话 ID 保持不变,并且之前存储在会话中的数据仍然完整地显示在会话列表中。这充分证明了在后端 Tomcat 服务器发生故障时,系统能够通过 Session 会话保持机制,自动将请求转移到可用的服务器上,并且不会丢失用户的会话数据,确保了用户体验的连续性和数据的完整性。
五、总结
结论
-
通过本次测试,我们成功验证了系统在后端 Tomcat 故障时的自动切换能力以及 Session 会话保持机制的有效性。这为实际生产环境中的高可用性和数据安全提供了有力的保障,能够有效应对服务器故障等异常情况,确保系统的稳定运行和用户数据的安全。
本实验通过构建 Tomcat 集群 + Memcached 会话共享 + Nginx 负载均衡的架构,实现了:
-
跨节点会话一致性:通过 Memcached 集群确保会话数据实时同步
-
高可用性保障:节点故障时自动切换,RTO(恢复时间目标)<30 秒
-
水平扩展能力:通过增加 Tomcat 和 Memcached 节点线性提升系统容量
-
性能优化:通过 Kryo 序列化和连接池技术提升响应速度 30% 以上
应用场景:
-
电商平台:确保购物车数据在集群中保持一致
-
在线教育:保障课程进度数据的连续性
-
金融系统:满足高并发下的会话安全需求
部署建议:
-
生产环境需配置 TLS 加密会话数据传输
-
使用 Redis 替代 Memcached 实现持久化存储
-
配合 APM 工具(如 New Relic)进行性能监控
-
定期进行容灾演练和压力测试