설정 :
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 드라이버가 다른 모든 스레드가 완료 될 때까지 기다리도록 강제하고있을 수 있습니다. 어떤 이유로 든이 읽기 상태에 있어야합니다 (서버가 자체적으로 복구되지 않으므로 다시 시작해야 함).
이는 서버와 데이터베이스 사이의 네트워크 또는 데이터베이스 자체와 관련이 있어야 함을 나타냅니다. 우리는 지속적으로 진단 노력을 기울이고 있지만 도움이 될만한 팁이 있습니다.
답변
Oracle 드라이버 의이 버전 (classes12-꽤 오래된)에는 교착 상태를 유발하는 다양한 버그가 있음이 밝혀졌습니다 (위의 TP-Processor2 상태에서 볼 수 있음). 새로운 환경으로 전환 할 때까지 활성화되지 않았습니다. 최신 버전 (ojdbc14)으로 업그레이드하면 기본 서버의 문제가 해결되었습니다.
답변
설명에서 문제는 데이터베이스 쿼리가 너무 오래 걸리기 때문일 수 있습니다. 쿼리 시간이 오래 걸리면 요청 시간이 오래 걸리므로 한 번에 더 많은 쿼리를 실행하게됩니다. 보시다시피 Tomcat 스레드가 부족합니다. 데이터베이스의 문제를 해결할 때는 괜찮을 것입니다.
- jstack 또는 kill -3 $ process_id를 사용하여 스택 추적을 가져옵니다. 스레드가 죽을 때 무엇을하는지보십시오. 그들이 모두 데이터베이스를 기다리고 있다면 그것은 내 이론에 대한 좋은 포인터입니다. 그들은 모두 자물쇠를 기다리고있을 수 있습니다.
- LambdaProbe를 설치하십시오. 바람둥이가하는 일을 찾는 것은 매우 중요합니다.
- 바람둥이를 업그레이드하십시오. 5.5.8은 엄청나게 오래되었습니다. 나는 그들이 지금 5.5.27에 있다고 생각합니다.
답변
/etc/tomcat7/server.xml에있는 AJP 커넥터에 connectionTimeout 및 keepAliveTimeout을 추가하십시오.
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"
connectionTimeout="10000" keepAliveTimeout="10000" />
https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html 의 AJP 커넥터에 대한 정보
-
connectionTimeout = 연결을 수락 한 후 요청 URI 행이 표시 될 때까지이 커넥터가 대기하는 시간 (밀리 초)입니다. AJP 프로토콜 커넥터의 기본값은 -1 (무한)입니다.
-
keepAliveTimeout =이 커넥터가 연결을 닫기 전에 다른 AJP 요청을 기다리는 시간 (밀리 초)입니다. 기본값은 connectionTimeout 속성에 설정된 값을 사용하는 것입니다.
connectionTimeout 및 keepAliveTimeout 값이 정의되지 않은 경우 AJP 연결은 무한대로 유지됩니다. 많은 스레드로 인해 기본 최대 스레드는 200입니다.
Lambda Probe에서 분기 된 Apache Tomcat의 고급 관리자 및 모니터 인 psi-probe를 설치하는 것이 좋습니다. https://code.google.com/p/psi-probe/
답변
AJP 작동 방식으로 인해 아파치 간의 지속적인 연결 (mod_proxy_ajp 또는 mod_jk 사용)은 클라이언트에 의해서만 안전하게 닫힐 수 있습니다 . 이 경우 클라이언트는 아파치 작업자가 열린 다음 작업자 프로세스 수명 동안 Tomcat에 연결됩니다 .
이 동작으로 인해 Tomcat 작업자 스레드보다 더 많은 Apache 작업자를 가질 수 없습니다. 그렇게하면 추가 http 작업자가 tomcat에 연결하지 못하고 (승인 대기열이 가득 찼으므로) 백엔드가 DOWN으로 표시됩니다.
답변
안정성 측면에서 mod_ajp 대신 mod_proxy로 더 나은 결과를 얻었으므로 해당 솔루션을 시도하십시오. 비 침습적입니다. 기껏해야 문제를 해결하고 최악의 경우 mod_ajp를 배제합니다.
Tomcats와 같은 소리가 들리지 않고 모든 요청 스레드가 묶여 있습니다. 개발자 팀에게 진행 상황을 조사하게하십시오 . 스레드 덤프를 가져 와서 전달하는 것이 유용합니다.
답변
서버가 얼마 동안 실행된다는 소식을 들었을 때 가장 먼저 생각하는 것은 갑자기 느려지고 서비스 장애가 발생하면 RAM이 부족하고 스 래싱 스왑이 발생한다는 것입니다. 보고있는 AJP 오류로 인해 시간 초과가 발생할 수 있는지 확실하지 않지만 완전히 비합리적인 것은 아닙니다. 그래도 NIC에 연결되는 확실한 방법은 없습니다. 어쨌든 이러한 이벤트가 발생할 때 메모리 사용량에 대한 상황을 파악하는 것이 좋습니다.
RAM이 부족한 경우 Apache를 종료하고을 MaxClients
증가시켜야합니다 ListenBacklog
.
그건 그렇고, 귀하의 질문을 체계적이고 완전하게 작성해 주셔서 감사합니다.
답변
proxy_ajp와 Tomcat을 사용하여 Redhat 환경에서 비슷한 로그 오류가 발생했습니다. 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
그런 다음 아파치를 다시 시작한 다음 Tomcat을 다시 시작했습니다.
그것은 나를 위해 그것을 고쳤다!