Apache+Tomcat 通信有问题。错误消息不明确。导致 Tomcat 托管的网站瘫痪

Apache+Tomcat 通信有问题。错误消息不明确。导致 Tomcat 托管的网站瘫痪

设置:
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 毫秒)。这只持续了 2-4 秒,然后出现 MaxThreads 消息。我认为这是由于服务器突然处理了太多数据/流量/线程造成的。

背景信息:
这两台服务器已经运行了很长时间,没有出现任何问题。当时,系统实际上是使用两个 NIC 设置的。它们将内部和外部流量分开。在网络升级后,我们将这些服务器移至单个 NIC(出于安全/简单原因,我们建议这样做)。在进行此更改后,服务器开始出现这些问题。

解决:
显而易见的解决方案是重新设置两个 NIC。但这样做的问题是,这会导致网络设置出现一些问题,而且这似乎是在忽略问题。我们更愿意尝试在单个 NIC 设置上运行它。

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

我们尝试调整各种超时时间,但这只会使服务器运行时间稍长一些才会死亡。

我们不确定从哪里可以进一步诊断问题。我们仍然不知道问题可能出在哪里:

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 驱动程序强制所有其他线程等待它完成。由于某种原因,它必须停留在此读取状态(服务器永远不会自行恢复,需要重新启动)。

这表明问题肯定与服务器和数据库之间的网络或数据库本身有关。我们正在继续诊断,但任何提示都会有所帮助。

答案1

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

答案2

根据描述,我认为问题可能是由于数据库查询耗时过长造成的。如果查询耗时较长,请求也会耗时较长,因此您将同时运行更多查询。如您所见,您的 tomcat 线程已用完。解决数据库问题后,应该就没问题了。

  • 获取堆栈跟踪,可以使用 jstack 或 kill -3 $process_id。查看线程死机时正在做什么。如果它们都在等待数据库,那么这对我的理论来说是一个很好的提示。它们可能都在等待某个锁。
  • 安装 LambdaProbe。它对于找出你的 tomcat 正在做什么非常有用。
  • 升级你的 tomcat。5.5.8 太旧了。我认为他们现在使用的是 5.5.27。

答案3

将 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 - Apache Tomcat 的高级管理器和监视器,由 Lambda Probe 分叉而来。https://code.google.com/p/psi-probe/

答案4

就稳定性而言,我使用 mod_proxy 的效果比使用 mod_ajp 更好,所以请尝试该解决方案。它是非侵入式的 - 最好的情况下它可以解决问题,最坏的情况下它会排除 mod_ajp。

除此之外,听起来您的 Tomcat 停止响应,并且所有请求线程都被占用。让您的开发团队调查发生了什么 -进行线程转储并将其传递给他们将会很有用。

相关内容