이 글은 이화여자대학교 이미정 교수님의 2014년 2학기 컴퓨터 네트워크 강의를 기반으로 재구성한 것입니다. 삽화는 링크를 출처로, 저작권은 J.F Kurose and K.W. Ross에게 있다는 것을 밝힙니다.
Transport Layer에서는 아래와 같은 내용들을 살펴본다.
- transport layer service principle
- multiplexing, demultiplexing
- UDP : connectionless transport
- TCP: connection oriented reliable transport
- reliable data transfer
- connection, disconnection
- flow control, congestion control
- performance
TCP에 관한 내용은 1%의 네트워크 - 2. OS Protocol Stack과 LAN Adapter 포스팅에도 작성되어 있다. 겹치는 부분이 꽤 많으므로 필요 시 참고하면 좋다.
TCP의 특징
- reliable data transfer
- in-order byte steam : TCP의 경우 UDP와 다르게 data 송/수신 전에 buffer에 넣는다. 때문에 모든 data들을 순서 있는 byte stream으로 본다.
- connection oriented : 통신 전에 handshake 과정을 거쳐 session을 만든다.
- point to point : server와 client가 1:1이다.
- full duplex : server와 client가 서로 message를 보낼 수 있고, 받을 수 있다.
- pipelined (flow control) : throughput을 높이기 위해 비동기로 계속 보낸다. 이 때 제한 없이 보내면 receiver buffer overflow가 일어나므로, 이러한 현상이 일어나지 않는 한도 내에서 계속 보낸다.
- congestion control
Reliable Data Transfer
통신이 reliable하기 위해서 필요한 것들은 다음과 같다.
- checksum : 이전 포스팅에서 설명했다.
- ACK : packet을 잘 받았다는 응답으로, sender에게 보낸다. ACK는 아래 2가지 용도로 사용할 수 있다.
- 보낸 packet을 잘 받았다.
- 보낸 packet과 그 전 packet을 모두 잘 받았다.
- N-ACK : packet을 잘 못받았다는 응답으로, web에서는 사용하지 않는다.
- timer : ACK만으로는 reliable하지 않다. (network에서 packet이 사라지거나 지연 등의 문제로 ACK가 오지 않을 수도 있다.) 때문에 ACK를 돌려받는 시간 제한을 두어 그 안에 ACK가 오지 않았다면 packet이 잘 도착하지 않은 것으로 간주하고 재발송한다.
- timer timeout에 의해 receiver는 받았던 packet을 또 받을 수도 있는데, 그 경우는 그냥 버린다.
- sequence : packet id라고 생각하면 편하다. 받은 packet을 또 받을 수 있기 때문에, 받은 적 있는 packet인지 판단하기 위해 사용한다. 또한 packet의 순서도 보장해줄 수 있다.
- window : data 송/수신을 비동기로 사용하는데, 이 때 ACK를 받지 않고 한 번에 보낼 수 있는 data의 양을 말한다. receiver buffer overflow를 막기 위해 사용한다.
- sender가 packet을 보내고, ACK를 받은 후 다음 packet을 보내는 방식은 비효율적이기 떄문이다.
TCP header
TCP header는 위와 같이 생겼다. UDP와는 다르게 내용이 굉장히 많다. fixed header만 해도 4byte * 5줄이므로 20byte이고, 거기에 dynamic header인 option까지 붙으면 20 + a byte가 된다.
- port : multiplexing과 demultiplexing을 위해 존재한다.
- TCP의 경우 [source IP address, source port, destination IP address, destination port] 4개 정보를 이용해 multiplexing/demultiplexing한다.
- sequence number : payload에 있는 data가 전체 data 중 몇 번째 byte인지를 의미한다.
- handshake 과정에서 초기 sequence 값을 통보하며, 이 값을 사용해 해당 payload가 몇 번째 byte인지 식별한다.
- acknowledge number : 상대방이 보낸 data에 대한 ACK를 의미하며, 요청하는 data의 sequence number를 이 곳에 넣는다.
- 예를 들어 acknowledge number가 n인 경우 n-1 byte까지는 잘 받았고, 다음으로 sequence number가 n인 packet을 달라는 것을 의미한다.
- receive window : flow control을 위한 field로, ACK를 받지 않아도 계속 전송 가능한 segment의 양을 의미한다. (receiver에게 여유 buffer size)
- checksum : 오류 감지를 위해 사용하며, UDP checksum과 동일하다.
- flag bit : 총 6개가 있다.
- RST : connection을 reset할 때 사용한다.
- SYN : connection을 만들 때 사용한다. (첫 연결/handshake 시 사용한다.)
- FIN : 연결을 끊을 때 사용한다.
- ACK : ACK number가 유효함을 의미한다.
- Push : 사용하지 않는다. TCP의 경우 모든 data를 buffer에 잠시 넣는데, 이 flag가 true라면 buffer를 flush하라는 의미를 가진다.
- Urgent : 사용하지 않는다. 해당 flag가 true라면 급한 정보가 있으므로 buffer를 flush하고 해당하는 data를 바로 application layer로 올려준다.
예시
위 예시는 sender가 보낸 packet들을 의미한다. 초록색은 ACK를 받은 것, 노란색은 보냈지만 ACK를 받지 않은 것, 파란색은 application layer가 아직 생성하지 않은 것, 회색은 사용하지 못하는 부분을 의미한다.
이 때 application layer에서 새로운 data가 들어왔다면 위와 같이 sequence number를 설정한 packet을 보내야 한다.
만약 receiver로부터 ACK number가 있는 packet이 돌아왔다면 노란 부분에 속할 것이다.
TCP timer
앞서 reliable data transfer를 위해서는 timer가 필요하다고 했다. 그러나 TCP header는 timer가 없으므로, 별개로 다루어야 한다.
network에서 packet이 사라지거나 지연 등의 문제로 ACK 응답이 오지 않을 수도 있기 때문에 ACK만으로는 reliable을 보장할 수 없다.
timer는 RTT, Round Trip Time과 매우 깊은 관련이 있다. 만약 RTT만큼 지났는데도 답신이 오지 않았다면 문제가 있다는 것을 의미한다. 그러나 RTT를 어떻게 알 수 있는가? 때문에 예측해야 한다. 그러나 정확하지 않은 예측을 할 경우에 아래와 같은 문제가 생긴다.
- 예측값이 너무 짧은 경우 - 재전송하기 때문에 필요없는 전송이 발생한다. (resource 낭비)
- 예측값이 너무 긴 경우 - packet이 사라졌지만 재전송까지 시간이 너무 오래 걸린다.
때문에 잘 예측해야 하며, 예측을 위해 sender가 보낸 segment에 대한 ACK가 돌아올 때마다 sampling하며, 평균을 구한다.
- 이 때 재전송된 segment와 ACK 응답은 sampling하지 않는다. 원래 보낸 segment의 ACK인지, 새로 보낸 segment의 ACK인지 모르기 때문이다.
추정치
EstimatedRTT = (1-α)*EstimatedRTT + α*SampleRTT
추정치 EstimatedRTT는 위 수식을 사용해 구한다. 우변의 좌항은 전 단계까지 추정치를, 우항은 새 sample의 RTT를 의미한다. 보통 α는 0.125를 쓴다.
- 이 수식을 사용할 경우 오래된 추정치일수록 반영치가 exponential하게 감소한다.
Safety Margin
그러나 estimated RTT만으로는 실제 값과 차이가 너무 크기 때문에 여기에 추가로 safety margin을 더하며, 아래와 같이 전체 timeout interval을 설정한다. safety margin을 사용하면 network 상황에 따라 dynamic하게 추정치를 바꿀 수 있다.
TimeoutInterval = EstimatedRTT + 4*DeviationRTT
DeviationRTT가 큰 경우에는 safety margin을 크게, DeviationRTT가 작은 경우에는 safety margin을 작게 설정한다.
DeviationRTT = (1-β)*DeviationRTT + β*|SampleRTT-EstimatedRTT|
DeviationRTT는 위와 같이 SampleRTT와 EstimatedRTT의 deviation을 사용해 구하는데, 보통 β는 0.25를 쓴다.
TCP의 동작
TCP sender events
TCP sender는 크게 3가지 event가 존재하며, 각각에 따른 동작은 다음과 같다.
- application layer에서 data를 받은 경우
- sequence number, checksum 등의 header를 붙여 segment를 만든다.
- 만약 timer가 돌고 있지 않다면 돌린다.
- timer가 돈다는 뜻은, 이전에 보냈지만 ACK를 수신하지 않은 segment가 있다는 뜻이므로 내버려둔다.
- timer가 돌고 있지 않다는 뜻은 이 segment가 oldest unacked segment이므로, timer를 돌린다.
- timeout이 발생하는 경우
- 해당 segment를 재전송하고 timer를 재시작한다.
- ACK를 수신한 경우
- in flight인 상태인 segment를 acked로 변경한다. (receiver에게 전달되었다고 정보를 갱신하는 것이다.)
- 추가로 oldest in flight segment (oldest unacked segment)의 timer를 설정한다.
timer는 oledst unacked segment에 대해 동작한다.
in flight segment는 sender가 발송했지만 아직 ACK 응답을 받지 않은 segment를 의미한다.
예시
A가 sender, B가 receiver라고 보면 된다.
- 제일 왼쪽 - sender가 packet를 보내고, receiver가 응답했지만 응답 packet이 사라진 경우 : sender는 receiver가 packet을 받지 못했다고 생각하고, 다시 보낸다.
- 가운데 - sender가 packet을 보내고 receiver가 응답했지만 timeout에 의해 재전송이 발생한 경우 : receiver는 이전까지 다 잘 받았다는 응답, 제일 최근의 ACK값을 재전송한다.
- 제일 오른쪽 - sender가 packet을 2개 보내고, receiver가 둘 다에 응답했지만 첫 번째 응답이 사라진 경우 : 이 때는 재전송이 일어나지 않는다. ACK는 cumulative이기 때문에 ACK=120을 수신한 것으로 "receiver가 120까지 잘 받았구나"라고 생각한다.
TCP receiver event
TCP receiver는 크게 4가지 event가 발생한다. 모두 segment를 받았을 때 event가 발생한다.
- segment를 받았고, 순서가 맞는 경우 : ACK 응답을 보내지 않은 것이 있는지 유무에 따라 2가지 event가 있다.
- ACK 응답을 보내지 않은 것이 없는 경우 : 500ms정도 기다리고, 다른 segment가 오지 않으면 ACK를 보낸다. 기다리는 이유는 segment가 연속적으로 오는 경우가 많기 때문이다. 최대한 overhead를 줄이기 위해 이러한 방식을 사용하며, 만약 추가적인 segment가 오면 cumulative ACK를 사용해 제일 최근의 ACK를 보내면 된다. 만약 새로운 segment가 들어오면 바로 ACK 응답을 보낸다.
- ACK 응답을 보내지 않은 것이 있는 경우 : 바로 ACK 응답을 보낸다.
- segment를 받았지만 순서에 맞지 않은 경우 : 예를 들어 기존 ACK가 n인데 sequence가 n+2 이상인 segment를 받은 경우이다. 이 경우 ACK를 n으로 설정해 재전송하며, 이를 duplicated ACK라고 한다.
- ACK는 받기 원하는 값을 보낸다.
- 순서에 맞지 않는 segment를 유지할지 말지는 application이 결정한다.
- 순서에 맞지 않은 segment가 온 상황에서 순서가 맞는 segment를 받는 경우 : 말이 어렵다. 예시로 설명하면 sequence가 n, n+100, n+200, n+300 순서대로 와야 하지만 n, n+300인 segment만 받은 경우에서 sequence가 n+100인 segment를 받은 경우이다. (쉽게 설명하면, 중간에 gap이 있는 상황에서 순서가 맞는 segment를 받은 상황이다.) 이 경우에는 바로 ACK를 보낸다.
- sequence가 n, n+300인 segment를 받은 상황에서 sequence가 n+200인 segment를 받은 경우는 이 case가 아니라 [순서에 맞지 않은 segment를 받은 경우]이다.
TCP fast retransmit
일반적으로 TCP timeout은 굉장히 길기 때문에 loss가 발생했을 때 복구에 오랜 시간이 걸린다. 이를 해결하기 위해 fast retransmit를 사용하며 3번의 duplicated ACK를 받는 경우 해당 segment를 재전송하는 것을 말한다.
위 예시를 보자. sender host가 총 5개의 packet을 보냈는데 sequence가 100인 packet만 사라졌다. 이 경우 바로 위의 TCP receiver event에서 [순서에 맞지 않은 segment를 받은 경우]에 해당하며, duplicated ACK를 sender에게 보내며, 이 경우가 3번 발생한다. 그러면 sender host는 packet이 사라졌음을 감지하고 재전송한다.
TCP connection : 3 way handshake
TCP는 3 way handshake라는 과정을 거쳐 connection을 만든다. 이는 TCP에서 매우 중요한 과정이며, 이 때 초기 sequence number나 window 값들을 교환한다.
2 way handshake를 사용하지 않는 이유
위 그림은 2 way handshake의 실패 예시이다.
왼쪽 그림을 보자. client가 server에게 connection 요청을 보냈지만 답이 너무 늦게 와서 재전송했는데, 모종의 이유로 재전송 요청이 connection이 끊긴 후에 도착했다고 가정하자. 그러면 server는 client가 없음에도 connection을 생성한다.
오른쪽 그림은 좀 더 극단적인 예시를 보여준다. connection 요청과 data 전송 모두 connection이 끊긴 후에 도착할 수도 있다.
이처럼 2 way handshake의 경우 server와 client가 서로의 상황을 확실하게 알 수 없기 때문에 문제가 생긴다.
3 way handshake
client가 server에게 connection 요청을 보내는 상황을 가정하고 순서를 보자.
- client가 server에게 연결 요청을 보낸다. - 이 때 SYN bit를 1로 설정하고 초기 sequence 값을 통보한다. (이 때 sequence는 client가 사용할 sequence이다.)
- server가 OK 응답을 보낸다. - SYN bit를 1로 설정하고 초기 sequence값을 통보한다. (이 때 sequence는 server가 사용할 sequence이다.) 추가로, client가 보낸 요청을 잘 받았다는 의미로 ACK bit를 1로 설정하고 client가 보낸 sequence값을 ACK에 담아 보낸다.
- client가 OK에 대한 OK 응답을 보낸다. - server가 보낸 요청을 잘 받았다는 의미로 ACK bit를 1로 설정하고 server가 보낸 sequence 값을 ACK에 담아 보낸다.
- 이 때는 상대에게 보내는 data가 실릴 수도 있으며, 이 경우 sequence값은 초기값 + 1로 설정한다.
이 3가지 과정이 거쳐 server와 client는 서로가 alive임을 보장할 수 있다. server와 client 각각에서 TCP connection이 만들어지는 시점은
- client의 경우 2.를 client가 받았을 때
- server의 경우 3.을 server가 받았을 때
이며, 이 시점은 상대가 alive임을 알 수 있는 지점이기 때문에 해당 시점에 session을 생성한다.
TCP disconnection : 4 way handshake
TCP의 경우 session으로 server와 client가 연결되어 있다. 이 때 연결을 끊고 싶은 쪽이 먼저 disconnect 신호를 보내며, 그 과정은 다음과 같다. 여기서는 client가 연결을 끊는다고 생각하고 flow를 쓰며, 그 역순은 주체만 바꾸면 된다.
- client가 server에게 FIN bit를 1로 만든 segment를 보낸다.
- server가 client에게 요청을 잘 받았다는 의미로 ACK를 보낸다.
- server가 client에게 FIN bit를 1로 만든 segment를 보낸다.
- client가 server에게 요청을 잘 받았다는 의미로 ACK를 보낸다.
이 때, FIN bit를 1로 설정한 segment를 상대에게 보내면 더 이상 data를 보낼 수 없다.
또한, session을 없애는 시점은 다음과 같다.
- server의 경우 자신이 보낸 FIN의 ACK를 받았을 때
- client의 경우 ACK를 보내고 일정시간 이후
예시
- client가 server에게 FIN bit를 1로 설정한 segment를 전송한다.
- 이 때부터 client는 server에게 data를 보내지 못한다.
- server가 받고, ACK를 보낸다.
- 이 때 server는 FIN을 보내지 않은 상태이기 때문에, 아직은 data를 보낼 수 있다.
- server가 자신의 동작을 끝내면 FIN bit를 1로 설정한 segment를 전송한다.
- 이 때부터는 server는 client에게 data를 보내지 못한다.
- client가 받고, ACK를 보낸다.
- server가 ACK를 보낸 내용을 받고, session을 close한다.
- client는 ACK를 보내고 [2*segment lifetime]만큼 기다린 이후 session을 close한다.
- client의 ACK가 network에서 사라진 경우, server는 자신의 FIN segment에 문제가 생겼다고 판단한 후 재전송한다. 만약, 이런 일이 발생했는데 client가 session을 기다리지 않고 바로 close하는 경우는 회신이 돌아오지 않기 때문에 server session이 계속 열린 상태로 유지된다. 때문에 client에게 계속 FIN을 보내지만 client session은 닫혀있으므로 의미없는 통신이 일어나게 된다. 이런 경우를 대비하기 위해 timed wait를 한다.
TCP Flow Control
TCP의 경우 받은 segment를 바로 application layer에게 주는 것이 아니라 socket buffer에 넣는 방식을 선택한다. 이 때 segment가 너무 많이 도착하면 buffer가 터지고 packet loss가 발생하기 때문에 이를 막기 위해 flow control을 사용한다.
구체적으로는 window라는 값을 사용해 buffer가 넘치지 않게 한다. 3 way handshake 과정 등 receiver가 sender에게 packet을 전달할 때 window를 전달하는데, 이는 receiver buffer의 free size이다. (rwnd값) sender는 이 값을 보고 packet을 전송할 때 rwnd를 초과하지 않을 만큼만 packet을 전송한다. 즉, in flight segment data sum이 window를 초과하지 않게 packet을 보낸다는 뜻이다.
socket buffer는 socket을 생성할 때 OS가 할당하며 default로 4096byte를 할당한다.
TCP Congestion Control
congestion은 network가 너무 바쁜 경우 발생하며, delay, 심한 경우 packet loss가 발생한다.
- λ$_{\text{in}}$ :application이 생성한 packet
- λ'$_{\text{in}}$ : 재전송으로 인해 실제로 전송하는 packet
- λ$_{\text{out}}$ : receiver가 실제로 필요한 packet
- c : bottleneck link bandwidth
위와 같이 symbol을 쓰자.
처음에는 λ$_{\text{in}}$가 커질수록 λ$_{\text{out}}$이 증가하지만 어느 순간부터는 λ$_{\text{out}}$이 0에 수렴한다.
재전송률이 낮을 때는 λ$_{\text{out}}$가 증가하지만, congestion이 발생하면 delay로 인해 불필요한 재전송이 계속 발생하기도 하고 packet loss도 일어나므로 network는 계속 packet을 옮기지만 필요없는 일만 하게 된다.
Congestion Control 접근 2가지
congestion은 network 내에서 발생하지만 end system으로 알려주냐, 마냐에 따라 2가지로 나뉜다.
- end-end congestion control : congestion을 end system으로 알리지 않는 방법으로, TCP가 사용한다. end system이 loss와 delay를 바탕으로 congestion을 감지해야 한다.
- internet은 packet 전달만 하고 나머지 복잡한 것들은 edge로 모은다는 철학 때문에 이러한 방식을 사용한다. TCP도 internet이기 때문에 이 방식을 사용한다.
- network assisted congestion control : congestion은 network 안의 router에서 일어나며, 해당 router가 host에게 문제를 알리는 방식이다. 알릴 때도 congestion 유무만 알리는 single bit, 얼만큼 packet을 줄여야 하는지 알려주는 explicit rate 2가지 방식이 있다.
TCP Congestion Control
그러면 본격적으로 TCP congestion control에 대해 살펴보자.
TCP는 cwnd를 사용해 congestion control을 한다. 이 때 cwnd는 congestion window의 약자로 packet을 얼마나 보낼 수 있는지에 대한 지표라고 생각하면 된다. (receiver window(rwnd)와 비슷한 개념)
in flight byte size <= min(cwnd, rwnd)
in flight byte size, 그러니까 보냈지만 아직 ACK를 받지 못한 packet size를 min(cwnd, rwnd)보다 작게 두면 flow control과 congestion control을 둘 다 할 수 있다.
이 때 1RTT에 cwnd개의 packet을 보낼 수 있다는 것이므로 보내는 속도는 $\frac{\text{cwnd}}{\text{RTT}}$ bytes/sec이다.
cwnd 값 조절
cwnd는 아래 2가지 방법으로 조절한다.
- slow start : 이 과정을 통해 cwnd의 초기값은 1이지만 매우 빠르게 커진다.
- connection이 시작했을 때 초기 cwnd값을 1MSS로 둔다. 그러면 segment를 하나밖에 보내지 못한다.
- 보낸 segment의 ACK가 돌아올 때마다 cwnd를 1MSS 늘린다. 그러면 RTT마다 cwnd는 2배가 된다.
- AIMD : Additive Increase Multiplicative Decrese의 약자로 이 방식을 통해 유효한 bandwidth를 찾아간다. slow start에 비해 천천히 cwnd를 늘려가며, 아래 2가지 요소가 있다.
- additive increase : loss가 발생하지 않은 경우 RTT마다 cwnd를 1MSS만큼 늘린다.
- multiplicative decrease : loss가 감지되면 cwnd를 반으로 줄인다.
MSS는 Maximum Segment Size, 한 번에 보낼 수 있는 segment의 최대 size를 의미한다.
Congestion Control Logic
slow start는 cwnd가 exponential하게 커지고, AIMD의 경우 linear하게 커진다. 이 때 어떤 것을 사용할지 결정하는 값을 ssthresh라고 하며, 초기값은 OS가 결정한다.
- cwnd < ssthresh인 경우 : 아직 더 많이 보내도 괜찮으므로 slow start를 한다.
- cwnd >= ssthresh인 경우 : 여기서부터는 cwnd를 조심히 늘려야 하므로 AIMD를 사용한다.
- 만약 loss가 발생한 경우 ssthresh를 cwnd의 절반으로 설정한다. (ssthresh = $\frac{\text{cwnd}}{2}$)
TCP의 loss 감지 및 저리
TCP는 2가지 방식으로 loss를 감지한다.
- timeout : network가 꽉 막혀서 돌아오지 않는 경우이다.
- 3 duplicated ACK : 중간에 어떤 packet을 잃어버렸지만 더 뒤의 packet은 도착하는 상황이다.
loss를 처리하는 방식에도 2가지가 있다.
- TCP TAHOE : loss를 감지했을 때 cwnd를 무조건 1로 설정한다.
- TCP RENO : timeout가 발생한 경우는 cwnd를 1로, 3 duplicated ACK가 발생한 경우는 cwnd를 절반으로 설정한다. (cwnd = $\frac{\text{cwnd}}{2}$)
- 3 duplicated ACK의 경우 어느 정도는 network로 운송할 수 있다는 것이기에 이런 방식을 취한다.
- 3 duplicated ACK가 발생한 경우를 가정하자. TCP congestion logic에서는 loss를 ssthresh를 cwnd의 절반으로 설하고, RENO를 사용하는 경우 ssthresh를 cwnd의 절반으로 설정한다. 그러면 ssthresh와 cwnd가 같아지게 되므로 AIMD를 사용해 천천히 cwnd를 늘인다.
예시
- 초기 cwnd는 항상 1에서 시작하며, 초기 ssthresh가 8인 상태이다. slow start, AIMD를 거쳐 12까지 올라왔다.
- time 8에서 3 duplicated ACK loss가 발생했다.
- TCP RENO의 경우 ssthresh를 cwnd(12)의 절반인 6으로 설정하고 cwnd도 동일한 값으로 설정한다. 때문에, 이후에는 AIMD로 cwnd가 늘어난다.
- TCP TAHOE의 경우 ssthresh를 cwnd(12)의 절반인 6으로 설정하고 cwnd를 1로 설정한다. 그러면 cwnd가 6까지는 slow start로, 그 이후에는 AIMD로 늘어간다.
TCP Performance
TCP의 성능은 주로 throughput, fairness 2가지를 본다.
Throughput
TCP에서 한 번에 보낼 수 있는 packet 수는, rwnd를 배제하고 생각하면, cwnd만큼 내보낼 수 있다. 그러면 throughtput은 다음과 같다.
$\frac{\text{cwnd}}{\text{RTT}}$
이 때, loss가 발생하는 cwnd를 w라고 하면 cwnd는 평균적으로 w와 $\frac{w}{2}$를 왔다갔다 한다. 따라서 TCP throughput은 다음과 같이 정의한다.
average TCP throughput = $\frac{3w}{4\text{RTT}}$ bytes/sec
기술 발전으로 인해 long, fat pipe - 동시에 처리할 수 있는 packet 수도 많아졌고, 더 빨리 보낼 수 있게 되었다. 그러나 실제 TCP throughput은 아래와 같은 수식을 가진다. 때문에, 원하는 값을 가지기 위해서는 loss가 매우 작아져야 한다.
TCP throughput = $\frac{1.22 * MSS}{RTT \sqrt{L}}$
TCP Fairness
TCP의 주된 성능 중 하나인 fairness이다. 만약 unfair라면 특정 client가 계속 network를 사용할 수 있고, 특정 client는 starvation을 겪기 때문에 중요한 요소이다.
어떤 bottleneck link bandwidth가 R일 때 총 K개의 TCP connection이 있다고 하자. 이 때 각 TCP connection이 $\frac{R}{K}$만큼 사용할 때 fair라고 한다.
TCP fairness 증명
하나의 router에 2개의 TCP connection이 있다고 하자. 이 때 router bandwidth는 R이다. 위 그림에서 파란 선은 합이 R이 되는 connection의 조합이고, 점선은 fair한 connection 조합을 의미한다.
이 때, 첫 conneciton이 not fair한 지점에서 시작했다고 하자.
- 두 TCP connection은 모두 congestion control을 하면서 cwnd를 늘려가고, 그러면 throughput가 점점 커진다.
- 어느 순간에 파란 선을 넘게 된다. 그러면 loss가 발생한다.
- loss가 발생하면 throughput을 절반으로 줄인다.
이 과정이 반복되면 점선에 수렴하게 되고, 즉 fair하게 된다.
단, 이 경우는 두 TCP connection이 router로부터 같은 거리에 있다는 것을 가정한다. 만약 거리가 다르면, 더 가까운 conneciton이 더 빠르기 때문에 더 많은 throughput을 차지한다.
TCP fairness is hard
TCP는 UDP나 parrallel TCP때문에 fairness를 구현하기 어렵다.
- UDP는 fairness를 고려하지 않고, application이 만드는 대로 network에 바로 전송한다.
- parallel TCP는 하나의 TCP connection보다 더 dominiate하기 때문에 이 경우에도 fairness가 떨어진다.
잘못된 내용이나 오탈자에 대한 지적, 질문 등은 언제나 환영합니다.