Apache + Tomcat通讯出现问题。不清楚的错误消息。取消托管在Tomcat下的网站


22

设置:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache正在使用AJP转发请求。

问题:
经过一段时间(完全没有常数,可能在一小时或两小时之间,或者一或几天以上),Tomcat就会崩溃。它要么停止响应,要么建立通用的“服务暂时不可用”。

诊断:
有两台服务器具有相同的设置。一个容纳一个流量较高的网站(每秒几个请求),另一个容纳低流量的网站(每几分钟请求几个)。这两个网站都是完全不同的代码库,但是它们表现出相似的问题。

在第一台服务器上,当问题发生时,所有线程慢慢开始占用,直到达到限制(MaxThreads 200)。届时服务器将不再响应(并在很长一段时间后显示服务不可用页面)。

在第二台服务器上,当问题发生时,请求将花费很长时间,并且完成后,您所看到的只是服务不可用页面。

除了提到MaxThreads问题之外,Tomcat日志不指示可能导致此问题的任何特定问题。

但是,在Apache日志中,我们看到了涉及AJP的随机消息。这是我们看到的随机消息样本(无特定顺序):

[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)

我们在流量较高的服务器上注意到的另一个奇怪的事情是,在问题开始发生之前,数据库查询所花的时间比以前更长(2000-5000毫秒,而通常为5-50毫秒)。在MaxThreads消息出现之前,这只持续2-4秒。我假设这是服务器突然处理太多数据/流量/线程的结果。

背景信息:
这两个服务器已经运行了一段时间没有出现问题。在此期间,实际上每个系统都使用两个NIC进行设置。他们将内部和外部流量分开。网络升级后,我们将这些服务器移到了单个NIC(出于安全性/简单性的考虑,建议我们使用该服务器)。更改之后,服务器开始出现这些问题。

解决方案:
显而易见的解决方案是移回两个NIC的设置。这样做的问题是它将导致网络设置复杂化,并且似乎忽略了该问题。我们希望尝试使其在单个NIC设置上运行。

搜寻各种错误消息并没有提供任何有用的信息(旧的解决方案或与我们的问题无关)。

我们已经尝试过调整各种超时时间,但这只是使服务器的运行时间稍长一些,然后才死亡。

我们不确定在哪里可以进一步诊断问题。我们仍在努力解决可能出现的问题:

1)使用AJP和Tomcat进行的设置不正确或已过时(即已知的错误?)
2)网络设置(两个NIC对一个NIC)引起混乱或吞吐量问题。
3)网站本身(没有通用代码,没有使用平台,只有带有servlet和JSP的基本Java代码)

更新1:
在遵循David Pashley的有用建议之后,我在发行过程中进行了堆栈跟踪/线程转储。我发现所有200个线程都处于以下状态之一:

"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at  oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

奇怪的是,在200个线程中只有一个线程处于这种状态:

"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.DataPacket.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]

可能是此线程中的Oracle驱动程序正在强制所有其他线程等待它完成。由于某种原因,它必须停留在此读取状态(服务器永远无法自行恢复,需要重新启动)。

这表明它必须与服务器和数据库之间的网络或数据库本身相关。我们正在继续进行诊断,但是任何提示都将有所帮助。


首先,这是一个很棒的书面问题。关于细节的出色工作!其次,您是否使用proxy_ajp或mod_jk连接Apache和Tomcat服务器?
Ophidian

我正在使用proxy_ajp来连接两者。
Jordy Boom

使用siege进行压力测试,joedog.org/ siege- home
paalfe 2014年

Answers:


9

事实证明,该版本的Oracle驱动程序(类12-相当旧)中存在各种错误,这些错误导致了死锁(如上面引用的TP-Processor2状态所示)。直到我们切换到新环境,它才变为活动状态。升级到最新版本(ojdbc14)已解决了主服务器上的问题。


这导致我到我的正确的解决方案:我有一个DB-行锁......而从来没有在App-服务器的任何异常
cljk

6

从描述中,我建议问题可能是由于数据库查询花费的时间太长。如果查询花费的时间更长,请求将花费更长的时间,因此您将一次运行更多的查询。如您所见,您的tomcat线程用完了。当您解决数据库问题时,您应该可以。

  • 使用jstack或kill -3 $ process_id获取堆栈跟踪。看看线程死后线程在做什么。如果他们都在等待数据库,那将很好地说明我的理论。他们可能都在等待锁。
  • 安装LambdaProbe。找出您的雄猫正在做什么,这是无价的。
  • 升级您的tomcat。5.5.8太老了。我认为他们现在是5.5.27。

David,根据您的线程转储/堆栈跟踪建议,我用新的发现更新了问题(请参阅更新1)。
Jordy Boom

我建议您的数据库连接池与tomcat最大连接值相比太小。似乎大多数线程都在等待获取数据库连接。
David Pashley

存在许多线程的唯一原因是因为通常使用的线程留在等待那个线程尝试从套接字读取的线程。任何时候使用的数据库连接数介于1到3之间。
Jordy Boom

5

将connectionTimeout和keepAliveTimeout添加到/etc/tomcat7/server.xml中的AJP连接器中。

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

有关AJP连接器的信息,访问https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html

  • connectionTimeout =该连接器在接受连接之后将等待呈现请求URI行的毫秒数。AJP协议连接器的默认值为-1(即无限)。

  • keepAliveTimeout =该连接器在关闭连接之前将等待另一个AJP请求的毫秒数。默认值是使用为connectionTimeout属性设置的值。

如果未定义connectionTimeout和keepAliveTimeout值,则AJP连接将无限期保持活动状态。导致许多线程,默认最大线程数为200。

我建议安装psi-probe-由Lambda Probe分叉的Apache Tomcat的高级管理器和监视器。https://code.google.com/p/psi-probe/


4

由于AJP的工作方式,apache之间的持久连接(使用mod_proxy_ajp或mod_jk)只能由客户端安全关闭。在这种情况下,客户端是打开的apache worker,然后在worker进程生命周期内保持与tomcat的连接。

由于这种行为,您不能有比Tomcat工作线程更多的Apache工作线程。这样做将导致其他http工作者无法连接到tomcat(因为接受队列已满),并将您的后端标记为DOWN!


1
很抱歉,这些年来的评论,但是不能通过将ProxyPass配置中的max-flag设置为servlet容器的MaxThreads数量来保证?
Horst Gutmann

2

就稳定性而言,使用mod_proxy而不是mod_ajp可获得更好的结果,因此请尝试该解决方案。它是非侵入性的-充其量只能解决问题,最糟糕的是可以排除mod_ajp。

除此之外,听起来您的Tomcat停止响应并且所有请求线程都被阻塞。让您的开发团队研究发生的情况- 进行线程转储并将其交付给他们将很有用。


我给人的印象是,尽管mod_proxy更易于连接,但仍存在一些可伸缩性问题。看来Apache基金会建议使用mod_jk(wiki.apache.org/tomcat/FAQ/Connectors#Q2
Ophidian 2009年

确实,它不提供粘性。但是除此之外,我从来没有遇到过问题。
罗伯特·蒙提亚努

1

当我听到服务器运行一段时间,突然减慢速度,然后开始出现服务故障时,我想到的第一件事是它的RAM不足并无法正常进行交换。我不清楚您所看到的AJP故障是否可能是由于超时导致的,但似乎并非完全没有道理。但是,看不到任何明显的方式将其连接到NIC。无论如何,我建议您了解这些事件发生时内存使用情况的情况。

如果RAM不足,则可能需要关闭Apache MaxClients并增加ListenBacklog

顺便说一句,感谢您提出的问题如此井井有条,完整。


当我观察到“ top”时,内存使用情况保持相当一致。至少没有峰值。高CPU使用率只是片刻。
Jordy Boom

1

我在Redhat环境中使用proxy_ajp和Tomcat遇到类似的日志错误。通过更新httpd程序包解决:

yum update httpd

从:

  • httpd-devel-2.2.3-43.el5_5.3.x86_64
  • httpd-2.2.3-43.el5_5.3.x86_64

至:

  • httpd-2.2.3-45.el5_6.3.x86_64
  • httpd-devel-2.2.3-45.el5_6.3.x86_64

然后重新启动apache,然后重新启动Tomcat。

这为我解决了!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.