웹서버에 request시에(socket통신) File(Socket) Descriptor 는 어떻게 생성될까?

HYK·2022년 10월 12일
0

File(Socket) Descriptor 가 소켓 통신을 할때 어떤식으로 생기는지에 대한 테스트를 해보았다.


테스트 방법

nginx(reverse proxy)와 tomcat was를 linux에 띄우고 Reqeust가 들어올때마다 File Descriptor가 어떤식으로 생성되는지 lsof 명령어를 통해서 살펴보기


테스트 과정

  1. naver cloud의 cent os 서버를 하나 생성한다.
  1. 서버에 java와 nginx를 설치한다.

    • 설치 : yum install nginx -y
    • 설정 : vi /etc/nginx/conf.d/default.conf
    server {
     listen       80;
     server_name  localhost;
    
     #access_log  /var/log/nginx/host.access.log  main;
    
     location / {
        # was url 등록
        proxy_pass http://localhost:8080/;
     }
     ...
  1. spring server 만들기
    @GetMapping("/start_sleep/{mill}") 
    public void startSleep(@PathVariable int mill) throws InterruptedException {
        log.info("start sleep");
        Thread.sleep(mill); // 특정 시간 만큼 멈추도록 설정
        log.info("enb sleep");
    }
    
    • Thread.sleep()을 쓰는 이유:
      일반적인 요청은 너무 빨리 끝나기 때문에 lsof 명령어로 관찰하기 힘들다.
      따라서 내부적으로 Thread.sleep()을 사용해서 잠시동안 멈추게 한후에 관찰해보자.
  1. was 실행 nohup java -jar test.jar &

  2. lsof -i:8080 명령어로 확인해보기


테스트 결과

1개의 Reqeust

요청 전 : TCP/IP 8080 포트를 사용 중이고 상태는 LISTEN 상태인 FD를 확인할 수 있음.
요청 후(Tread Sleep 상태 즉 통신 중인 상태) : 3개의 결과를 볼 수 있는데 결과가 3개인 이유는 1개의 서버에서 nginx 와 was를 같이 띄웠기 때문이다.
따라서

  • nginx -> was (ESTABLISHED상태)
  • was -> (LISTEN상태)
  • was -> nginx (ESTABLISHED상태)

이렇게 3개가 나오게 된다. 각각 다른 서버에 배치했다면 nginx가 배치된 서버에서는 1개 was 가 배치된 서버는 2개 (LISTEN과 요청 중인 소켓 총 2개)의 결과가 나올 것이다.

여러개의 Reqeust(20개)


앞서 살펴본 것처럼 nginx 요청과 내부의 was 요청 + LISTEN 해서 총 41 개의 FD 가 생성된 것을 살펴볼 수 있다.

FD의 상태변화

사진과 같이 NAME 오른쪽에 TCP/IP의 상태가 표시되는데 FD : 24U의 통신이 끝날 때쯤 서버의 TCP/IP CLOSE_WAIT 상태가 되는 것을 볼 수가 있었다.


더알아보기

TCP/IP의 상태 전이

TCP/IP 프로토콜은 다음 과 같은 순서로 동작하는 데 순서를 살펴보자(꼭 클라이언트가 먼저 통신을 요청/종료를 하는 것은 아니다)

연결 및 통신 (TCP 3-way Handshake)

  1. 먼저 recive 받는 쪽의 상태가 LISTEN 상태여야 통신이 진행될 수 있다.
  2. 클라이언트에서 SYN을 보낸 후에 SYN_SENT 상태로 변경된다
  3. 서버에서는 SYN을 받고 그에 대한 응답으로 SYN와 ACK을 같이 보내고 자신은 SYN_RCVD 상태로 전이된다.
  4. 클라이언트는 서버에서 SYN과 ACK 을 받고 나서 ESTABLISHED(연결 수립) 상태로 변경된다. 후에 ACK을 서버에 보낸다
  5. 서버는 클라이언트에서 ACK 을 받은 후에 자신도 ESTABLISHED 상태로 변경되고 통신이 시작된다.

연결 종료(TCP 4-way Handshake)

  1. 클라이언트에서 close를 실행하고 FIN을 서버로 전송한다 이때 클라이언트는 FIN_WAIT_1 상태가 된다.
  2. 서버에서는 FIN을 받고 CLOSE_WAIT 상태가 된다. 또한 ACK을 클라이언트로 전달하고 해당 포트의 애플리케이션에게 close를 요청한다
  3. 클라이언트는 ACK 을 받으면 FIN_WAIT_2 상태가 된다.
  4. 종료 프로세스를 진행하고 FIN을 클라이언트에 보내 LAST_ACK 상태로 바꾼다.
  5. 클라이언트는 FIN을 받고 ACK를 서버에 전송한 후에 TIME_WAIT으로 상태가 된다. TIME_WAIT에서 일정 시간이 지나면 CLOSED 상태로 변경된다.
  6. 서버는 ACK를 받고 포트를 닫는다.

Ref
https://tech.kakao.com/2016/04/21/closewait-timewait/
https://man7.org/linux/man-pages/man8/lsof.8.html
https://www.ncloud.com/guideCenter/guide/36

profile
Test로 학습 하기

0개의 댓글