모든 이야기

만약에 TCP 연결 중에 상대방이 끊기면..

TCP 연결이 무엇인가에 대한 대학교 네트워크 수업수준의 내용은 생략하고, 심화로 글을 써보자.

만약에 TCP 연결중에 상대방이 갑자기 노쇼해버리면???

1. 데이터 전송 중 응답이 없을 시엔 Retransmission 일정 횟수만큼 시도 후 소켓끊기.

이 때 시도를 Exponential Backoff기반으로 1초뒤에 시도하고>2초뒤에 시도하고>4초뒤에 시도하고>8초뒤에 시도하고 식으로 늘려간다. 괜히 규칙적으로 프로세스가 몰리면 안 되니 일종의 'Carrier Sense'가 담겨있는 점을 유심히 보자.

2. 연결이 유지중인데 유휴 상태일 때(Keepalive) 상대방이 유휴상태에 빠지면, 그땐 주기적으로 Keepalive 패킷을 보내며 체킹을 해준다. 일정 횟수만큼 응답이 없다면 TCP 연결을 끊어버린다.


이론은 이렇고 여기서 더 심화로 들어가자면 리눅스 기준 sysctl net.ipv4.tcp~~ 식으로 사용자가 바꿀 수 있는 설정값들이 있다(안 바꾸는게 강하게 추천된다..)

오늘의 글엔 얘들의 의미와, "왜 리누즈 토발즈는 이렇게 기본값을 설정했을까?" 를 써보고자 한다.

1) net.ipv4.tcp_retries1

1이 있고 2가 따로 있다. TCP 패킷이 실패샜을 떼 네트워크 레이어에 문제가 있는지 확인하도록 요청하기 전까지의 재전송 횟수를 의미한다. 이 정해진 횟수만큼 실패하면 '아 문제가 있다'라는걸 커널이 인지하게 된다. 이 retries1만큼 재전송 하고 끊어지는게 절대 아니다!!! 기본값은 3으로 돼있다.

2)net.ipv4.tcp_retries2

TCP 연결이 완전히 끊어졌다고 판단하고 포기할 때까지의 최대 전송횟수를 의미한다. 이 값은 15로 기본값이 돼있는데 이 때 Exponentoal Backoff 때문에 통상 30분정도의 시간이 걸린다. 따라서 장애시에 빠른 회복을 요하는 환경에서는 이 설정값을 유연하게 바꿔줘야 한다.

3)net.ipv4.tcp_keepalive_time

TCP 연결은 맺어졌는데 양쪽이 아무런 데이터를 안 주고받을 때 keepalive_time만큼 이 상황이 지속되면 'probe 패킷'을 보내기 시작한다. 이 기본값은 7200초이다.

4)net.ipv4.tcp_keepalive_intvl, net.ipv4.tcp_keepalive_probes

keepalive_intvl은 keepalive 패킷을 보내는데에 간격이고(기본은 75초) keepalive_probes는 이렇게 몇번 보낼 것인지(기본은 9번) 이다.

keepalive 관련해서 이런 보수적인 로직을 리눅스에서 표준으로 정한 이유는 인터넷망이 혼잡할 때 보통 1시간 이상씩 특정 route가 막히는 경우가 비일비재한데 이 keepalive값이 좀 짧아버리면 이런 혼잡 상황에서 모든 TCP연결이 끊어지는 대참사가 발생할 수 있기 때문이다. 아무래도 표준으로써 범용적으로 돌아가기 위해선 안전이 1순위지요

따라서 이 값은 '안전'을 상정한 값이며 이러한 안전이 굳이 필요없는 어플리케이션 계층(OSI 7 Layer 5,6,7계층) 에서는 TCP 소켓옵션을 짧게 두는 것이 정석이다. Nginx, Apache등의 웹서버를 어플리케이션으로써 둔다면 거기서 이미 디폴트값으로 리눅스 net.ipv4.tcp~~ 에서와 별개로 짧게 설정을 해뒀을 것이다.


글을 마치며

SYN Flooding이 어쩌고... DNS Spoofing이 어쩌고.. 이런거 네트워크 수업 처음 들을 때는 걍 단기암기한단 생각으로 임했는데 요즘 전반적인 컴공 취업시장이 개헬이라 이런거 계속 곱씹으면서 이런거 가지고도 사이드프로젝트 여럿 해보면서 포트폴리오거리 만드는게 중요한 것 같다. Selective Repeat/GoBackN, 2계층의 CarrierSense, 3계층의 라우팅 등등 난 CS 하위분야중 굳이 개발자가 좀 딥하게 사이드 프로젝트 AI 프로요금제 쓰면서 굴린다면 여기가 ㄹㅇ 주제 밭인듯..