CS/Network

[Network]TCP 계층 혼잡제어 완벽 정리

frog-in-well 2022. 7. 29. 21:46

0. 들어가기 전에

TCP 계층의 혼잡제어 알고리즘은 크게 3가지 단계이지만 조건과 작동이 꽤나 복잡하다. 게다가 블로그마다 설명이 제각각인 경우를 많이 보았다. 이번 글에서는 Computer Networking A Top-Down Approach, 7th의 TCP 혼잡제어 FSM을 보고 정리한 내용을 다룰 것이다. 

1. TCP 혼잡제어

네트워크의 혼잡을 어떻게 감지하고 해결할 수 있을까?

  1. 타임아웃 또는 3중의 중복 ACK 발생에 의한 세그먼트 손실을 네트워크 혼잡의 발생으로 생각할 수 있다. 그리고 이에 따라 송신측의 윈도우 크기를 줄이면 된다. 즉 종단간의 혼잡을 제어하는 접근이다.

만약 네트워크 계층에서 직접적인 피드백을 준다면 송신자가 전송률을 증가시키거나 감소시킬 수 있을 것이다. 하지만 TCP 계층에서 네트워크 혼잡의 원인을 해결할 수는 없다. IP 계층이 네트워크 혼잡에 관해서 종단 시스템에게 어떠한 직접적인 피드백도 제공하지 않기 떄문에, TCP는 종단간의 혼잡을 제어해야 한다.


정리하자면 TCP 혼잡제어는 3가지 의문점을 갖게 되는 것이다.

1. 혼잡제어를 위해 송신자 전송 트래픽 전송률을 어떻게 제한하는가?

  • TCP에서는 혼잡 윈도우를 이용하여 송신 측에서 전송할 수 있는 트래픽을 제한한다.

이전에 TCP 흐름제어에서 다룬 내용에 의하면 송신 측은 수신 윈도우의 크기에 따라 트래픽이 결정된다고 했다. (송신 버퍼에서 확인응답이 안 된 데이터는 한 번에 보낸 데이터의 양이라고 생각할 수 있다. 이를 송신 윈도우라고 하자.)

이제 혼잡제어 까지 생각한다면 결국 송신 윈도우는 수신 윈도우와 혼잡 윈도우의 최솟값보다 작아야 한다.

  • LastByteSent - LastByteAcked ≤ min(cwnd, rwnd)

2. 혼잡을 어떻게 감지하는가?

  • 과도한 혼잡이 발생하면 라우터에 오버플로가 발생하고 데이터그램이 버려질 것이다. 결국 송신 측에서는 타임아웃 또는 3개의 중복된 ACK가 발생한다.

3. 송신율을 변화시키기 위한 알고리즘? (TCP 혼잡제어 알고리즘)

  • TCP에서 손실 이벤트가 발생되지 않는 경우 혼잡 윈도우의 크기를 증가시키고 손실 이벤트가 발생하면 혼잡 윈도우의 크기를 감소시긴다.
    • 네트워크에서 혼잡 상태에 대한 정보를 알려주지 않기 때문에 TCP 계층은 당근과 채찍을 반복하며 혼잡을 달래야(?) 한다.

TCP 혼잡제어 알고리즘을 보기 전, TCP에서는 타임아웃 이벤트를 중복된 3개의 ACK가 발생한 경우보다 더 혼잡한 상태로 판단한다.(TCP Tahoe 버전에서는 동일하게 처리한다.) 중복된 ACK는 적어도 손실된 세그먼트 이후의 순서번호를 가진 세그먼트들은 성공적으로 도착했다고 생각할 수 있기 때문이다.

2. TCP 혼잡제어 알고리즘

1. 슬로 스타트

  • TCP 연결이 시작될 떄, cnwd의 값은 일반적으로 1MSS로 초기화된다.
  • 확인응답을 받을 때마다 cnwd의 크기를 1MSS 씩 증가시킨다.
    • 확인응답 당 1MSS 증가이므로 1개의 세그먼트 전송 → 1개의 응답(cnwd+1) → 2개의 세그먼트 전송 → 2개의 응답(cnwd+2) → 4개의 세그먼트 전송 → …
    • 결국 확인응답(ACK)마다 cnwd의 크기를 1씩 증가시키면 매 RTT 마다 cnwd의 크기가 지수적으로 증가하는 효과를 얻게 된다.
  • 혼잡 윈도우의 지수적 증가는 영원할 수 없다. 
  1. 만약 타임아웃에 의한 손실이 일어난 경우, TCP에서는 슬로 스타트의 임계치인 ssthresh의 값을 cwnd/2 으로 정하고 cwnd의 값을 1로 한 뒤 TCP는 새로운 슬로 스타트를 시작한다. 
  2. cnwd의 값이 sshtresh 값에 도달하게 되면 슬로 스타트를 종료하고 혼잡 회피 모드로 전환한다. 
  3. 만약 3개의 중복 ACK들이 검출되면 cnwd의 값을 ssthresh+3MSS로 한 뒤 빠른 회복 상태로 들어간다.

2. 혼잡 회피

위의 설명에서처럼 혼잡 회피 모드로 들어가는 경우 cnwd의 값이 sshtresh 값에 도달한 경우이다. 즉, 혼잡을 마지막으로 검출한 시점의 cnwd 값의 절반인 범위에서 다시 cnwd의 값을 2배로 증가시키는 것은 좋은 선택이 아닐 것이다. 혼잡 회피 모드에서는 더 보수적인 방법을 선택한다. 

  • 확인응답을 받을 때마다 cnwd의 크기를 1 MSS/cwnd만큼 증가시킨다.
    • 만약 현재 혼잡 윈도우의 크기가 10 MSS 이라면, 10개의 세그먼트를 보낼 것이고, 각 세그먼트의 ACK당 cnwd의 크기는 1/10 MSS 만큼 커진다. 결국 모든 ACK를 성공적으로 받게 되면 cnwd의 크기는 1 MSS만큼 커지는 것이다
    • 다시 말하자면, 매 RTT 마다 cnwd의 크기는 1 증가한다.
  • 혼잡 회피 모드 또한 영원히 지속되지 않는다.
  1. 타임아웃이 발생한다면 ssthresh의 값을 cwnd/2으로 정하고 cwnd의 값을 1로 한 뒤 슬로 스타트 단계로 들어간다.
  2. 만약 3개의 중복 ACK들이 검출되면 ssthresh 값을 cnwd/2으로 정하고 cnwd의 값을 ssthresh+3MSS로 한다. 이후 빠른 회복 상태로 들어간다.

3. 빠른 회복 TCP Reno / TCP Tahoe

빠른 회복은 필수적인 TCP 요소는 아니다. TCP Reno라고 불리는 새로운 버전에서 채택한 방식이다. 초기 TCP 버전인 TCP Tahoe에서는 빠른 회복 없이 무조건 혼잡 윈도우를 1MSS로 줄이는 슬로 스타트 단계로 들어간다.

빠른 회복에서는 조금 다른 방식으로 혼잡 윈도우의 크기를 조절한다. 빠른 회복에 들어갈 때, 혼잡 윈도우의 크기를 반으로 한다는 설명은 많으나 그 이후의 과정은 자세하게 찾을 수 없었다. 게다가 빠른 회복으로 들어갈 때, 혼잡 윈도우의 크기를 절반으로 줄이고 +3MSS의 값을 더해주는 것이 정확한 설명이다. 

  • 손실된 세그먼트에 대한 중복된 ACK를 수신할 때마다 cnwd의 크기를 1 MSS 증가시킨다.
    • 이상하다. 중복된 ACK는 손실을 의미하는데 오히려 혼잡 윈도우의 크기를 증가시킨다? 처음에는 책에 오류가 있다고 생각했다. 하지만 "손실된 세그먼트에 대한 매 중복된 ACK를 수신할 때마다 1 MSS 씩 증가시킨다" 라는 의미를 이해하는 것이 중요하다.
    • 빠른 회복 단계에는 중복된 ACK가 3개 검출되면 들어오게 된다. 즉 정상적으로 도착했으나 순서가 맞지 않은 세그먼트가 3개 존재한다. 이 때 송신측에서는 혼잡 윈도우의 크기를 3개 늘려주어야 제대로 된 패킷을 재전송할 수 있다. 그렇기 때문에 빠른 회복 모드로 들어갈 때 +3 MSS를 해주는 것이다.
    • 같은 이유로 중복된 ACK가 발생하면 손실된 세그먼트를 전송해주기 위해서는 윈도우의 크기가 여유로워야 하기 때문에 혼잡 윈도우의 크기에 +1MSS를 반복하는 것이다.
  • 즉, 빠른 회복은 말 그대로 손실로 부터 회복하기 위해 잠깐 거쳐 가는 단계라고 생각할 수 있다. 
  1. 새로운 ACK를 받으면 cnwd의 값을 sshtresh 값으로 정하고 혼잡 회피 모드로 들어간다.
  2. 타임아웃이 발생한다면 ssthresh의 값을 cwnd/2으로 정하고 cwnd의 값을 1로 한 뒤 슬로 스타트 단계로 들어간다.

 

<혼잡제어 FSM>

 

- 아래와 같은 글도 있다.

 

TCP congestion control - Fast Recovery in graph

I've been reading the book "Computer Networking: A Top Down Approach" and encountered a question I don't seem to understand. As I read, TCP Congestion Control has three states: Slow Start, Congestion

stackoverflow.com