首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tomcat集群环境的体系结构问题

Tomcat集群环境的体系结构问题
EN

Stack Overflow用户
提问于 2012-12-23 11:57:42
回答 10查看 2.2K关注 0票数 8

我正在做一个项目,在这个项目中我们有一个认证机制。我们在身份验证机制中遵循以下步骤。

  1. 用户打开浏览器,在文本框中输入他/她的电子邮件,然后单击登录按钮。
  2. 请求转到服务器。我们生成一个随机字符串(例如,123456)并向用户的安卓/苹果手机发送通知,并在wait()方法的帮助下使当前线程等待。
  3. 用户在他/她的手机上输入密码,然后点击他/她手机上的提交按钮。
  4. 一旦用户单击submit按钮,我们将使webservice访问服务器并传递先前生成的字符串(例如,123456)和密码。
  5. 如果密码对先前输入的电子邮件是正确的,我们将notify()方法调用到先前等待的线程,并在响应和用户被输入到我们的系统时发送成功。
  6. 如果密码与先前输入的电子邮件不正确,则将notify()方法调用到先前等待的线程,并将失败作为响应发送,并向用户显示无效的凭据消息。

一切都很好,但最近我们转向了集群环境。我们发现,一些线程即使在用户回复后也没有得到通知,等待时间也是无限的。

对于服务器,我们使用Tomcat5.5,我们遵循http://tomcat.apache.org/tomcat-5.5-doc/cluster-howto.html来创建Tomcat集群环境。

答案::可能的问题和解决方案

可能的问题是集群环境中的多个JVM。现在,我们还将集群Tomcat与生成的字符串一起发送给用户Android应用程序。

当用户单击“回复”按钮时,我们将发送生成的字符串和集群Tomcat,因此在本例中,这两个请求都指向相同的JVM,并且工作正常。

但我不知道上述问题是否有单一的解决办法。

这个解决方案有一个问题。如果集群Tomcat崩溃会发生什么?负载均衡器将向第二个集群Tomcat发送请求,同样的问题也会出现。

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2012-12-27 09:16:54

造成问题的根本原因是,Java被设计成以一种不同的方式工作--试图阻止/等待服务线程是一个重要的不-不。我将首先给出原因,以及如何在此之后解决问题。

Java ( web和EJB层)被设计成能够扩展到非常大的大小(集群中有数百台计算机)。然而,为了做到这一点,设计者必须做出以下假设,这是对如何编写代码的具体限制:

  • 交易是:
代码语言:javascript
复制
1. Short lived (eg don't block or wait for periods greater than a second or so)
2. Independent of each other (eg no communication between threads)
3. For EJBs, managed by the container

  • 所有用户状态都在特定的数据存储容器中维护,包括:
代码语言:javascript
复制
1. A data store accessed through, eg, JDBC. You can use a traditional SQL database or a NoSQL backend
2. Stateful session beans, if you use EJBs. Think of these as Java Bean that persists its fields to a database. Stateful session beans are managed by the container
3. [Web session](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSession.html) This is a key-value store (kinda like a NoSQL database but without the scale or search capabilities) that persists data for a specific user over their session. It's managed by the Java EE container and has the following properties:
代码语言:javascript
复制
    1. It will automatically relocate if the node crashes in a cluster
    2. Users can have more than one current web session (i.e. on two different browsers)
    3. Web sessions end when the user ends their session by logging out, or when the session is inactive for longer than the configurable timeout. 
    4. All values that are stored **must** be serializable for them to be persisted or transfered between nodes in a cluster.

如果遵循这些规则,Java容器可以成功地管理集群,包括关闭节点、启动新节点和迁移用户会话,而无需任何特定的开发人员代码。开发人员编写图形界面和业务逻辑--所有的“管道”都由可配置的容器特性管理。

此外,在运行时,Java容器可以被一些相当复杂的软件监视和管理,这些软件可以跟踪实时系统上的应用程序性能和行为问题。

< snark >嗯,这就是理论。实践表明,忽略了一些非常重要的限制,这导致了AOSP和代码注入技术,但这是另一个故事< /snark >

[在这个问题上,围绕‘网络有许多讨论。其中一个关注于EJB的是:为什么不鼓励在Java容器中生成线程? --对像Tomcat这样的web容器来说完全一样--]

抱歉,这篇文章--但这对你的问题很重要。由于线程的限制,您不应该阻止web请求等待另一个请求,稍后的请求。

当前设计的另一个问题是,如果用户与网络断开连接、断电或干脆放弃,该怎么办?大概你会超时,但过了多久?对一些客户来说,可能太早了,这会导致满意度问题。如果超时时间太长,您可能会阻塞Tomcat中的所有工作线程,服务器就会冻结。这将为您的组织打开拒绝服务攻击的大门。

编辑:在发布了更详细的算法描述之后,改进了建议。

尽管上面讨论了阻塞web工作线程的不良做法以及可能的拒绝服务,但很明显,用户有一个很小的时间窗口来对Android电话上的通知作出反应,并且可以保持较小的时间以增强安全性。这个时间窗口也可以保持在Tomcat的响应超时以下。因此可以使用线程阻塞方法。

有两种方法可以解决这个问题:

  1. 将解决方案的焦点更改为客户端-在浏览器上使用Javascript轮询服务器
  2. 集群中节点之间的通信允许从Android接收授权响应的节点解除阻塞servlet响应的阻塞。

对于方法1,浏览器通过Javascript对Tomcat上的web服务进行AJAX调用,通过Javascript轮询服务器;如果安卓应用程序通过身份验证,则AJAX调用返回True。优点:客户端,服务器上的实现最少,服务器上没有线程阻塞。缺点:在等待期间,您必须频繁地调用(可能每秒一次--用户不会注意到这个延迟),这相当于服务器上的大量调用和一些额外的负载。

对于方法2,也有选择:

  1. Object.wait() (可选地将节点ID、IP或其他标识符存储在共享数据存储区中)阻止线程:如果是这样,接收安卓应用程序授权的节点需要:
代码语言:javascript
复制
1. Either find the node that is currently blocking or broadcast to all nodes in the cluster
2. For each node in 1. above, send a message that identifies the user session to unblock. The message could be sent via:
代码语言:javascript
复制
    1. Have an internal-only servlet on each node - this is called by the servlet performing the Android app authorization. The internal servlet will call `Object.notify` on the correct thread
    2. Use a JMS pub-sub message queue to broadcast to all members of the cluster. Each node is a subscriber that, on receipt of a notification will call `Object.notify()` on the correct thread.

  1. 轮询数据存储,直到线程被授权继续:在这种情况下,Android应用程序所需要做的就是将状态保存在SQL DB中。
票数 9
EN

Stack Overflow用户

发布于 2012-12-23 12:03:58

使用等待/通知可能会很棘手。请记住,任何线程都可以随时挂起。因此,在等待之前调用通知是可能的,在这种情况下,等待将永远阻塞。

在您的情况下,我不会想到这一点,因为您涉及到了用户交互。但是对于您所做的同步类型,请尝试使用信号量。创建一个0(零)数量的信号量。等待的线程调用获取(),它将阻塞,直到另一个线程调用release()。

以这种方式使用信号量比等待/通知您描述的任务要健壮得多。

票数 1
EN

Stack Overflow用户

发布于 2012-12-23 12:08:51

在分析了您的问题之后,我得出结论,确切的问题在于集群环境中的多个JVM。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14010765

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档