gpt4 book ai didi

java - 为什么 Tomcat 8 不会在创建后立即将 session 持久保存到数据存储区?

转载 作者:行者123 更新时间:2023-11-28 22:01:45 27 4
gpt4 key购买 nike

我正在运行 Tomcat 8,我正在设置一个自定义 session 管理器以将 session 持久化到 Amazon DynamoDB。我正在使用 AWS Java session manager library对于 Tomcat-DynamoDB,它似乎工作正常(尽管我的问题并不特定于该库)。我正在使用单个 Tomcat 实例(无集群)进行开发和运行测试。

有一些我不理解的异常行为。当我登录我的站点时,会创建一个新 session 。登录后,我可以立即向我的网络服务器发送请求并执行操作,所有这些都需要一个有效的 session (我有)。

问题是,在我登录后,新 session 条目不会立即保存到数据存储区 (DynamoDB)。事实上,每次创建新 session 时,我观察到在 session 条目出现在 DynamoDB 之前需要 30 秒到 1 分钟,有时甚至更多。

现在,显然我能够在登录后立即发出需要身份验证的请求的原因是因为单个 Tomcat 实例正在以某种方式缓存 session 数据,然后大概在闲暇时将 session 持久保存到数据存储。

我担心的是,当我在带有负载均衡器的自动缩放组中使用实例集群时,如果 session 在创建时没有立即持久保存到数据存储区,那么在登录后立即发出的后续请求可能无法通过身份验证。如果集群中有2台机器,机器A处理登录并缓存新创建的 session ,然后机器B处理后续请求,请求将失败,因为机器B不知道 session 并且它不会在数据存储。

另一方面,使请求无效立即从数据存储中删除 session 。

我还应该提到我知道 maxIdleBackup选项,当前设置为 30 秒。来自此选项的文档:

The time interval (in seconds) since the last access to a session before it is eligible for being persisted to the session store...

我不介意 session 数据没有立即更新(比如上次访问时间),如果我不介意将其延长到 1 或 2 分钟。但是在创建时立即保留 session 似乎是 Tomcat 未提供的一个关键功能。

最后,我还应该提到我已经查看了我正在使用的 session 管理器库的所有源代码(对于 DynamoDB 的持久性,它只有几个类)并且它基本上只处理来自Tomcat session 到 DynamoDB 项目,反之亦然,加上过期的 session 收割等。所以,在我看来,这就像一个 Tomcat 问题,除非我误解了什么。


我已经跑遍了 clustering how-to它似乎旨在以这样一种方式管理机器集群,即内存中的 session 数据不断复制并在集群中的所有机器之间保持同步。这不是我想要的,因为我使用的是远程数据库 (DynamoDB),因此每个 Tomcat 实例都不必知道或关心集群中的任何其他节点。每个节点都有自己的 session 缓存,并在必要时回退到/更新数据库。

文档确实讨论了内置的 BackupManager作为 <Manager> 的选项,但我的理解是它负责将 session 数据备份到一台特定的机器。

我实际上已经设法找到解决方法来解决我遇到的新 session 没有立即保存到数据库的问题。我会添加一个详细的答案,这样这个问题就不会变成一个怪物。

最佳答案

这是我正在使用的解决方案,可以为我解决问题。我想这可能被认为是黑客攻击,但它正在运行,我没有发现任何问题(但如果有人有疑虑,请告诉我)。

基本上,我只是在 session 创建后立即强制保存它。问题实际上是找到一种方法来获取对 session 管理器数据存储的引用,因为 servlet API 不公开对它的访问。所以,首先我必须使用反射获得对 session 管理器的引用:

private static PersistentManagerBase getSessionManager(HttpSession session) {
StandardSession stdSession;
try {
Field facadeSessionField = StandardSessionFacade.class.getDeclaredField("session");
facadeSessionField.setAccessible(true);
stdSession = (StandardSession) facadeSessionField.get(session);

} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
System.out.println("Error attempting to retrieve session manager => "
+ e.getMessage() + " -- the new session has been created anyway, just not immediately persisted to the database");
e.printStackTrace();
return null;
}
return (PersistentManagerBase) stdSession.getManager();
}

...然后我可以获得对 Store 对象的引用。

Store store = manager.getStore();

不幸的是,Store.save(Session session) 调用(将 session 保存到数据库)将只接受一个实现了 Session 接口(interface)的对象。 HttpSession 没有,因此您必须创建一个 StandardSession 对象,它本质上是新的 HttpSession 对象的副本,如下所示:

private static Session createStandardSession(HttpSession newSession, Manager manager) {
StandardSession stdSession = new StandardSession(manager);
stdSession.setId(newSession.getId());
stdSession.setCreationTime(newSession.getCreationTime());
stdSession.setValid(true);
stdSession.setMaxInactiveInterval(newSession.getMaxInactiveInterval());
Enumeration<String> attrNames = newSession.getAttributeNames();
while ( attrNames.hasMoreElements() ){
String attrName = attrNames.nextElement();
stdSession.setAttribute(attrName, newSession.getAttribute(attrName));
}
return stdSession;
}

所以,把它们放在一起:

HttpSession newSession = request.getSession(true);
PersistentManagerBase manager = getSessionManager(newSession);
if (manager != null) {
manager.getStore().save( createStandardSession(newSession, manager) );
}

您需要 Tomcat 库 catalina.jar 来访问这些类:

  • org.apache.catalina.session.StandardSession
  • org.apache.catalina.session.PersistentManagerBase

关于java - 为什么 Tomcat 8 不会在创建后立即将 session 持久保存到数据存储区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37392266/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com