본문 바로가기

전공/네트워크

전송 계층 - TCP 의 모든 것 #2. 흐름제어, ARQ, Sliding Window

반응형

들어가기 전에,

해당 포스팅에선 '메시지'란 단어와 '패킷'이란 단어를 함께 혼용해서 사용했다. 따라서 글을 읽으면서 같은 뜻이라고 이해하고 읽으면 될 것 같다. 그러나, 원래 정의는 메시지는 7계층인 application 계층의 단위이며 이러한 메시지를 전송하기 편하게 잘게 쪼개놓은 것을 packet인 것을 염두하자.

 

TCP는 흐름제어를 통해 메시지 전송을 보장한다.

흐름제어란 송신자[Sender]가 메시지를 보내는 속도가 수신자[Receiever]가 메시지를 처리하는 속도보다 빠를 때, 수신자의 메시지 함은 점점 차게 되고 결국 FULL 상태가 된다. 메시지 함이 꽉찬 상태에서 메시지를 더 받게되면 더 이상 저장할 공간이 없기 때문에 메시지를 버려야 하는 상황이 온다. 이를 '오버플로우[Overflow]'라 한다. 이러한 오버플로우 현상을 방지하기 위해 송신자와 수신자 사이에 속도를 맞춰주는 것을 흐름제어라고 한다.

TCP의 흐름제어 방식은 Window Sliding이다. 

수신자가 한번에 받을 수 있는 메시지의 개수를 제한하는 것이다. 그리고 제한된 이 메시지 개수를 Window라 한다. 예를 들어 Window 크기가 5라면, 수신자의 메시지함에는 최대 5개의 메시지만 보관될 수 있다. TCP는 이 Window 개수를 이용해서 수신자에게 앞으로 보낼 수 있는 메시지의 양을 계산한다. Window 크기가 0이 되면 송신자는 전송을 멈추고 대기한다. 이 개념을 Window Sliding라고 한다.

앞서 TCP는 흐름제어를 통해 메시지 전송을 보장한다고 하였다. 수신함에 들어갈 수 있는 메시지 크기를 예측하여 오버플로우 현상이 일어나지 않도록 조절하기 때문에 메시지는 버려질 일이 없다. 따라서 메시지 전송을 보장할 수 있다. 

이러한 Window Sliding 방식을 실용화하여 사용되는 알고리즘으로는 Stop&Wait, Go-Back-N[GBN], Selective Repeat[SR] 방식이 있다. 이러한 알고리즘을 완벽하게 이해하기 위해서는 ARQ를 이해하고 있어야 한다. ARQ를 먼저 살펴보자

신뢰적인 데이터 전송을 위해 TCP는 자동 재전송 요구[Automatic Repeat reQuest, ARQ]를 수행한다. ARQ란 수신자가 메시지를 받으면 송신자에게 "잘 받았어"라고 피드백을 보내주는 기능이다. 이 "잘 받았어"란 피드백을 위해 ACK 또는 "못 받았는데"란 피드백을 위해 NAK가 사용된다. (또한 ARQ는 비트오류 발생 시, 수신자가 검출할 수 있도록하는 체크섬 기능도 포함이지만 여기서는 다루지 않는다.) ACK와 Timeout 개념을 모른다면 이 개념을 알고와야 포스팅 다음 내용을 이해할 수 있다. 

이제 Window Sliding 방식과 ARQ가 무엇인지 알았다. 이것을 기반으로 TCP는 어떻게 메시지 전송을 보장하는지 살펴보자. 

1. Stop&Wait 방식

가장 직관적이고 기본적인 방식이다. 송신자는 메시지를 1개 보내고 대기(STOP)하고 피드백이 올 때까지 기다리는(WAIT)하는 방식이다. 

메시지 유실 발생하지 않은 상태

  1. 송신자[Sender]는 메시지인 pkt0 을 보낸다. 
  2. 수신자[Receiver]는 pkt0를 잘 받았다는 피드백인 ack0을 보낸다.
  3. 송신자는 ack0을 보고 '아하 pkt0이 잘 도착했구나, 이제 다음거를 보내야지'하고 pkt1를 전송한다.
  4. 수신자는 pkt1를 잘 받았다는 피드백인 ack1을 보낸다.
  5. 이하 반복

 

송신자가 보낸 pkt1이 유실되었다.

  1. 송신자[Sender]는 메시지인 pkt0 을 보낸다. 
  2. 수신자[Receiver]는 pkt0를 잘 받았다는 피드백인 ack0을 보낸다.
  3. 송신자는 ack0을 받고 pkt1을 보냈다. 그러나 해당 패킷 pkt1이 전송되던 중 유실되었다.
  4. 수신자는 pkt1을 받지 못했다. 수신자 입장에서는 이게 사라진건지 아니면 송신자가 보내지 않은건지 알 수 없다.
  5. 송신자는 일정시간 동안 ack1을 기다린다. 일정시간 이후에 해당 패킷에 문제가 생겼음을 알고 pkt1을 재전송한다.
  6. 수신자는 pkt1을 받고 피드백인 ack1을 보낸다.

메시지를 잘 받았다는 피드백인 ACK1이 사라졌다.

  1. 송신자가 메시지인 pkt1을 보낸다.
  2. 수신자는 pkt1에 대한 피드백인 ack1을 보낸다. 그러나 이 ack1 메시지가 전송되는 도중에 유실되었다.
  3. 송신자 입장에서는 ack1이 오지 않는다. 일정시간동안 ack1을 기다리다가 일정시간 후 pkt1을 재전송한다.

상황2에서는 메시지(=pkt)가 사라졌고 상황3에서는 피드백(=ack)가 사라졌다. 그러나 송신자는 사라진 것이 메시지인지 피드백인지 구분할 길이 없다. 따라서, 이 둘 상황을 구분하지 않고 그냥 재전송할 뿐이다.

타임아웃이 너무 빠른 경우/ACK가 지연된 경우

이 상황에서 유실된 것은 없다. pkt와 ack는 모두 잘 전송되었지만, 다만 대기하는 시간이 너무 짧았거나 메시지가 지연된 경우다.

  1. 송신자가 메시지인 pkt1을 보낸다.
  2. 수신자는 pkt1에 대한 피드백인 ack1을 보낸다. 그러나 이 ack1 메시지는 지연되어 전달된다.
  3. 송신자는 일정시간을 기다려보지만 ack1이 오지 않는다. 송신자는 이 ack1이 지연된건지 유실된건지 알 길이 없다. 따라서 일정시간 안에 안오면 다시 재전송한다.
  4. 수신자는 pkt1을 또 다시 수신받는다. 그러나 pkt1은 이미 받은 적이 있기 때문에 해당 메시지를 버린다.

 

해당 Stop&Wait 은 하나를 보내고 기다리는 방식을 취한다. 이러한 방식은 하나씩 주고받기 때문에 느릴 수 밖에 없다. 따라서 파이프라인을 이용하여 여러 패킷을 한번에 보내고 기다리는 방식을 취한다. 이때 한번에 보낼 수 있는 패킷의 개수가 앞에서 배웠던 Window 크기가 된다. 파이프라인을 통해 성능이 개선될 수 있다. 다음은 성능 계산법이다.

데이터를 하나씩 주고받는 방식에서의 성능

 

파이프라이닝을 활용했을 때의 성능

여기서의 L은 메시지 길이인 Length를 뜻하고 R은 Rate으로서 네트워크 위의 전송률을 뜻한다. RTT는 데이터가 송수신되는 왕복 시간(Round Trip Time)을 의미한다.

 

이처럼 Window 사이즈는 파이프라인 기법에서 사용된다. 이를 활용하는 가장 유명한 프로토콜인 GBN과 SR을 알아보자

 

1. GBN[Go-Back-N]

GBN은 메시지 하나를 보낼 때마다 윈도우 크기를 하나씩 감소한다. 그러다 윈도우 크기가 0이 되면 대기한다. 그 후, 수신자로부터 피드백(ACK)을 받을 때마다 윈도우 크기를 하나씩 늘리는 프로토콜이다.

GBN은 누적 ACK [Accumulate ACK] 방식을 택한다. 누적 ACK란 수신자 측에서 받은 n을 포함하여, n까지의 pkt에 대한 확인 응답이란 뜻이다. 예시를 보면서 이해하자.

윈도우 크기가 4일 때 GBN 프로토콜

윈도우 최대 크기는 4다. 따라서 송신자는 ACK없이 최대 4개의 메시지를 보낼 수 있다. 

송신자는 메시지를 하나 보낼 때마다 윈도우는 -1 씩 된다. 따라서 메시지를 4개 보낸 이후엔 윈도우가 0이 되기 때문에 더 이상 전송할 수 없고 대기한다.

이때 pkt2가 분실된다. pkt1까지는 정상으로 받았기 때문에 송신자는 "내가 제대로 받은건 pkt1까지야." 라는 피드백으로 ack1을 계속 재전송한다. 

수신자가 보낸 ack1이 송신자에게 전달되었다. 이때 윈도우는 다시 +1이 되었기 때문에 송신자는 pkt4와 pkt5까지 전송한다. 그러다 일정시간 이후 ack2에 Timeout이 발생한다. 그제서야 pkt2를 재전송하고, 그 이후에 보냈었던 pkt3~pkt5를 다시 전송한다.

여기서 주목해야할 것은 다음과 같다.

  • 메시지를 하나 보낼 때마다 윈도우는 -1이 된다는 것, ACK를 하나 받을 때마다 윈도우는 +1이 된다는 것
  • 중간에 메시지가 유실되었을 경우 그 뒤에 오는 메시지는 다 버리고 재전송해야 하기에 비효율적으로 보인다.

 

이러한 비효율성 문제를 해결하기 위해 나온 것이 다음 소개할 SR 프로토콜이다.

 

2. 선택적 반복 [Selective Repeat, SR]

SR 프로토콜은 오류가 발생한 패킷만 재전송함으로써 불필요한 재전송을 피한다. GBN에선 누적 ACK를 사용했지만 SR에선 올바르게 온 패킷에 대해서만 

SR은 순서가 틀리게 온 메시지는 버퍼에 저장한 다음, 올바른 순서의 패킷이 오면 버퍼에서 이전에 받았던 메시지들을 꺼내서 순서를 조합한다. 

윈도우 크기가 4일 때 SR 프로토콜

윈도우 크기는 4기 때문에 송신자는 처음에 4개의 메시지를 연속없이 보낸다. 하나 보낼 때 마다 윈도우가 줄기 때문에 메시지 4개를 보낸 후 윈도우는 0이 된다. 따라서 송신자는 ack를 받을 때까지 대기한다.

그러나 송신자가 보낸 pkt2가 분실되었다. 이 상황을 수신자 입장에서 보자. pkt2가 올 차례지만 pkt3이 왔다. 수신자는 pkt3을 버퍼에 임시 보관한 후 ack3을 보낸다. 아까 GBN과의 차이점이 보이는가? 누적 ACK를 택하는 GBN 프로토콜에선 ack1를 보냈지만 SR에선 ack3을 보낸다. 

pkt2에 대한 ack2가 안와 timeout이 발생했다. 따라서 송신자는 pkt2를 재전송한다. 수신자는 pkt2를 받은 후, 버퍼에 있었던 pkt3, pkt4, pkt5를 꺼내서 추가적으로 처리하고 ack2를 전송한다. 송신자는 그 다음 패킷인 pkt 6을 보낸다.

 

GBN과의 차이점이 보이는가?

  GBN SR
ACK 방식 누적 ACK
패킷 1,2,3,4,5 중에 3이 분실되면 패킷 4, 5에 대한 ACK도 2다.
정상적으로 도착한 패킷에 대해 각각 ACK
패킷 1,2,3,4,5 중에 3이 분실되도 패킷 4,5 에 대한 ACK는 각각 ACK 4,5다.
순서가 다른
패킷 처리
순서가 틀리면 그 뒤에오는 패킷은 모두 버린다.
따라서 그 뒤에 패킷들도 모두 재전송되어야 한다.
순서가 틀리면 그 뒤에온 패킷은 모두 버퍼에 저장한 다. 따라서 그 뒤에 패킷들에 대한 재전송은 필요하지 않다.

 

그러나 좋아보이기만 하는 SR에도 딜레마가 존재한다.

윈도우 크기가 3인 SR 프로토콜

우리가 사용할 수 있는 Sequence 번호는 매~우 한정적이다. 오직 0,1,2,3 밖에 없다고 가정해보자. (Sequence 번호 = pkt#, 즉 pkt 뒤에 붙는 숫자) 이때는 해당 시퀀스 번호를 재활용해야 한다. 실제로 윈도우 크기가 굉장히 클 경우 해당 상황이 발생할 수 있다. (여기서 패킷 0,1,2,3을 보내고 또 다시 전송되는 pkt0은, 이전에 보냈던 pkt0과는 완전 다른 데이터다. 시퀀스 번호가 부족하기 때문에 시퀀스 번호만 중복 사용할 뿐이고 데이터 자체는 같지 않다. 헷갈리지 말자)

윈도우 크기가 3이다. 송신자는 3개의 메시지를 한번에 전송한다. 그 후 ack를 받고 pkt3을 전송하지만 분실되고 pkt0은 정상적으로 전달된다. 이때 수신자는 pkt0은 그 다음으로 오는 패킷이라는 것을 알고 처리하기 때문에 문제가 없다.

 

 

뭔소리인지 이해가 잘 안되면, 해당 상황과 비슷한 아래 시나리오를 보자

윈도우 크기가 3인 SR 프로토콜

pkt0,1,2가 모두 수신자에게 잘 전달되었고 수신자는 이에 따른 피드백인 ack0,1,2를 전송한다. 그러나 ack0,1,2가 모두 분실되어 버린다..! ack를 받지 못한 송신자는 각 패킷에 대해 timeout이 발생한다. 따라서 아까 전송했던 패킷인 pkt 0,1,2를 또 다시 재전송한다. 

그러나 수신자 입장을 보자. 수신자는 이전에 pkt0,1,2를 받았고 이에 따라 ack0,1,2도 받았다. 그런데 그 뒤에 오는 이 pkt0 이라는 메시지가 이전에 온 데이터가 재전송 된건지 아니면 완전 새로운 데이터가 온 것인지 알 방법이 없다. 따라서 수신자는 해당 데이터를 정상적으로 처리해버리지만, 이 데이터는 중복된 데이터기 때문에 잘못된 처리방식인 것이다.

앞의 시나리오와 뒤의 시나리오는 엄연히 다른 상황이지만, 수신자 입장에서는 이를 구분할 방법이 없다는 것이 SR의 딜레마다.

 

 

- GBN vs SR

TCP는 그럼 GBN 또는 SR 중 어떤 것을 사용할까? TCP는 사실 GBN과 SR을 혼합하여 사용한다. 

 

반응형