• 카테고리

    질문 & 답변
  • 세부 분야

    네트워크

  • 해결 여부

    해결됨

TCP 연결 종료 시 FIN_WAIT2 에서 병목이 일어나는데 원인을 모르겠습니다.

23.10.24 15:28 작성 23.10.24 16:02 수정 조회수 588

0

안녕하세요 선생님.

양질의 강의 너무너무 감사드립니다.

AWS에서 이커머스를 운영하고 있는데 최근에 접속자가 몰려 네트워크 장애가 일어났습니다. 당시 웹서버를 늘려서 CPU 병목 등은 해결을 했지만 네트워크 장애 상황은 나아지질 않았습니다.

이후 테스트 환경을 세팅하고 장애 상황을 재연한 뒤 wireshock 을 이용해 패킷 분석도 해봤습니다.

 

참고로 인스턴스 하나에 프론트엔드(nextjs) 서버(==서버)와 백엔드(django) 서버(클라이언트) 둘 다 띄워져 있는 설정이고, 그 둘 사이의 송수신을 분석한 결과 알게 된 사실은 다음과 같습니다.

  1. 캐시(redis)가 걸린 요청은 CPU 자원을 소모하지 않는다. >총 CPU 역시 여유가 있음.

    1. 1. 패킷 분석 결과 장애상황에서도 속도가 크게 느려지지 않았다.

       

       

  2. 그렇지 않은 요청은 쿼리와 결과가 아주 간단한 요청임에도 시간이 많이 걸렸다.

     

    1. 패킷 분석 결과 TCP 연결을 종료할 때 공통적으로 병목이 일어남. (1초 내외)

처음엔 Zero-window 문제인가 했는데, 패킷 로그를 보니 window size도 문제가 없는 것 같고, FIN_WAIT2 에서 시간이 오래 걸린 것 같은데 원인을 모르겠네요. 참고로 4-way handshaking 의 로그는 다음과 같습니다.
(8000 포트가 백엔드 서버, 55032 포트가 프론트엔드의 임시포트로 추정)
```
65234 21.171396396 127.0.0.1 127.0.0.1 TCP 66 8000 → 55032 [FIN, ACK] Seq=384 Ack=570 Win=65536 Len=0 TSval=2505689308 TSecr=2505689308

65343 21.213509737 127.0.0.1 127.0.0.1 TCP 66 55032 → 8000 [ACK] Seq=570 Ack=385 Win=65280 Len=0 TSval=2505689351 TSecr=2505689308

66656 22.900434334 127.0.0.1 127.0.0.1 TCP 66 55032 → 8000 [FIN, ACK] Seq=570 Ack=385 Win=65536 Len=0 TSval=2505691037 TSecr=2505689308

66657 22.900437554 127.0.0.1 127.0.0.1 TCP 66 8000 → 55032 [ACK] Seq=385 Ack=571 Win=65536 Len=0 TSval=2505691037 TSecr=2505691037
```

정리하자면,

DB와 인스턴스 자체의 리소스(cpu, 메모리 등)엔 문제가 없는 것으로 보이고, DB 풀링도 되고 있는 상황에서
전체 패킷 로그를 보면 데이터 전송에 오래 걸린 게 아니라 TCP 연결 종료만 오래 걸려서 애플리케이션(nextjs)의 문제라고 결론지으려다가도 캐시 걸린 요청은 문제가 없어서 원인을 특정하기가 무척 힘드네요.

FIN_WAIT2 에서 병목이 일어나는데 해결할 방법이 있을까요?

다시 한 번 귀에 쏙쏙 들어오는 강의 마련해주셔서 감사합니다.

답변 1

답변을 작성해보세요.

1

대략적인 정보를 바탕으로 추측성 의견을 드려봅니다. 우선 FIN_WAIT2는 소켓을 닫으려 시도한 호스트에서 발생합니다. 보통 서버에 연결하고 종료하는 모든 능동적 행위는 클라이언트가 합니다. 그러나 간혹 서버가 먼저 TCP연결을 닫으려 시도하는 경우가 있습니다. 문제는 이 FIN_WAIT2 다음이 TIME_WAIT 상태로 전이 한다는 것입니다. 이런 흐름이 클라이언트라면 문제가 되지 않지만 서버라면 이야기가 달라집니다.

관련해 글을 하나 추천해드리오니 읽어보시고 본인의 상황에 알맞게 판단하시면 되겠습니다.

https://sunyzero.tistory.com/198

장애 문제는 늘 엔지니어를 힘들게 합니다. 하지만 한 단계 도약하려면 누구나 겪는 일이기도 합니다. 좋은 결과 얻으시기를 바랍니다. 건투를 빕니다. :)

답변 감사합니다!
제가 잘못 파악한 것 중 하나가 로그를 다시 보니 프론트엔드가 클라이언트, 백엔드가 서버인 게 맞았네요.
TCP 종료 로그의 시작이 8000(백엔드) 포트라 착각했었습니다.

댓글에도 남겨주셨고, 영상에서도 말씀하신 서버가 먼저 TCP 연결을 닫으려 시도한 비정상적인 상황인 것 같은데,

추천해주신 글을 읽어보니 아래와 같이 설명하고 있어 더 헷갈리는 상황이 되었습니다^^;;;

강의 전부 듣고 사이사이 다시 테스트해보면서 좀 더 답을 찾아보겠습니다. 감사합니다.

일반적으로 클라이언트가 active close 하도록 설계하므로 TIME_WAIT는 클라이언트측에 발생한다. 하지만 타임 아웃이나 비정상 종료를 처리하는 경우에는 서버측에서 active close하는 경우가 있다. 그렇지만 세상일은 항상 일반적인 케이스만 있는 것은 아니다. 간혹 비정상이 일반적인 케이스도 있는데, 웹서버가 그런 경우다. 웹서비스에서 사용하는 HTTP 프로토콜은 구현의 특성상 여러 클라이언트 커넥션을 빠르게 받기 위해 서버측에서 active close를 시도하는 상황이 일반적이다. 그래서 대부분의 TIME_WAIT 이슈는 웹서비스에서 주로 발생한다. 게임이나 증권 시스템들은 time_wait보단 fin_wait2나 close_wait 상태가 문제가 되는 경우가 많다.