TCP의 흐름 제어 & 혼잡 제어

2025. 5. 7. 17:21·Computer Science/네트워크
728x90

흐름 제어 (Flow Control)

파이프라이닝 기반 전송으로 한 번에 무한히 많은 데이터를 주고 받을 수 있는가? 👉 No!
수신 측이 송신 측보다 데이터 처리 속도가 빠르면 문제 없지만, 송신 측의 속도가 더 빠를 경우 문제가 생김

수신 호스트가 한 번에 받아서 처리할 수 있는 세그먼트의 양에는 한계가 있기 때문에,
한계를 초과한 이후 도착하는 패킷은 손실될 수 있고 만일 손실된 경우 불필요한 추가 패킷 전송 발생

TCP 헤더에 정의된 Window 필드

📌 TCP의 흐름 제어
송신 호스트가 수신 호스트의 처리 속도를 고려하여 송수신 속도를 균일하게 유지하는 기능
  • Stop-and-Wait ARQ를 사용하면, 흐름 제어 필요 없음
  • 파이프 라이닝 기반 ARQ를 사용하면 흐름 제어 필요!

rfc793#section-3.1에 기술된 흐름 제어

ACK 응답 마다 윈도우 크기를 포함하여, 수신자가 이후 허용 가능한 시퀀스 번호 범위를 알림으로 흐름 제어.

윈도우 크기는: 송신자가 다음 허가(ACK)를 받기 전까지 전송할 수 있는 바이트(octet)의 수


시퀀스 번호 범위

TCP에서 수신자가 어떤 시퀀스 번호 범위의 데이터까지 수신 가능한지 송신자에게 알리는 방식
👉 `ACK+윈도우 크기` 필드 사용

ACK 패킷에 들어있는 정보

  • `ACK 번호`: 수신자가 다음으로 기대하는 시퀀스 번호, 현재까지 정상적으로 받은 마지막 바이트 + 1
  • `Window Size`: 수신자가 현재 수신 버퍼에 수용할 수 있는 여유 공간

즉, 수신자가 허용하는 시퀀스 번호 범위 = 수신자가 기대하는 다음 바이트 + 수신 가능 크기

📌 예시
수신자가 ACK 번호로 1001, 윈도우 크기로 5000 전송
송신자는 `1001 ~ 6000`까지 전송 가능 (총 5000byte)

슬라이딩 윈도우 (Sliding Window)

TCP 흐름제어 기법, 윈도우의 크기 만큼 확인 응답(ACK)을 받지 않고도 한 번에 전송 가능

  • 윈도우 (Window): 송신 호스트가 파이프라이닝할 수 있는 최대량
  • 수신 호스트는 TCP 헤더 (윈도우 필드)를 통해 송신 측에 자신이 받을 데이터의 양을 알려줌
  • 송신 윈도우: 헤더로 전달받은 수신 윈도우를 토대로 연산

LastByteAcked

수신자로부터 ACK를 받은 가장 마지막 바이트의 시퀀스 번호.
→ 수신자가 성공적으로 받았다고 확인한 마지막 바이트

LastByteSent

송신자가 전송을 시도한 마지막 바이트의 시퀀스 번호
→ 아직 ACK을 받지 못했을 수 있음

📌 추가로 전송 가능한 데이터 크기 계산
윈도우 크기(N)
= LastByteAcked + AdvertisedWindow(수신자가 알려준 수용 가능 윈도우 크기) - LastByteSent

예제 👇🏻

더보기
  1. 수신자가 말한 윈도우 크기: `600`
    • 수신자는 지금 600바이트만 더 받을 수 있다고 알려줌 (AdvertisedWindow = 600)
  2. 송신자가 마지막으로 ACK 받은 시퀀스 번호: `100`
    • 즉, 수신자가 1000번까지 잘 받았다고 응답했음 (LastByteAcked = 1000)
  3. 송신자가 지금까지 보낸 마지막 바이트: `1400`
    • 1001 ~ 1400까지의 총 400바이트를 보냈으나 아직 ACK를 받지 못함 (LastByteSent = 1400)

수신자가 말한 AdvertisedWindow는 1001번 부터 600byte까지만 받을 수 있음을 의미
∴ 수신자가 받을 수 있는 시퀀스 번호 범위 = `1001 ~ 1600` (전송 가능 구간)

 송신자는 이 범위 안에서만 데이터 전송 가능 하지만, 송신자는 이미 1001 ~ 1400번 까지 전송

남은 수용 공간 = 600 - 400 = 200 바이트 ( = usable Window)

∴ 새로 보낼 수 있는 범위 = 1401 ~ 1600 


혼잡 제어 (Congestion Control)

네트워크 혼잡 시나리오

네트워크 혼잡 시나리오

A는 C로, B는 D로 데이터를 전송하는 상황, 경유지 라우터의 버퍼는 유한함.

전송량에 대한 그래프

  • R: 입/출력 링크 용량
  • λout: 도착하는 데이터
  • λIn: 전송되는 데이터 (원본 + 재전송)

네트워크 혼잡이 발생하여 패킷이 유실 된다면,
해당 패킷이 링크를 점유했던 시간 & 버퍼링 시간이 무용지물 됨 = 오버헤드


혼잡 제어 vs 흐름 제어

  • 흐름 제어
    • 송/수신 측 간의 전송 속도 조절
    • 수신측의 버퍼 오버플로우 방지를 위해 슬라이딩 윈도우 기법으로 데이터 전송 속도 조절
  • 혼잡 제어
    • 라우터에서 발생할 수 있는 네트워크 혼잡 상황 방지
    • 네트워크 상황이 좋지 않을 때, 패킷이 계속 수신되어 유실 되는 상황을 방지하기 위해 데이터 전송 속도 조절

혼잡 감지

1) TCP Throughput을 계산하여 확 줄어들면 혼잡하다고 판단

모든 ACKed된 패킷에 대해 RTT 측정 후, min(RTT)로 구한 처리율과 현재 처리율 비교

처리율 계산

  • MSS: Max Segment Size
  • cwnd: 윈도우 크기
  • RTT (Round Trip Time): 네트워크 요청이 시작점에서 목적지로 갔다가 시작점으로 다시 돌아오는데 소요되는 시간

2) 타임아웃

송신한 패킷에 대한 ACK가 일정 시간 내 도착하지 않으면 혼잡이 발생했다고 판단
👉  cwnd를 1MSS로 줄이고, Slow Start

3) Triple Duplicate ACKs (중복 ACK 3개)

같은 ACK가 3번 연속 도착하면, TCP는 그 다음 패킷이 유실된 것으로 판단
👉 Fast Retransmit + Fast Recovery 사용

 = 혼잡 윈도우를 절반으로 줄이고, 유실된 패킷만 재전송


혼잡 회피

1) Slow Start 

네트워크 상태를 모르므로 cwnd를 1부터 시작하여 천천히 증가

새로운 TCP 세션 생성 또는 타임아웃 발생 시 진입하는 스테이지

cwnd는 1부터 시작하여 매 ACK 수신 시마다 1씩 증가

cwnd의 크기는 얼마나 빠르게 증가하는가?

송신자는 한 RTT 동안 cwnd 만큼의 패킷 전송 가능
→ 모든 패킷에 대한 ACK를 받으면, cwnd는 RTT마다 2배씩 지수적으로 증가

Slow Start는 언제 종료 되는가?

`ssthresh` (Slow-start threshold): Slow Start를 종료하는 임계값

  • 혼잡 발생 시 현재 cwnd의 ½로 ssthresh 설정, cwnd는 1로 설정
  • Slow start 수행  `cwnd > ssthresh`가 되면 네트워크 용량 근처에 도달했다고 판단
  • SS 종료 후,  Congestion Avoidence로 전이

2) AIMD (Additive Increase Multiplicative Decrease)

= 혼잡 회피 (Congestion Avoidence)

증가는 하나씩, 감소는 공격적으로!

  1. Additive Increase (AI)
    1. 혼잡이 감지되지 않는 한, 매 RTT(왕복 시간) 마다 cwnd를 조금씩 증가
    2. 보통 1 MSS씩 증가 (선형 증가)
    3. cwnd = cwnd + 1 
  2. Multiplicative Decrease (MD)
    1. 패킷 손실이 감지되면 (예: 중복 ACK 3개 또는 타임아웃)
    2. cwnd를 절반으로 급격히 줄임
    3. cwnd = cwnd / 2

AIMD는 톱니 모양 그래프를 만듦

항목 Slow Start  AIMD (Congestion Avoidance)
목적 처음엔 네트워크 대역폭을 빨리 파악 이후엔 안정적으로 속도 조절
증가 방식 지수 증가 (cwnd ×2) → 매우 빠름 선형 증가 (cwnd += 1) → 느리지만 안정적
혼잡 발생 시 cwnd = 1로 초기화 cwnd를 절반으로 감소
전환 시점 cwnd ≥ ssthresh 되면 AIMD로 전환 Slow Start 이후 자동 적용

3) Fast Recovery 

네트워크가 덜 혼잡하면 cwnd를 굳이 1로 확 줄이지 않아도 되지 않나?
 = 패킷 손실이 일어난 경우, 네트워크 성능을 최대한 떨어뜨리지 않고 복구하기 위한 기법

중복 ACK 3개를 받았을 때, 패킷 손실로 간주하여 빠르게 재전송 & cwnd를 `절반`으로 줄인 후 전송을 계속하는 알고리즘

FastRetransmit (빠른 재전송) & Fast Recovery (빠른 회복)

 

  • Fast Retransmit: 중복 ACK 3개 받으면, 타임아웃 기다리지 않고 손실된 패킷 즉시 재전송
  • Fast Recovery: 그 직후, 혼잡 윈도우를 확 줄이되, 송신은 멈추지 않고 이어감

왜 사용하는가?

타임아웃을 기다리는 건 너무 느리기 때문에,

  • Fast Retransmit은 손실된 패킷을 빨리 재전송하고
  • Fast Recovery는 "그만 보내고 다시 시작" 대신, 전송 속도를 조절하며 계속 보냄

 


TCP Tahoe & TCP Reno

TCP에는 Tahoe, Reno, New Reno, Cubic, Ealstic-TCP까지 다양한 혼잡 제어 정책이 존재.

이러한 혼잡 제어 정책들은 공통적으로 혼잡이 발생하면
윈도우 크기를 줄이거나, 혹은 증가시키지 않으며 혼잡을 회피한다 라는 전제를 깔고 있음

Tahoe와 Reno는 기본적으로 처음에는 Slow Start 방식을 사용,
네트워크가 혼잡하다고 느껴졌을 때는 AIMD 방식으로 전환하는 방법을 사용하는 정책

Tahoe & Reno의 작동 방식

그래프의 Y축은 혼잡 윈도우, X축은 시간으로 하여 Tahoe와 Reno의 작동 방식 설명함.


TCP Tahoe

처음에는 Slow Start를 사용하여 자신의 윈도우 크기를 지수적으로 빠르게 증가시키다가
ssthresh를 만난 이후부터는 AIMD을 사용하여 선형적으로 윈도우 크기를 증가

ACK Duplicated나 Timeout이 발생하면 네트워크에 혼잡이 발생했다고 판단하고,
ssthresh와 자신의 윈도우 크기를 수정함

청록선: cwnd 크기 / 굵은 선: ssthresh 값

혼잡 윈도우 크기는 8로 초기화 되었고, 그에 따라 ssthresh는 4로 설정

  1. 송신 측은 임계점을 만나기 전까지 Slow Start 방식을 사용하여 자신의 윈도우 크기를 증가
  2. ssthresh를 넘어선 이후부터는 선형적으로 증가
  3. 처음 혼잡 상황이 발생한 상태의 혼잡 윈도우 크기는 6임
  4. ssthresh를 3으로 변경 & cwnd 크기를 1로 줄임
  5. 다시 Slow Start로 시작하여 임계점에 도달하면 AIMD를 시작

TCP Reno

TCP Tahoe 이후에 나온 정책으로, Tahoe와 마찬가지로 Slow Start로 시작하여 임계점을 넘어서면 AIMD을 사용.

다만, Tahoe와는 다르게 3 ACK Duplicated와 Timeout 혼잡 상황을 구분한다.

  1. 중복 ACK가 발생했을 때, AIMD처럼 반으로만 줄이고 sshthresh를 줄어든 윈도우 값으로 설정
    👉
    빠른 회복
  2. 타임아웃에 의해서 데이터가 손실되면 Tahoe와 마찬가지로 윈도우 크기를 바로 1로 줄이고 Slow Start 진행
    이때 ssthresh를 변경X
즉, Reno는 ACK 중복은 Timeout에 비해 그리 큰 혼잡이 아니라고 가정하고
혼잡 윈도우 크기를 1로 줄이지도 않는다는 점에서 혼잡 상황의 우선 순위를 둔 정책이라 볼 수 있음

UDP가 흐름/혼잡 제어를 하지 않는 이유 ?

UDP는 기본적으로 흐름 제어나 혼잡 제어를 하지 않음.
그 이유는 UDP의 디자인 목표와 역할에 있음

1. UDP는 단순하고 빠른 전송을 목표로 함

  • 연결 없음(connectionless): 연결 설정 과정 없이 바로 전송
  • 비신뢰성(unreliable): 재전송, ACK 없음
  • 순서 보장 없음: 패킷 순서 보장 X

→ 이런 구조 덕분에 오버헤드가 매우 적고,
실시간성과 속도가 중요한 애플리케이션에 적합


2. 흐름 제어, 혼잡 제어는 “상위 애플리케이션”이 책임짐

TCP와는 달리, UDP는 네트워크의 상태를 감지하거나, 상대의 처리 능력을 고려하지 않음

대신 애플리케이션이 직접 패킷 속도 조절. 손실 감지/복구, 흐름 제어 등을 구현

📌 VoIP, 실시간 게임, 스트리밍 등에서는 약간의 손실보다는 지연 최소화가 더 중요하므로 UDP를 선호함

 3. 혼잡 제어를 하면 “속도”라는 장점이 사라짐

UDP에 TCP처럼 혼잡 제어를 넣으면 RTT 측정, 윈도우 계산, 전송 속도 조절 같은 로직이 들어가야 함
👉 속도 이점이 없어짐

이유 설명
목적이 다름 UDP는 빠르고 단순한 데이터 전송용
책임 분리 흐름/혼잡 제어는 애플리케이션이 직접 처리
성능 우선 지연이 더 중요한 환경 (VoIP, 게임 등)
TCP와 구분 TCP가 이미 혼잡 제어를 제공하므로, 선택 가능성 보장

참고

https://steady-coding.tistory.com/507

 

[네트워크] TCP/IP 흐름 제어 & 혼잡 제어

cs-study에서 스터디를 진행하고 있습니다. 흐름 제어 수신 측이 송신 측보다 데이터 처리 속도가 빠르면 문제가 없지만, 송신 측의 속도가 빠를 경우 문제가 생긴다. 수신 측에서 제한된 저장 용

steady-coding.tistory.com

728x90
'Computer Science/네트워크' 카테고리의 다른 글
  • HTTP 변천사
  • IP
  • TCP & UDP, TCP의 오류 검출과 재전송
  • HTTP & HTTPS
0woy
0woy
Algorithm, CS, Web 등 배운 내용을 기록합니다.
  • 0woy
    0woy dev
    0woy
  • 전체
    오늘
    어제
    • 분류 전체보기 (45) N
      • Backend (4)
        • JAVA (3)
        • DB (1)
      • Frontend (15)
        • HTML5 (1)
        • CSS (1)
        • JS (4)
        • Vue 3 (9)
      • Computer Science (14) N
        • 네트워크 (8) N
        • 운영체제 (5)
      • PS (8)
        • LeetCode (2)
        • Baekjoon (1)
        • Programmers (0)
        • 알고리즘 (5)
      • Dev Trivia (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Vue3
    javascript
    fastretransmit
    select
    https
    java
    set
    l7 스위치
    DP
    DNS
    function
    그래프
    HTTP
    dfs
    JS
    leetcode
    tcp
    list
    Props
    상속
    함수
    map
    html
    암시적그래프
    BFS
    udp
    implicit graph
    속성
    dom
    트리
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
0woy
TCP의 흐름 제어 & 혼잡 제어
상단으로

티스토리툴바