December 10, 2020
이 글은 실제 업무 중에 만났던 오류를 노트에 기록해놓은 후 왜 그랬을까? 왜 해결됬을까?를 고민하는 글이다.
TIME_WAIT
상태와 ESTABLISHED
socket을 확인 할 수 있다Client => Middleware => Server
위 스크린샷 속 Application은 위 구조에서 Middleware이다.
Public API
로 생각하면 편할것 같다. 어떤 구조를 지녔는지 모른다.클라이언트의 많은 요청을 받고 미들웨어는 그 요청을 처리하기 위해 더 많은 요청을 서버로 보낸다
서버의 응답 속도는 점점 느려졌다.
The connection cannot be served because Server.Concurrency limit exceeded
golang fasthttp
를 사용한 것으로 추측된다.간단히 말해 concurrencyLimit = 1000
이라면 동시에 1000개의 요청을 처리중일때 나머지는 위 응답을 보내온다.
즉 만약 오랫동안 지연되는 요청이 있다면, 그 요청은 끝나지 않고 계속 연결된 채로 자원을 점유한다.
connectoin
들은 만들어진다일단, 나의 경우 가장 간단하고 쉬운 해결 방법을 사용했다.
timeout
옵션을 짧게 만들어 해당 문제를 해결 했다.
문제는 사실 간단하게 해결했지만 고민과정에서 이상한 방향으로 빠질뻔했다.
일단 이 글은 먼저 오류를 해결하고, 몇달뒤에 다시 고민해보는 과정에서 만들어진 글이다.
The connection cannot be served because Server.Concurrency limit exceeded
위 오류가 있었다는 사실을 잊어버리고, 대량의 TIME_WAIT
에 집중하다 보니 TCP/IP 부분을 많이 학습하게 되었다…
TIME_WAIT
가 많은 캡쳐사진만 보면서 아! TCP/IP를 공부해보자!
실제 오류 메세지부터 확인했어야 하는데… 오류가 있었다는 사실만 기억하다보니…
‘오류 메세지’를 보고 오류를 해결하고, 다시 공부하는 과정에서 ‘오류 메세지’를 잊어버려서 더 공부하게 되다니…
그런데 고민하면 할 수록 왜 timeout
옵션으로 문제가 해결됬는지가 의문이였고
slack
에 남은 메세지로 발견했다.간단하다 HTTP/1.1
은 keep-alive
속성을 가진다.
HTTP Response
를 처리한다고 해서, socket
을 끊지 않는다socket
을 끊는다socket
을 끊는다는건 4-way handshake
를 말한다이미 말했듯이, 실제 오류 메세지를 잊어버리고 너무 많은 TIME_WAIT
소켓이 존재하기 때문에 새로운 socket
생성이 불가능하다고 추측했다.
TIME_WAIT
는 아직 socket
이 종료되지 않은 상태이기에 local port등 자원 점여 중 상태이다TIME_WAIT
상태의 소켓은 자연스럽게 사라지긴 하지만, 그 사이 너무 많은 요청이 생성되어 문제가 발생했다고 추측했다.TIME_WAIT
소켓이 존재한 이유는 무엇인가?이건 사실 글을 쓰는 지금도 명확히 파악하지 못했다.
지연된 상태의 소켓이 계속 존재하고 새로운 socket
들은 만들어진다
Concurrency limit exceeded
오류 메세지를 응답하고, 클라이언트가 socket.close()
를 한다.TIME_WAIT
들이 발생했을까?Docker-compose
를 이용해서 재연해 볼려고 시도했으나, 실패했다.
아래는 문제 재연을 위해 사용된 Dockerfile
, docker-compose.yml
netstat
를 사용해서 socket
을 확인해야 하기 때문에 ubuntu
이미지를 사용했다.sleep()
을 가지고 응답하고, 클라이언트는 setInterval()
을 통해서 대량의 요청을 만들어내었다.FROM ubuntu:18.04
# install nodejs
RUN apt-get -qq update
RUN apt-get -qq upgrade --yes
RUN apt-get -qq install curl --yes
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get -qq install nodejs --yes
# istall tools
RUN apt-get -qq install net-tools --yes
WORKDIR /app
COPY ./package.json ./
RUN npm install
COPY . .
version: '3'
services:
client:
build: .
container_name: client_app
volumes:
- .:/usr/app/
- /usr/app/node_modules
command: npm run client
server:
build: .
container_name: server_app
volumes:
- .:/usr/app/
- /usr/app/node_modules
command: npm run server
이 문제를 겪고 생성한 에버노트 파일인데, 9개월쯤 지난 지금도, 새로 배울때마다 다시 찾아보면서 원인이 뭐였을까 고민하고 있다
글을 수정한 지금도
2021-08-28
이다 (블로그 글 생성일은2020-12-10
)
기록으로 남기는건 엄청 도움되는 일 같다.
또 이번 이슈를 계기로 조금이지만 네트워크/OS를 더 배우게 되었다. (실제로 블로그 글도 많이 쓸 수 있었다)
socket
과 4-way handshake
과정 및 비정상 종료 등이 단순한 과정이 매번 어렵게 느껴지는 이유는 대부분은 고급언어로 소켓을 랩핑해서 사용하기 때문에 소켓에 문제가 생기지 않는 한 로우 레벨로 내려가 확인할 일이 흔치 않고, 또한 확인하는 방법을 아는 이도 드물기 때문일 겁니다.