
저는 MySQL에 대해 쿼리를 실행하는 웹 애플리케이션(Tomcat/Hibernate/DBCP 1.4)을 가지고 있는데, 이것은 특정 로드, 즉 초당 50개의 쿼리에 대해 잘 작동합니다. HAProxy를 통해 동일한 중간 로드를 라우팅하면(여전히 단일 데이터베이스만 사용) 오류가 발생합니다. 쿼리 500개마다 오류가 발생할 수 있습니다. 내 앱 보고서:
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 196,898 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.
at sun.reflect.GeneratedConstructorAccessor210.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1117)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3567)
...
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3017)
...
한편 HAProxy 로그에는 다음과 같은 많은 항목이 표시됩니다.
27] mysql mysql/db03 0/0/34605 2364382 cD 3/3/3/3/0 0/0
Oct 15 15:43:12 localhost haproxy[3141]: 127.0.0.1:35500 [15/Oct/2012:15:42:50.0
"cD"는 분명히 클라이언트 시간 초과 상태를 나타냅니다. 따라서 내 웹앱에서는 HAProxy가 새로운 연결 수락을 거부한다고 말하는 반면, HAProxy는 내 웹앱에서 데이터를 다시 수락하지 않는다고 말합니다.
HAProxy 구성은 포함하지 않습니다. 다양한 매개변수 값을 시도했지만 본질적으로 동일한 결과가 나왔기 때문입니다. 특히 전역 및 서버 섹션 모두에서 maxconn을 높은 값과 낮은 값으로 설정했는데 통계에서 항상 발생하는 현상은 최대 세션이 약 7 이하로 증가한다는 것입니다. 내 JDBC 풀 크기도 높습니다.
일반적으로 JDBC 풀과 HAProxy 풀을 함께 사용해도 괜찮나요? 사람들이 전에 이런 종류의 문제에 직면한 적이 있습니까?
이 문제를 해결하는 방법에 대한 아이디어가 있습니다. 즉, 모든 쿼리 전에 "유효성 검사 쿼리"를 보내는 것입니다. 그러나 거기에는 특정 오버헤드가 있으며 내 웹 애플리케이션이 MySQL로 바로 이동할 때 성공하지만 HAProxy를 통과할 때 연결이 끊어지는 이유를 여전히 알고 싶습니다.
"cD"보다 더 자세히 디버깅하고 더 많은 정보를 얻으려면 어떻게 해야 합니까? 디버그 모드에서 HAProxy를 실행해 보았지만 더 이상 아무것도 드러나지 않는 것 같습니다.
업데이트 - 1월 4일 금요일 11:49:28 ICT 2013 (JimB에게 답장)
haproxy에서 가지고 있는 것보다 더 많은 정보를 얻는 유일한 방법은
show sess
또는show sess <id>
명령을 주기적으로 사용하여 각 TCP 연결의 상태를 관찰하는 것입니다.
세션에 대한 몇 가지 정보는 다음과 같습니다.
0x31f4310: proto=tcpv4 src=192.168.3.40:60401 fe=FE_mysql be=BE_mysql srv=mysql3 ts=08 age=1m2s calls=2 rq[f=909202h,l=0,an=00h,rx=13s,wx=,ax=] rp[f=109202h,l=0,an=00h,rx=13s,wx=,ax=] s0=[7,18h,fd=0,ex=] s1=[7,18h,fd=1,ex=] exp=13s
0x31fca50: proto=tcpv4 src=192.168.3.40:60423 fe=FE_mysql be=BE_mysql srv=mysql1 ts=08 age=2s calls=2 rq[f=909202h,l=0,an=00h,rx=1m13s,wx=,ax=] rp[f=109202h,l=0,an=00h,rx=1m13s,wx=,ax=] s0=[7,18h,fd=9,ex=] s1=[7,18h,fd=12,ex=] exp=1m13s
Haproxy의 기본 시간 제한은 10초입니다(예제 구성의 경우 50초인 것으로 생각됩니다). 나는 JDBC에 익숙하지 않지만 Tomcat의 문서에 가면 풀에서 유휴 연결을 제거하는 설정이 있으며
minEvictableIdleTimeMillis
기본값은 60초이고timeBetweenEvictionRunsMillis
기본적으로 5초이므로 최대 65초까지 걸릴 수 있습니다. 기본적으로 haproxy 시간 초과가 풀의 유휴 연결을 설명할 만큼 충분히 높은지 확인해야 합니다.
75초로 늘렸는데 timeout client
이제 위 오류가 이전보다 덜 발생하는 것 같습니다.
2013-01-04 11:59:59 디버그: 통신 링크 실패
서버로부터 성공적으로 수신된 마지막 패킷은 145,255밀리초 전이었습니다. 서버에 성공적으로 전송된 마지막 패킷은 10밀리초 전이었습니다.
또한, 위의 내용 외에도 다음과 같은 오류가 있다는 점에 유의하고 싶습니다.
통신 링크 실패 서버에 성공적으로 전송된 마지막 패킷은 0밀리초 전이었습니다. 드라이버가 서버로부터 패킷을 수신하지 못했습니다.
서버 측에서는 sD
연결이 끊어졌을 때 플래그가 표시되는 경우가 있습니다.
haproxy[15770]: 192.168.3.40:56944 [04/Jan/2013:11:06:55.895] FE_mysql BE_mysql/mysql1 0/0/77153 1954480 sD 1/1/1/1/0 0/0
또한 timeout server
75초로 설정됩니다.
testWhileIdle
또 다른 접근 방식은 연결을 활성화 하고 유지하는 것입니다valildationQuery
. 몇 초마다 몇 개의 트래픽 패킷이 문제를 완화할 수도 있기 때문입니다.
다른 방법이 없다면 개발자에게 이러한 옵션을 시도해 볼 것을 제안합니다.
답변1
haproxy에서 가지고 있는 것보다 더 많은 정보를 얻는 유일한 방법은 show sess
또는 show sess <id>
명령을 주기적으로 사용하여 각 TCP 연결의 상태를 확인하는 것입니다. 하지만 더 유용한 정보를 얻을 수 있을지는 확실하지 않습니다.
종료 cD
상태는 현재 가지고 있는 가장 유용한 정보입니다. 이것이 정확히 의미하는 바는 클라이언트와의 설정된 연결 시간이 초과되었다는 것입니다. 이는 timeout client
구성의 매개변수를 통해 haproxy에서 전역적으로 설정되거나 프론트엔트 또는 청취 섹션에서 제어됩니다 .
당신은 동시 연결이 7개를 초과하는 것을 볼 수 없다고 말했고 이 로그 항목은 연결이 3개만 있을 때 실패가 발생했음을 보여 주므로 연결 제한 문제가 있는지 의심됩니다(haproxy의 제어 범위 밖에서도).
따라서 발생하는 현상은 때때로 풀이 일부 쿼리를 처리하는 새 연결을 추가한 다음 유휴 상태로 유지되는 것입니다. 해당 연결이 haproxy의 설정보다 오랫동안 유휴 상태로 있으면 timeout client
haproxy는 연결 자체를 종료합니다. 다음에 풀에서 해당 연결을 사용할 때 위의 오류가 발생합니다.
Haproxy의 기본 시간 제한은 10초입니다(예제 구성의 경우 50초인 것으로 생각됩니다). 나는 JDBC에 익숙하지 않지만 Tomcat의 문서에 가면 풀에서 유휴 연결을 제거하는 설정이 있으며 minEvictableIdleTimeMillis
기본값은 60초이고 timeBetweenEvictionRunsMillis
기본적으로 5초이므로 최대 65초까지 걸릴 수 있습니다. 기본적으로 haproxy 시간 초과가 풀의 유휴 연결을 설명할 만큼 충분히 높은지 확인해야 합니다.
testWhileIdle
또 다른 접근 방식은 연결을 활성화 하고 유지하는 것입니다 valildationQuery
. 몇 초마다 몇 개의 트래픽 패킷이 문제를 완화할 수도 있기 때문입니다.
[편집] @Quanta의 추가 정보에 대한 응답:
haproxy 시간 초과가 이제 75초임에도 불구하고 여전히 세션 시간 초과가 발생합니다. JDBC 연결의 전체 수명 동안 내가 알지 못하는 추가 작업이 있을 수 있습니다. 이러한 유형의 서비스에는 연결이 거의 필요하지 않으므로 시간 초과를 한 시간 이상으로 매우 높게 늘려도 아무런 문제가 없습니다. JDBC 풀에서 이전 연결을 해제하는 데 실제로 문제가 있는 경우 이는 문제를 가릴 뿐이지만 쉽게 해결할 수도 있습니다.