ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Linux TCP Keepalive 정리
    커널(Kernel) 2022. 12. 11. 22:33

     

    환경 정보

    OS: ubuntu18.04 

     

     

    TCP Keepalive

    종단 간 커넥션을 만들기 위해서는 TCP 맺음/ 끊기가 필요하다.  

    하지만 통신할 때마다 TCP 연결을 맺고 끊는 방식은 비효율적이기 때문에,

    만들어진 세션을 계속 사용함으로써 자원을 아끼고 애플리케이션  응답속도를 향상시킬 수 있다.

    이렇게 세션을 유지하는 방법이 keepalive이다. 

     

    keepalive는 클라이언트와 서버 둘 다 사용할 수 있으며, 둘 중 하나라도 있으면 세션은 유지된다. 

    keepalive로 커넥션을 맺게 되면, 서로가 살아 있는지 확인하기 위해 아주 작은 패킷 하나를 보내는데, 

    둘 중 하나에서만 보내도 충분하기 때문에 keepalive를 사용하기 유리한 쪽에서 보내 세션을 유지한다. 

     

    keeplialive를 사용 중인 소켓은 다음과 같이 확인할 수 있다. 

     

    그리고 ESTABLISHED 상태의 소켓에서 keepalive 타이머를 확인할 수 있다.

     

     

     

    TCP Keepalive 커널 파라미터

    TCP keepalive와 관련된 커널 파라미터도 있다.

     

    net.ipv4.tcp_keepalive_time: 패킷이 지나지 않아도 7200초 동안 커넥션을 유지한다. 

    net.ipv4.tcp_keepalive_probes: keepalive 커넥션을 유지하기 위해 보내는 keepalive 패킷의 최대 재전송 횟수를 의미한다. 

    net.ipv4.tcp_keepalive_intvl: 재전송 패킷을 보내는 주기로 패킷을 보냈는데 응답이 없으면 몇 초 후에 패킷을 재전송할 것인지를 나타낸다. 

     

     

    TCP Keepalive를 이용한 좀비 커넥션 방지 

    좀비 커넥션은 잘못된 커넥션을 유지하고 있는 것을 말한다.

    그리고 TCP Keepalive를 이용하면, 좀비 커넥션을 방지하는데 좋다. 

     

    예를 들면, 두 종단간 연결을 끊기 위해서는 FIN 패킷이 필요한데 네트워크 이슈로 FIN 패킷을 전달받지 못하게 된다면  FIN을 전달할 방법이 없어 연결된 것처럼 남아 있게 되어 좀비 커넥션이 생성된다.  

     

    이때 TCP keepalive 옵션을 사용하면, 일정 시간이 지난 후에 keepalive 확인 패킷을 보내고

    이에 대한 응답이 없다면 커널이 끊어진  세션으로 판단하고 소켓을 정리한다. 

     

    이러한 방식으로 좀비 커넥션을 방지한다. 

     

     

    좀비 커넥션 만들기 테스트 

    이 테스트 내용은 내가 임의로 진행한 거라 정확하지 않을 수도 있다. 

     

    테스트의 내용은 대략적으로 다음과 같다. 

     

    클라이언트(192.168.9.75) => nginx(192.168.9.75:80) telnet으로 접속한다.

    그리고 iptables를 통해 192.168.9.75:80로 가는 패킷을 드랍시켰을 때, 소켓의 상태를 확인한다.  

     

    환경이 가지고 있는 파라미터는 다음과 같다. 

     

    nginx

    keepalive_timeout = 120

     

    커널 파라미터

     

    1. 클라이언트(192.168.9.75) => nginx(192.168.9.75:80)로 연결 

     

    두 프로세스 다 ESTABLISHED 상태를 유지한다.  

     

     

    2. 클라이언트에서 192.168.9.75:80로 가는 경우 패킷을 드랍시키는 rule을 OUPUT chain rule에 추가한다. 

    iptables -A OUTPUT -p tcp -d 192.168.9.75 --dport 80 -j DROP

     

     

     

    3. 클라이언트와 nginx의 연결은 nginx로 보낸 마지막 요청으로부터 120 초 후에 커넥션이 끝이 난다. 

     

     

    이후 남아있는 telnet 클라이언트와 nginx 서버는 다음과 같은 상태로 남게된다.

     

     

     

    각각 FIN_WAIT1, LAST_ACK 상태가 된다.

    TIME_WAIT 상태로 빠지지 못하고 stuck 되어 좀비 커넥션이 된다. 

     

     

    이렇게 남겨진 커넥션은 시간이 지나면서 천천히 사라진다.  

     

    위에서 TCP Keepalive probe라는 커널 파라미터가 있었는데

    위 사진의 probe를 보면 keepalive packet 재전송을 통해서 연결을 끊은 것 같다. 

     

     

    TCP Keepalive와 HTTP Keepalive

    TCP Keepalive와 HTTP Keepalive를 혼동할 수 있는데, 이 둘은 다르다. 

     

    TCP Keepalive

    두 종단 간의 연결을 유지하는 것이 목적이다. 

     

    HTTP Keepalive

    최대한 연결을 유지하는 것이 목적이다. 

     

    위 두 값이 동시에 사용된다면 다음과 같이 동작한다. 

     

    예시 1) TCP keepalive timeout = 30, HTTP keepalive timeout = 60

    TCP Keepalive 시간이 끝나도 새로 TCP 커넥션이 생성되어 HTTP keepalive 시간이 끝날 때까지

    TCP keepalive가 유지된다. 이후 HTTP keepalive time이 60초가 지나면 서버에서 먼저 FIN을 보내 연결을 종료한다. 

     

    예시 2) TCP keepalive timeout = 60, HTTP keepalive timeout = 30

    HTTP keepalive time이 30초가 지나면 서버에서 먼저 FIN을 보내 연결을 종료한다. 

     

    결론은 TCP Keepalive가 설정되어 있어도, HTTP Keepalive가 설정되어 있다면

    HTTP Keepalive 설정 값에 맞춰서 동작한다. 

    즉, 두 값이 다르게 세팅되어 있더라도 걱정하지 않아도 된다.

     

     

    Reference

    Devops와 SE를 위한 리눅스 커널 이야기 

     

    반응형

    '커널(Kernel)' 카테고리의 다른 글

    Linux Dirty page가 I/O에 미치는 영향  (0) 2022.12.19
    Linux TCP 재전송과 타임 아웃  (0) 2022.12.18
    Linux TIME_WAIT 소켓 정리  (0) 2022.12.11
    Linux NUMA 아키텍처 정리  (0) 2022.12.05
    Linux Swap 영역 정리  (0) 2022.12.04

    댓글

Designed by Tistory.