설정 :
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache가 AJP를 사용하여 요청을 전달하고 있습니다.
문제 :
일정 시간이 지나면 (일정하지 않고 1 ~ 2 시간 또는 1 일 이상 지속될 수 있음) 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-5000ms 대 일반적으로 5-50ms). MaxThreads 메시지가 나타나기 전에 2-4 초 동안 만 지속됩니다. 나는 이것이 서버가 갑자기 너무 많은 데이터 / 트래픽 / 스레드를 처리 한 결과라고 가정합니다.
배경 정보 :
이 두 서버는 꽤 오랫동안 문제없이 실행되었습니다. 시스템은 실제로 그 시간 동안 두 개의 NIC를 사용하여 각각 설정되었습니다. 내부 및 외부 트래픽을 분리했습니다. 네트워크 업그레이드 후 이러한 서버를 단일 NIC로 옮겼습니다 (보안 / 간단 성을 위해 권장되었습니다). 그 변경 후, 서버는 이러한 문제를 겪기 시작했습니다.
해결 :
확실한 해결책은 두 개의 NIC 설정으로 돌아가는 것입니다. 그 문제는 네트워크 설정에 약간의 합병증을 유발할 수 있으며 문제를 무시하는 것처럼 보입니다. 단일 NIC 설정에서 실행하려고합니다.
다양한 오류 메시지를 검색해도 유용한 정보는 없었습니다 (오래된 솔루션이거나 문제와 관련이 없음).
우리는 다양한 시간 제한을 조정하려고 시도했지만 죽기 전에 서버가 약간 더 오래 실행되었습니다.
문제를 진단 할 위치를 잘 모릅니다. 우리는 여전히 문제가 무엇인지에 대해 빨대를 잡고 있습니다.
1) AJP 및 Tomcat 설정이 잘못되었거나 오래되었습니다 (예 : 알려진 버그?).
2) 네트워크 설정 (NIC 두 대 NIC 하나)이 혼동 또는 처리량 문제를 일으 킵니다.
3) 웹 사이트 자체 (공통 코드, 플랫폼 사용 없음, 서블릿 및 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 드라이버가 다른 모든 스레드가 완료 될 때까지 기다리도록 강제하고있을 수 있습니다. 어떤 이유로 든이 읽기 상태에 있어야합니다 (서버가 자체적으로 복구되지 않으므로 다시 시작해야 함).
이는 서버와 데이터베이스 사이의 네트워크 또는 데이터베이스 자체와 관련이 있어야 함을 나타냅니다. 우리는 지속적으로 진단 노력을 기울이고 있지만 도움이 될만한 팁이 있습니다.