TCP의 흐름제어와 동작 방식의 문제점

date
Apr 5, 2024
slug
tcp-flow-control
status
Published
tags
Network
summary
TCP의 흐름제어에 대해 간단히 알아보고 TCP의 동작 방식이 어떤 문제를 발생시킬 수 있는지 알아봅니다.
type
Post

TCP(Transmission Control Protocol)란?

먼저, TCP(Transmission Control Protocol)은 OSI 7 Layer 기준 4계층의 프로토콜로서, byte 단위로 통신하는 유일한 프로토콜입니다. 또한, TCP는 수신자와 송신자 간에 연결을 맺고 지속적으로 통신하는 연결지향형 프로토콜이며, UDP와는 다르게 흐름제어, 에러검출 및 제어 등을 수행합니다.
 
그러나, TCP는 네트워크가 느리고 불안정하던 과거에 만들어진 프로토콜이기 때문에, 현재는 다소 비효율적인 동작 방식을 가지고 있습니다. 따라서, 본 글에서는 TCP의 흐름제어에 대해 간단히 알아보고 TCP의 동작 방식이 어떤 문제를 발생시킬 수 있는지 알아봅니다.

TCP의 흐름제어

notion image
위 그림은 클라이언트가 서버에게 단방향으로 데이터를 전송하는 상황을 가정하고, TCP의 흐름제어를 나타낸 그림입니다.
이를 글로 설명하면 아래와 같습니다.
[연결 성립 단계]
  1. 연결을 시작하고자 할 때, Client는 SYN에 임의의 seqNo를 담아서 Server에게 연결 수립을 요청합니다.
  1. Server는 이에 대한 응답으로 ackNo와 Server의 인 rwnd(Server 가용 버퍼 사이즈)를 보냄과 동시에, 본인도 연결 요청을 위해 seqNo를 함께 담아 SYN + ACK 를 Client에게 전달합니다.
  1. Client는 Server에서 받은 SYN의 응답으로 ackNo와 함께 rwnd(Client 가용 버퍼 사이즈)를 ACK 에 담아 응답합니다.
위의 (1)~(3) 까지를 우리는 흔히 3-way-handshaking 이라고 부릅니다. 연결이 모두 성립되었으면, 서버와 클라이언트는 본격적으로 데이터를 주고받기 시작합니다.
 
[데이터 송수신 단계]
  1. 연결이 수립되었으니, Client는 서버에서 받은 rwnd 보다 작은 사이즈의 데이터를 Server에게 전송합니다. 이 때, seqNo에는 전달되는 데이터의 첫번째 byte number를 포함합니다.
  1. 수신 버퍼에 데이터를 받은 Server는 "잘 받았다"는 의미의 ACK와 함께, 다음으로 받고자하는 데이터의 byte number(ackNo)와 남은 가용 버퍼 사이즈(800 - 200 = 600)을 담아 응답합니다.
  1. ACK 로 송신이 정상적으로 이루어졌음을 확인한 Client는 본인의 송신 버퍼에서 잘 전달된 데이터를 삭제하고, 새로운 데이터를 전송합니다.
  1. Server는 5번과 마찬가지로 ACK에 ackNo와 rwnd를 넣어 응답합니다.
  1. Server의 상위 레이어에서 수신 버퍼의 데이터를 소비(consume)하면, Server는 본인의 rwnd를 업데이트 해 ACK를 재전송합니다. (그림의 8번)
위의 내용처럼, TCP에서는 서버가 rwnd를 ACK에 넣어 함께 전달함으로써, 클라이언트가 데이터를 소비하는 속도보다 서버가 데이터를 전송하는 속도가 빨라지지 않도록 흐름제어(Flow control)을 하게됩니다.

정상 동작 시 TCP의 문제점

그러면, 이제부터 TCP의 고유한 동작 방식으로 인해 발생하는 문제점을 알아보겠습니다.   먼저, 정상적으로 데이터가 전달될 시 일어나는 TCP의 문제를 살펴봅시다.
notion image
위의 그림에는 ACK-delaying timer가 등장합니다. ACK-delaying timer는 수신자가 수신한 데이터에 대해서 매번 ACK를 보내지 않고 일정시간을 지연시킨 후, 한 번에 ACK를 전달하는데에 사용됩니다.   첫 번째 예시(최상단 파란 박스)에서는 Client가 4001-5000번 바이트를 전달 받은 이후, 500ms 동안 대기하다가 ACK를 전송하는 모습을 볼 수 있습니다. 두 번째 예시(하단의 2개의 파란 박스)에서는 Client가 5001-6000번 바이트를 받은 후 ACK를 보내지 않고 대기하다가, time-out 전에 도착한 6001-7000번 바이트까지 잘 받았다는 ACK 응답을 보내는 것을 확인 할 수 있습니다.
 
이를 통해 Server는 하나의 ACK 응답으로 두 번의 송신이 잘 이루어졌음을 확인할 수 있습니다. 이는 Server로 하여금 여러번 ACK를 처리하지 않도록 도와주어 Server의 프로세싱 부하를 줄여준다는 장점이 있습니다.
 
그러나, 이는 다음과 같은 문제를 유발합니다.
  1. Client는 한 번의 데이터만 수신하더라도, 반드시 ACK-delaying time만큼 시간을 지연시킵니다.이는 네트워크의 속도가 느리던 과거에는 합리적인 방법이었지만, 네트워크의 속도가 현저히 빠른 현재로서는 불필요한 지연시간을 발생시킵니다.
  1. 흐름제어를 위해서, 송신자는 ACK 응답을 받기 전까지는 데이터를 다시 전송할 수 없습니다.자세히 설명하자면, 수신자가 데이터를 잘 받았다는 것을 나타내는 ACK에 포함 된 rwnd를 통해서 송신자는 다음 세그먼트의 크기를 결정하기 때문에, ACK-delaying time 동안 송신자도 데이터를 전송하지 못하고 있는 상황이 발생하게 됩니다.
 
따라서 이는 다음과 같은 방법으로 개선할 수 있습니다.
  1. Timer 시간 줄이기: 단순하게 ACK-delaying time을 줄인다면, 수신자는 더 빠른 시간내에 ACK 응답을 보낼 수 있게되고, 송신자는 더 짧은 간격으로 데이터를 전송할 수 있습니다.
  1. 수신버퍼 사이즈 키우기: 수신자의 버퍼 크기를 증가시키면, 수신자는 한 번에 더 많은 데이터를 받아들일 수 있습니다. 이는 수신자가 더 많은 데이터를 처리할 수 있게 하고, rwnd 값이 더 크게 설정되어 송신자는 더 많은 데이터를 연속적으로 보낼 수 있습니다.
 
다만, 더 많은 ACK 응답을 처리하는 것과 더 큰 크기의 데이터를 한 번에 처리하는 것은 기존보다 더 많은 프로세싱 부하를 가져오기에, 양측 모두 더 좋은 성능의 프로세서를 사용해야할 필요가 있습니다.
 

© Daehwi Kim 2025