build立:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache使用AJP转发请求。
问题:
经过一段时间(一点也不固定,可能在一两个小时之间,或一天或多天),Tomcat就会下降。 要么停止响应,要么放置通用的“Service Temporarily Unavailable”。
诊断:
有两台服务器具有相同的设置。 其中一个拥有较高的stream量网站(每秒几个请求),另一个拥有较低stream量的网站(每几分钟有less数几个请求)。 这两个网站是完全不同的代码库,但他们展示类似的问题。
在第一台服务器上,当问题发生时,所有线程缓慢地开始占用,直到达到极限(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)
我们在高stream量服务器上注意到的另外一件奇怪的事情是,在问题发生之前,数据库查询花费的时间比以前长得多(2000-5000毫秒,而通常5-50毫秒)。 这只会在MaxThreads消息出现之前持续2-4秒。 我假设这是服务器突然处理太多的数据/stream量/线程的结果。
背景信息:
这两台服务器已经运行了一段时间没有问题。 在这段时间内,系统实际上每个都使用两个NIC进行设置。 他们分开内部和外部的交通。 在networking升级之后,我们将这些服务器移到了单个网卡(为了安全/简单的原因,我们推荐这样做)。 在更改之后,服务器开始出现这些问题。
parsing度:
显而易见的解决办法是回到两个NIC的设置。 问题在于它会导致networking设置的一些复杂性,似乎忽略了这个问题。 我们宁愿尝试让它在单个NIC设置上运行。
谷歌search各种错误消息没有提供任何有用的(旧的解决scheme或与我们的问题无关)。
我们已经尝试过调整各种超时,但是这只是让服务器在死亡之前稍微运行一段时间。
我们不确定在哪里寻找进一步诊断问题。 我们仍在抓紧解决问题:
1)AJP和Tomcat的设置不正确,或过时(即已知的错误?)
2)networking设置(两个NIC对一个NIC)造成混淆或吞吐量问题。
3)网站本身(没有通用的代码,没有使用的平台,只有使用servlet和JSP的基本Java代码)
更新1:
遵循David Pashley的有用build议,我在问题期间做了堆栈跟踪/线程转储。 我发现,所有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驱动程序可能会强制所有其他线程等待它完成。 由于某种原因,它必须停留在这种阅读状态(服务器从不自行恢复,需要重新启动)。
这表明它必须与服务器和数据库之间的networking或数据库本身相关。 我们正在继续进行诊断,但任何提示都会有所帮助。
事实certificate,Oracle驱动程序的这个版本(类12 – 相当老)有其中的各种错误导致死锁(如上面引用的TP-Processor2状态所示)。 直到我们转向新的环境,它才开始活跃起来。 升级到最新版本(ojdbc14)已解决主服务器上的问题。
从描述中,我build议这个问题可能是由于数据库查询花费的时间太长。 如果查询花费的时间更长,请求将花费更长时间,因此您将有更多的同时运行。 正如你所看到的,你正在用完tomcat线程。 当你解决数据库的问题,你应该没问题。
将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 =此连接器在closures连接之前等待另一个AJP请求的毫秒数。 默认值是使用为connectionTimeout属性设置的值。
如果connectionTimeout和keepAliveTimeout值没有定义,那么AJP连接将保持活动无限。 导致许multithreading,默认的最大线程数为200。
我推荐安装psi-probe – 一个来自Lambda Probe的Apache Tomcat的高级pipe理器和监视器。 https://code.google.com/p/psi-probe/
由于AJP的工作方式,Apache(使用mod_proxy_ajp或mod_jk)之间的持久连接只能由客户端安全地closures。 在这种情况下,客户端是打开的apache工作者,然后在工作进程的生命周期中保持与tomcat的连接。
由于这种行为,你不能比tomcat工作线程有更多的apache工作者。 这样做会导致额外的http工作者无法连接到tomcat(因为接受队列已满),并将您的后端标记为DOWN!
在稳定性方面,我使用mod_proxy而不是mod_ajp获得了更好的结果,所以试试这个解决scheme。 这是非侵入性的 – 充其量只能解决问题,最坏的情况是排除mod_ajp。
除此之外,听起来像你的雄猫停止响应,所有的请求线程都被束缚住了。 让你的开发团队看看发生了什么 – 把线程转储并提供给他们将是有益的。
当我听到服务器运行一段时间时,我想到的第一件事突然变慢,然后开始出现服务故障,这是因为内存不足,并且出现掉换。 我不清楚你所看到的AJP失败是否会导致超时,但这似乎并不完全不合理; 虽然没有看到任何明显的连接到网卡的方式。 无论如何,我build议您在这些事件发生时了解您的内存使用情况。
如果RAM耗尽,则可能需要closuresApache MaxClients
并增加ListenBacklog
。
顺便说一下,感谢您的问题如此组织和完整。
我在Redhat环境中使用proxy_ajp和Tomcat发生了类似的日志错误。 通过更新httpd包来解决:
yum update httpd
从:
至:
然后重新启动apache,然后重新启动Tomcat。
为我修好了!