如何隔离Java EE中的用户会话?

时间:2011-03-09 20:14:08

标签: java session java-ee isolation

我们正在考虑在Java EE中开发关键任务应用程序,并且让我印象深刻的一件事是平台中缺少会话隔离。让我解释一下这个场景。

我们有一个原生Windows应用程序(一个完整的ERP解决方案),每月从稀疏的贡献者那里获得大约2k LoC和50个bug修复。它还支持脚本,因此客户可以添加自己的逻辑,我们不知道这样的逻辑是做什么的。每个服务器节点都有一个代理和一个进程池,而不是使用线程池。代理接收客户端请求,将其排队直到池化实例空闲,向该实例发送请求,向客户端发送响应,然后将实例释放回进程池。

这种架构非常强大,因为有很多稀疏的贡献和自定义脚本,所以部署版本有一些严重的错误,例如无限循环,长时间等待的悲观锁,内存损坏或内存泄漏,这种情况并不少见。我们实现了内存限制,请求超时和简单的监视器。只要某个进程无法正确及时地回答,代理就会杀死它,因此监视程序会检测并启动另一个实例。如果进程在开始响应请求之前崩溃,则代理会将相同的请求发送到另一个池化实例,并且用户不知道服务器端的任何故障(管理日志除外)。这很好,因为有些实例在处理请求时会被伪代码慢慢删除。因为大多数会话数据都是在客户端或(在极少数情况下)在共享存储中保存,所以它似乎完美无缺。

现在考虑迁移到Java EE,我在规范或流行的应用程序服务器上找不到类似的东西,比如Glassfish和JBoss。是的,我知道大多数集群实现都使用会话复制进行透明故障转移,但是我们有一些小公司在简单的双节点集群上使用我们的系统(我们也有冒险者在单节点服务器上使用该系统) 。使用线程池,我理解一个错误的线程可以使整个节点关闭,因为服务器无法检测并安全地杀死它。将整个节点关闭比杀死单个进程要糟糕得多 - 我们有部署,其中每个节点有大约100个池化流程实例。

我知道IBM和SAP已经意识到这个问题,基于

分别是

。但基于最近的JSR,论坛和开源工具,社区上的活动并不多。

现在问题来了!

  1. 如果你有类似的情况和 使用Java EE,你是如何解决的?

  2. 你知道即将到来吗? 开源产品或改变 Java EE规范可以解决这个问题 问题

  3. .NET有同样的问题吗?能够 你解释或引用参考文献?

  4. 你知道一些现代的和 开放平台可以解决这个问题 问题,是值得的任务 ERP业务逻辑?

  5. 拜托,我不得不告诉你不要做更多的测试或任何QA投资,因为我们不能强迫我们的客户在他们自己的脚本上做这件事。我们也有紧急错误修复必须绕过质量保证的情况,虽然我们强迫客户接受这一点,但我们不能让他接受有缺陷的软件部分会影响一系列不相关的功能。这个问题是关于健壮的架构,而不是开发过程。

    感谢您的关注!

3 个答案:

答案 0 :(得分:6)

您偶然发现的是使用Java和“恶意”应用程序的基本问题。

这不仅是Java EE级别的基本问题,而且是核心JVM级别的基础问题。可用的典型JVM在加载“不安全代码”时存在各种问题。从内存泄漏,类加载器泄漏,资源耗尽和不清洁的线程杀死,典型的JVM根本不够健壮,无法在共享环境中很好地处理严重错误的代码。

一个简单的例子是Java堆的内存耗尽。作为一个基本规则,NOBODY(并且没有人,我特别指的是核心java库以及几乎所有其他第三方库)捕获OutOfMemory异常。有少数人这样做,但即便他们也无能为力。典型的代码处理他们“期望”处理的异常,但让其他人失败。运行时异常(其中OOM是其中一个)将很快通过调用堆栈一直到顶部,留下未经检查的关键路径代码的残骸,使所有类型的事物处于未知状态。

诸如构造函数或静态初始化程序之类的东西“不能失败”,留下未初始化的类成员“永不为空”。这些受损的班级根本不知道他们受损了。没有人知道它们已经损坏了,而且没有办法清理它们。击中OOM的堆是一个不安全的图像,几乎需要重新启动(当然,除非你自己编写或审核了所有代码,当然,你不会 - 谁会这样做?)。

现在,可能会出现特定于供应商的JVM,这些JVM表现得更好并且可以让您更好地控制。基于Sun / Oracle JVM(即其中大多数)的那些不支持。

因此,它不一定是Java EE问题,它是JVM问题。

在JVM中托管恶意代码是一个坏主意。唯一可行的方法是,如果您托管脚本语言,并且该脚本语言实现某种资源控制。这可以做到,你可以调整现有的作为开始(JavaScript,Groovy,JPython,JRuby)。这些语言允许用户直接访问Java库这一事实使它们具有潜在的危险性,因此您可能必须将其限制为仅由脚本处理程序包装的方面。但是,在这一点上,“为什么要使用Java”问题浮出水面。

您会注意到Google App Engine不会执行这些操作。它为每个正在运行的应用程序分离一个单独的JVM,但即便如此,它也极大地限制了在这些JVM中可以完成的工作,特别是通过现有的Java安全模型。这里的区别在于这些实例往往“长寿”,以免承受启动和关闭的处理成本。我应该说,它们应该是长寿的,而那些不存在的则会产生这些代价。

您可以自己创建JVM的几个实例,为它们提供一些基础结构来处理逻辑请求,为它们提供自定义类加载器逻辑以尝试防止类加载器泄漏,并最低限度地让您终止实例(它们如果你愿意,那只是一个过程。这可以工作,并且可能工作“ok”,具体取决于调用的粒度,以及逻辑的“启动”时间。启动时间最低限度是从运行到运行的逻辑类的加载,仅此一点可能会使这个想法变坏。它肯定不会是“Java EE”。 Java EE没有设置为执行此类操作。但是你还不清楚你正在寻找什么样的Java EE功能。

实际上,这就是Apache和“mod_php”的作用。有几个实例,作为进程,单独处理请求,一旦被扼杀就会表现得很糟糕。这就是PHP在共享托管业务中很常见的原因。在这种结构中,它基本上是“安全的”。

答案 1 :(得分:0)

我认为您的场景非常不典型,因此不可能有一个现成的框架/平台来满足这种需求。 Java EE类假设请求处理代码由与应用程序其余部分相同的团队编写,因此不需要经常隔离,监视和重置,并且错误修复将在所有部分中以相同的方式处理系统。这个假设大大简化了大多数项目的开发,部署,测试等,而不是强迫他们为不需要的东西付费,是的,它并不适合所有人。如果你想要一些根本不同的东西,你可能需要自己实现相当数量的故障转移逻辑。 Java EE确实为此提供了基本构建块。

我相信(尽管没有具体经验可以证明).NET或其他平台基本上建立在类似的假设之上。

答案 2 :(得分:0)

我们有一个类似的 - 虽然不是那么严重 - 一个非常庞大的Perl站点到Java的端口。收到HTTP请求后,我们实例化一个类并调用其processRequest方法。被try-catch和时间测量所包围。添加计时器和线程就足以杀死线程。 这在现实生活中可能已经足够了。

像glassfish这样的Java EE服务器是一个OSGi容器,你可能有更多的隔离手段。

此外,您还可以运行一系列(Web或本地)应用程序,通过中央Web应用程序向您发送请求。那些应用程序就是孤立的。

更加孤立的是序列化会话和启动新JVM的操作系统进程。

相关问题