2009년 10월 8일 목요일

[TCP] 신뢰적인 전송 4 : Timer, Time out, RTT

지금까지 TCP가 신뢰적인 데이터 전송을 위해 사용하는 필수적인 정보인 Ack bit, Sequence number, Ack number 대해 살펴보았다. 이번 포스트에서는 그에 더하여 재전송의 필수적인 기능인 타이머에 대하여 알아보도록 하겠다.

 

패킷을 전송함에 있어서 TCP는 패킷이 어떻게 목적지까지 전달되는지를 전혀 알지 못한다(심지어 전달이나 제대로 될지조차 알 수 없다). 그 이유는 패킷의 전송 경로 및 전송 여부가 TCP의 하위 계층 프로토콜인 IP에 의해 결정되기 때문이다. 이미 언급하였듯이 IP는 기본적으로 Best effort 서비스를 제공하기 때문에 패킷이 어떤 경로로 전달 되는지를 관리할 필요가 없다. 라우터의 입장에서 특정 패킷을 받았을 경우, 패킷의 목적지 주소를 확인하고, 자신이 가지고 있는 라우팅 테이블에 등록되어 있는 라우터들 중에서 목적지 주소로 가기에 가장 비용이 저렴한 라우터를 선택해 패킷을 전달하면 라우터는 자신의 역할을 모두 한 것이다.(자세한 내용은 IP를 다룰 때 설명하겠다.) 즉 자신을 포함하여 다음 라우터까지의 단 1홉에 해당하는 경로만을 관리하는 프로토콜인 IP에 의해 패킷이 전달되기 때문에 TCP에서는 자신이 보낸 패킷이 어떤 경로로 목적지까지 갈 것인지를 알 수 있는 방법이 전혀 없다는 것이다.

 

자신이 전송한 패킷이 어떤 경로로 갈지 알 수 없다는 것은 무엇을 의미하는가? 그것은 패킷이 목적지까지 도착하는데 얼마나 시간이 걸릴지 전혀 알 수 없다는 뜻이며, 이에 따라 당연히 응답이 올 때까지 얼마나 기다려야 할지 전혀 알 수 없다는 뜻이기도 하다. 그렇다면 TCP는 타이머를 돌리면서 얼마나 기다려야 할지, 즉 타임 아웃 시간을 얼마로 설정해야할지 어떻게 결정하는가?

 

TCP가 타임 아웃 시간을 어떻게 설정하는지를 살펴보기 전에, 우선 타임 아웃 시간에 대한 기본적인 사항들을 생각해보자. 타임 아웃 시간은 얼마나 길어야 하는가? 쉽게 생각할 수 있듯이 "Time out > 패킷이 목적지까지 가는 시간 + 응답이 되돌아오는 시간" 이다. 만일 타임 아웃 시간이 왕복 시간보다 짧다면 패킷은 불필요하게 재전송 될 것이다. 그럼 타임 아웃을 좀 길게 잡으면 어떨까? 이것 역시 답이 될 수 없다. 이미 말했듯 왕복 시간은 얼마나 길어질 지 아무도 모르기 때문에 여유있게 잡는다고 잡은 타임 아웃 시간보다 훨씬 길 수 있으며, 또 다른 더 큰 문제는 실제로 패킷이 손실되어 정말로 재전송을 해야할 때에 너무 긴 타임 아웃으로 인해 심각한 시간 지연을 가져 올 수 있다는 것이다. 이와 같은 사실을 통해 타임 아웃 시간은 "고정된" 값을 가져서는 안된다는 것을 알 수 있다.

 

그러면 이제 실제로 TCP는 이러한 타이머의 타임 아웃 시간을 어떻게 결정하는지 살펴보자.

타임 아웃 시간을 결정하는 알고리즘은 여러 가지가 있을 수 있지만, 그 중 Van Jacobson이 1988에 제안한 방법에 근거하여 설명하겠다. 이와 관련된 더 자세한 내용을 알기 원한다면 RFC2988을 찾아보기 바란다.

 

우선 설명에 앞서서 계산식에 사용할 변수들을 정의하겠다. 이 정의는 RFC2988에 근거한 것이다.

- RTO (Retransmission Time Out) : 최종적으로 구해야 할 타임 아웃 시간.

- RTT (Round Trip Time) : 패킷이 목적지에 도달한 후, 그에 대한 응답이 돌아오기까지의 시간. 즉 패킷의 왕복 시간. 각 패킷마다 전송 경로 및 그 때마다의 네트웍 부하가 틀리므로 매번의 RTT는 각 패킷별로 틀릴 수밖에 없으며 RTT는 이러한 각 패킷마다의 개별적인 왕복 시간을 의미한다.

- SRTT (Smoothed RTT) : 각 RTT들의 가중 평균치.

- RTTVAR (RTT variation) : 최근의 RTT가 이전까지의 평균 RTT에 비해서 얼마나 빗나갔는지를 나타내는 가중치.

 

용어 설명에서 일부 설명이 되었지만, RTT는 패킷이 TCP단에서 IP단으로 넘어간 시점으로부터 ACK가 되돌아올 때까지의 총 시간을 의미하고, 각 패킷마다 그 때의 망 상황과 경로 선택에 의해 매번 변경될 수 밖에 없다. 따라서 우리는 RTO를 결정하기 위해 이 RTT의 어떤 평균치를 구해야 한다는 것을 알 수 있다. 그러나 단순히 각 RTT를 더한 후, 총 회수로 나누는 단순 평균은 적절치 않은데, 그 이유는 쉽게 생각할 수 있듯이 가장 최근의 RTT가 현재의 망 상황을 더 잘 반영하기 때문이다. 따라서 가장 최근에 측정된 RTT의 비중이 크게 적용되도록 평균을 구해야 하며 이런 식으로 구해진 평균 RTT를 SRTT이라고 부른다. (이와 같은 통계 기법을 EWMA- Exponential Weighted Moving Average라고 하며 예전 값들이 전체 평균에 미치는 영향이 지수적으로 감수하므로 Exponential이라고 부른다).

 

위와 같은 사실들을 기억하고 다음 식을 보자. 다음 식은 SRTT를 구하는 식이다.

 

SRTT_n = ((1-x) * SRTT_m) + (x * RTT)

 

위의 식을 보면 이전까지의 평균치(SRTT_m)와 최근에 측정된 RTT에 가중치(x)를 곱한값을 더해서 가중 평균치(SRTT_n)을 구하고 있다는 것을 알 수 있다. 여기에서의 가중치 x는 일반적으로 0.125 (1/8)인데 이 수치는 V. Jacobson과 M. Karels가 제안한 [JK88] - Congestion Avoidance and Control을 참조하면 된다. 이 수치를 넣어서 위의 식을 다시 정리하면

 

SRTT_n = (0.875 * SRTT_m) + (0.125 * RTT)

 

가 된다.

 

우리가 지금까지 구한 것은 RTT값이었다. 즉 패킷을 전송한 후, 그 패킷이 돌아올 때까지의 평균 시간을 구한 것이었다. 그렇다면 우리가 정작 구해야 할 RTO는 어떻게 결정해야 할까?  명백하게 타임아웃 값은 Ack가 돌아오기 전에 만료되어서는 안된다는 점을 생각해볼 때, RTT의 평균치에 약간의 여분을 더해서 설정되어야 한다. 즉

 

RTO = SRTT + (4*RTTVAR)

 

이다. 여기에서 왜 RTTVAR에 4를 곱하는지에 대한 이유는 아직 찾지 못했다. 어떤 근거가 있을텐데 나중에 찾게 되면 이 포스트를 다시 업데이트 할 예정이다. 우선 RTTVAR은 최근의 RTT가 SRTT에 비해 얼마나 빗나가있는지를 나타내는 정도라고 얘기했다. 그렇다면 위의 식을 생각해볼때, RTTVAR가 크면, 즉 최근의 RTT가 평균치인 SRTT보다 매우 크거나 매우 작으면 RTO는 크게 변한다는 것을 알 수 있다. 그렇다면 RTTVAR은 어떻게 구하는가? RFC2988에 따르면 다음과 같다.

 

RTTVAR_n = ((1-x)*RTTVAR_m) + (x*|RTT - SRTT|)

 

이다. RTTVAR 역시 SRTT와 마찬가지로 변동치 값에 대한 가중 평균치임을 알 수 있다. 여기에서 x는 0.25(1/4)로 제안되었는데, 이 수치 역시 [JK88] - Congestion Avoidance and Control을 참조하면 된다.

 

Reference : RFC2988, RFC1122

댓글 없음:

댓글 쓰기