Linux Network Internal
시스템 엔지니어에게 가장 골치 아픈 커널 파라미터가 뭐냐고 묻는다면 아마 위 두 값이라고 하시는 분들이 많으실 겁니다. 비슷하게 보이지만 차이점을 알기가 힘든 두 값에 대해 간단한 테스트를 통해 그 의미를 알아보는 시간을 마련해 보았습니다.
우선 두 대의 서버를 준비합니다. 편의상 client, server라고 지정합니다.
그리고 client에서는 net.ipv4.ip_local_port_range 값을 default 값에서 32768 32768로 고칩니다.
server에서는 nginx를 yum으로 기본 설치해서 80만 띄워 놓습니다.
먼저 tcp_tw_reuse 에 대해 살펴보겠습니다.
client에서 server로 curl 명령으로 페이지를 가져오면 방금 사용했던 포트는 timewait 상태로 빠지게 됩니다. 그리고 곧바로 curl 명령을 다시 입력하면 아래와 같이 에러가 발생합니다.
네.. 당연하겠죠? 사용할 수 있는 로컬 포트는 32768 하나뿐인데 TW 상태이니 결국 사용할 수 있는 로컬 포트가 하나도 없는 상태가 됩니다.
자.. 그럼 tw_reuse를 enable 하면 어떻게 변하게 될까요?
보이는 것처럼 몇 번이고 TW 상태의 소켓을 재사용하게 됩니다.
tw_reuse는 outgoing 트래픽에 대해 로컬 포트가 모자랄 경우, TW 상태에 있는 소켓을 재사용할 수 있게 해 줍니다.
그래서 로컬 포트가 고갈되는 현상이 있을 경우 ip_local_port_range 값을 튜닝해 주기 보다는 tw_reuse를 사용하는 것이 좋습니다.
일부 인터넷에 있는 문서들 중에는 tw_reuse 가 SO_REUSEADDR와 같은 역할을 한다고 하는데, 잘못된 정보입니다. SO_REUSEADDR 은 bind와 listen 하는 과정에서 커널이 선점하고 있는 포트를 다시 사용할 수 있게 해 주는 것이고 tw_reuse는 outgoing 트래픽에 대해 TW 상태의 로컬 포트를 재사용할 수 있게 해 주는 것입니다.
자세한 내용은 http://docs.likejazz.com/time-wait/ 이 곳을 참고하시면 됩니다. 아주 정리가 잘 되어 있는 블로그입니다.
이번엔 tcp_tw_recycle 에 대해 살펴봅니다. tcp_tw_recycle 은 server에서 살펴봅니다.
client에서 telnet으로 붙은 후에 GET 요청을 보내 보면, server에서는 연결을 끊기 때문에 (keepalive는 꺼 둡니다.) 사용했던 소켓이 TW 상태로 빠집니다.
이 상태에서 client 가 다시 한 번 GET 요청을 하게 되면 어떻게 될까요?
네.. 바로바로 재사용이 됩니다. 어라..? 안될 거라고 생각했는데..? server 입장에서는 172.16.33.136:32768 포트는 끊어진 상태로 간주되기 때문에 동일한 IP에서 동일한 포트로 다시 한 번 연결 요청이 온다면 거절할 이유가 없습니다. 그래서 server 입장에서는 tw_recycle 값에 관계없이 TW 소켓을 재사용하게 됩니다.
그렇다면 tw_recycle을 enable 하면 동작이 어떻게 변화할까요?
몇 번을 요청하더라도 netstat으로 소켓이 보이지 않을 만큼 빠르게 TW 소켓이 정리됩니다. 마치 아예 만들어지지 않는 것처럼 요. 이 부분을 좀 더 자세히 살펴보기 위해 커널 소스 코드를 잠깐 봅시다.
아주 중요한 힌트가 net/ipv4/tcp_minisock.c 에 있습니다.
tw_recycle이 켜져 있으면 tw_timeout 의 값이 rto 값으로 변경되기 때문에 TW 상태의 소켓 유지 시간이 아주 짧아집니다.
특히 내부 서버간 통신의 경우 rto 가 매우 짧기 때문에 TW 소켓이 눈에 보이지도 않을 정도의 속도로 정리가 됩니다.
켜져 있지 않으면 TCP_TIMEWAIT_LEN 값에 따라 하드 코딩된 60초로 설정이 됩니다.
또한 tcp_tw_recycle 이 켜져 있으면 TW 상태의 소켓을 재사용할 때 timestamp 값을 비교하는 로직이 추가되는데, 바로 이 로직 때문에 패킷 드랍이 발생할 수 있습니다.
NAT 기반의 클라이언트들이 tw_recycle 이 켜져 있는 서버에 접속할 경우, NAT 의 IP와 포트가 똑같은 순간이 발생할 텐데요, NAT 뒷 단에 있는 클라이언트들은 서로 다른 timestamp를 가지기 때문에 첫 번째 클라이언트를 제외한 나머지 클라이언트들에서 패킷 드랍이 발생하게 됩니다.
여기까지 간단한 테스트를 통해 두 파라미터가 서버의 동작에 어떻게 영향을 끼치는 지 살펴봤습니다.
결론을 얘기하자면..
tcp_tw_reuse는 enable
tcp_tw_recycle은 disable
이상입니다. 제가 정리한 내용 중에 잘못된 내용이 있으면 언제든지 말씀해 주세요~