- stackoverflow에서 대부분 tcpdump를 이용해서 패킷 덤프를 떠 보는 방법을 제안하고 있다.
- 하지만 현재 우리 사이트와 같은 경우 1일 기준 / 특정 서버 기준으로는 1번 이하의 빈도를 갖고 있기 때문에, 덤프를 떠 확인하기 어려운 상황 이다. 이에 타 사례를 예시를 통해 사례탐구 해 보기로 한다.
※ 사례 탐구 전 몇가지 참고사항
- 주 목적은 상기 오류 해결을 위해서니 하기 내용은 아주 간단하게 참고만 하도록 하자.
▶ TCP(Transmission Control Protocol) 통신
- TCP 통신의 경우 데이터를 주고 받기 위해 HandShake 과정이 필요하다.
1) 연결 (3 way HandShake)
- SYN : Client에서 Server에 연결 요청.
- SYN-ACK : 서버는 SYN-ACK로 응답.
- ACK : 마지막으로 클라이언트가 서버에 다시 ACK를 보낸다.
이 과정을 통해서 서버와 클라이언트는 연결을 맺으며 3 Way HandShake라고 한다.
2) 데이터 요청 request / 응답 response
3) 연결해제 (4 way HandShake)
1) 클라이언트에서 서버와의 연결 종료를 위해 서버에 FIN 패킷 전송. (FIN-WAIT 상태) 2) 서버는 FIN을 받고, ACK 보낸다.(CLOSE_WAIT상태) 3) 연결을 종료할 준비가 되면 클라이언트에게 FIN패킷을 보낸다.(LAST_WAIT 상태) 4) 클라이언트는 확인 패킷 ACK을 보낸다. (TIME_WAIT 상태) 연결이 끊겼음에도 클라이언트에서 TIME WAIT을 하는 이유는 Routing 지연, 패킷 유실로 인한 재전송 등이 있다.
▶ Keep-Alive
- http는 기본적으로 통신때마다 Connection을 맞고(연결하고) 끊는것이 기본이다.
웹 서비스가 통신할 때 마다 위의 Handshake를 한다면 네트워크 측면에서 손실이 많다.
이때문에 HTTP/1.1 부터 이미 연결되어 있는 Connection을 재 사용하는 Keep-Alive라는 기능이 추가되었다. HTTP 헤더에 Keep-Alive 값을 넣어 주어서 연결을 해제하지 않고 유지 할 수 있다. (재 사용시 HandShake 는 pass)
keepAliveTimeout
The number of milliseconds this Connector will wait for another HTTP request before closing the connection.
The default value is to use the value that has been set for the connectionTimeout attribute. Use a value of -1to indicate no(i.e. infinite) timeout.
▶ Connection pool
- 클라이언트와 서버간에 연결을 맺어 놓은 상태(3way HandShake 완료 상태)를 여러개 유지하고 필요시 마나 하나씩 사용하고 반납하는 형태이다. 그러함으로써 연결/연결해제에 필요한 HandShake를 하지 않고 더 빠르게 데이터를 주고 받을 수 있다.
3. 해당 오류 발생 사례
1. KeepAlive & idle Timeout
※ 사례 예시
1) Was( ex. Tomcat )의 KeepAlive 설정에 의해 발생
- 통신 타겟 서버 Was의 connectionTimeout, keepAliveTimeout 설정에 따라 발생할 수 있다.
- tcp 덤프를 통해 확인 가능 하다. ( tcpdump -i any -A -vvv -nn host <목적지 IP> -w packet_dump.pcap)
ex) 응답을 주지 않고 FIN 패킷을 보내버리는 경우. 요청을 보냈으나, 닫겠다는 패킷을 수신하는 경우
2) LoadBalance 설정에 의해 발생
- 종료 알림인 TCP RST를 보내지 않는 옵션을 사용하는 LB의 사례
ex) 1분간 연결 유휴가 발생하면 연결을 닫지만, nettry-react를 사용한 Client에 닫힘을 인식하지 못했기 때문에, 해당 연결을 사용하려고 시도 한다. 이 경우 클라이언트 에서 연결을 닫거나 버릴 수 있다.