MSS:
Maximum Segment Size
Piggybacked ACK:
데이터 세그먼트의 Header에 ACK를 포함시켜서 보낸다.
Piggybacked ACK
ACK도 패킷이다.
ACK를 보내야하는데, 세그먼트로 만들어서 보내면 오버헤드가 매우 크므로 그냥 데이터 세그먼트를 보낼 때 ACK를 포함시켜서 보내는 방식이다.
하지만, 모든 상황에서 바로바로 데이터를 전송하는 것이 아니기 때문에, ACK를 포함시킬 데이터 세그먼트 조차 없을 수 있다.
이 경우에는 타이머를 사용해서, 일정 시간동안 세그먼트가 만들어지지 않으면 ACK를 위한 세그먼트를 만들어서 보낸다.
sequence Number는 연속적이지 않을 수 있다.
TCP에서 sequence Number는 세그먼트의 첫 바이트를 기준으로 할당된다.
예를 들어, 1000 Bytes의 데이터를 보내는데 MSS가 100 Bytes인 경우, 세그먼트는 100개로 분할된다.
그럼 첫 세그먼트의 sequence Number는 0, 두 번째는 100, 세 번째는 200... 이런식으로 증가한다.
TCP에서 재전송 타이머는 1개만 사용한다.
하지만, 이전에 보낸 세그먼트가 Time Out 되었다고 해서 다음 세그먼트 모두를 재전송하지는 않는다.
∴ TCP는 Go-Back-N이랑 Selective Repeat의 짬뽕
Time out 시간은 최소한 RTT보단 커야된다.
적당한 시간은 다음과 같이 EWMA 방식을 사용해서 도출한다.
EstimatedRTT_(n) = (1-a)*EstimatedRTT_(n-1) + a*SampleRTT_(n)
하지만, 생각보다 값이 너무 작게 나오는 문제가 발생한다.
➜ DevRTT로 해결
예상 RTT = EstimatedRTT + 4*DevRTT
DevRTT = (1-b)*DevRTT + B*|sampleRTT-EstimatedRTT|
재전송 타이머의 값
➜ 오리지널 타이머의 2배가 된다.
가정
No flow Control
No Congestion Control
TCP는 Loss에 어떻게 대처하는지 알아보자.
Sender에서는 한개의 Retransmission Timer를 사용한다.
Event | Action |
---|---|
상위 계층에서 데이터 전송 요청 | 타이머 시작(sequence Number는 세그먼트의 첫 Byte Number) |
Time Out | 1. ACK 받지 못한 세그먼트 중 가장 작은 sequence Number를 가진 세그먼트 재전송 2. 타이머 시작 |
ACK(n) 받음 | 1. ACK(n) 이전에 ACK 받지 못한 세그먼트들을 모두 ACK 받았다고 처리(Cumulative ACK) 2. sequence n 이후에 보낸 세그먼트가 있으면 Timer start |
Event ③
A가 보낸 sequence 100을 잘 수신한 B는 ACK 200을 보낸다. 하지만, Loss가 발생한다.
A가 보낸 sequence 200을 잘 수신한 B는 ACK 300을 보낸다.
A는 ACK200을 받지 못했지만 TCP의 기본 동작은 Cumulative ACK이기 때문에 sequence 100, 200 패킷이 잘 전송되었다고 판단한다.
Receiver 에서는 한개의 piggyback 타이머를 사용한다.
Event | Action |
---|---|
순서에 맞는 세그먼트 도착. 이전 세그먼트는 모두 ACK 보냈음 | Delayed ACK. ACK 보내는 것을 지연한다. - 보낼 데이터가 500ms 안에 생기면, ACK를 얹어서 보낸다.(PiggyBacked ACK) - 보낼 데이터가 안생기면, ACK를 위한 세그먼트를 만들어서 보낸다. |
순서에 맞는 세그먼트 도착. 이전 세그먼트 중 아직 ACK 전송을 기다리는 세그먼트가 존재 | 즉시 Cumulative ACK를 전송한다. |
순서에 맞지 않는 세그먼트 도착. 예상 했던 sequence Number보다 큼 즉, 이전에 송신측에서 보낸 세그먼트가 Loss 되었음 | 즉시 Duplicate ACK를 전송한다. 즉, 순서대로 잘 받은 Byte + 1 전송 송신측에서는 이미 해당 ACK를 받은 것이므로 Duplicate ACK이다. |
순서를 끼워 맞춰줄 세그먼트 도착. Event ③, ④가 순차적으로 발생하면, 중간에 못받은 세그먼트가 존재할 것이다. 그 세그먼트가 도착한 경우 | 즉시 ACK 전송 |
A가 보낸 sequence 100을 잘 수신한 B는 ACK 200을 보낸다.
A가 보낸 sequence 200은 Loss
A가 보낸 sequence 300을 잘 수신했지만, 순서대로 오지 않았기 때문에 순서대로 온 데이터 중 가장 큰 Byte + 1을 보낸다.(ACK200)
여러 시나리오들
- Premature Timeout 발생
- 3번의 duplicate ACK (fast Retransmit)
Original ACK + 3번의 duplicate ACK가 발생하면 Time out이 발생하지 않아도 즉시 재전송한다.// 송신측 fast Retransmit 알고리즘 ACK(y) 수신 if(y > sendBase){ sendBase = y if(전송했지만 ACK 못받은 패킷 존재) start timer } else { // 이 코드가 실행된다는 것은 duplicate ACK를 받았다는 것 duplicateACK_y++; if(duplicateACK_y==3){ retransmit(y); } }
Flow Control: 수신할 공간이 있는지 보고 보낼 양을 조절한다.
수신측의 가용 버퍼 공간을 초과하면 안된다!
rwnd(Receive Window) = RcvBuffer - (LastByteRcvd - LastByteRead)
LastByteSent - LastByteAcked <= rwnd
TCP의 Connection을 Session이라 한다.
Session 설정할 때 주고 받는 정보는 다음과 같다.
이 외에도 다양한 정보를 주고받는다.
- 송신: request Connection
- 수신: Roger
- 송신: good Copy
세그먼트 안에 3개의 Flag(R, S, F)가 존재한다.
그 중, S가 연결에 관한 플래그이다.
3 Way Handshake는 다음과 같이 이루어진다.
- 송신: SYNbit=1, 자신의 초기 sequnce number(x)
- 수신: SYNbit=1, 자신의 초기 sequnce number(y)
ACKbit=1, ACKnum=x+1- 송신: ACKbit=1, ACKnum=y+1
F(Fin) flag(bit)를 1로 설정해서 보낸다.
- 송신: FIN
- 수신: ACK
- 수신: FIN (closed)
- 송신: ACK후 30초 대기
Time wait후 closed
도착할 수 있는 오래된 패킷들을 처리하기 위해서 잠시동안 close를 대기한다.
너무 많은 데이터를 "네트워크"로 보냈을 때 처리가 버겁다.
따라서, Congetsion Control이 필요하다.
Network-assisted Congestion Control
: 라우터가 개입하여 Congestion Control을 돕는다.
End-End Congestion Control
: 라우터의 개입없이, end host끼리 문제를 해결한다.
실제 TCP에서도 이 방법을 개선해서 사용한다.
라우터가 feedback 정보(choke packet)를 sender/receiver에게 보낸다.
congestion의 원인 제공자는 source이다.
➜ TCP sender 문제
ECN(Explicit Congestion Notification)이라는 프로토콜이 사용하는 방식이다.
TCP와 같이 사용하기도 한다.
ATM, DECbit이라는 프로토콜도 있지만 ECN이 널리 사용된다.
router와 무관하게 동작하는 방식이다.
end host에서 loss, delay를 통해 Congestion을 추측한 뒤 조절한다.
다음 장에서 더 자세히 알아보자.
ECN(Explicit Congestion Notification)을 사용한다.
end point는 어느 라우터가 이 필드를 설정했는지 알지 못한다.
⚠️ ECN은 3계층이고, TCP는 4계층이다.
⚠️ Router는 3계층 장비이기 때문에 IP 헤더의 ECN bit만 건드릴 수 있다.
TCP에서 실제로 사용하는 Congestion Control 방식에 대해서 알아보자.
Additive Increase Multiplicative Decrease
TCP 송신 윈도우 크기가 Addictive(linear)하게 올라가다가, Multiplicative(half)하게 줄어들음
더 자세히 알아보자.
송신할 때, 반드시 다음과 같은 규칙을 지켜야 한다.
LastByteSent-LastByteAcked <= min(cwnd,rwnd)
즉, 송신 윈도우 크기 <= min(congestion window 크기, receive window 크기)
Congestion control을 공부하고 있는 중이므로, rwnd가 cwnd보다 크다고 가정한다.
∴ LastByteSent-LastByteAcked <= cwnd
loss가 detect되기 전까지는 윈도우 크기(cwnd)를 1MSS씩 증가시킨다.
➜ Addictive Increase
loss가 detect되면 윈도우 크기(cwnd)를 반으로 줄인다.
➜ Multiplicative Decrease
통신이 시작되면, first Loss가 발생하기 전까지 윈도우 크기를 Exponential하게 늘린다.
패킷의 개수가 일정수준(slow start threshold) 에 다다르면 더이상 Slow Start로 동작하지 않고, Congestion Avoidance로 동작한다.
ssthresh == 6
ssthresh + 3
으로 줄인다.Slow Start
State Event Action ➜ SS start cwnd를 1MSS로 설정
ssthresh를 64KB로 설정
dup ACKcount를 0으로 설정루프 duplicat ACK 수신 dup ACKcount++ 루프 new ACK 수신 cwnd+=MSS
dup ACKcount = 0
새로운 세그먼트 전송SS ➜ fast Recovery 약한 Loss 발생(dup ACKcount == 3) ssthresh = cwnd/2
cwnd = ssthresh + 3
retransmit루프 심각한 Loss 발생(time out) ssthresh = cwnd/2
cwnd = 1MSS
dup ACKcount = 0
retransmitSS ➜ CA cwnd >= ssthresh NONE
Congestion Avoidance
State Event Action 루프 duplicat ACK 수신 dup ACKcount++ 루프 new ACK 수신 cwnd = cwnd + MSS*(MSS/cwnd)
dup ACKcount = 0
새로운 세그먼트 전송CA ➜ SS 심각한 Loss 발생(time out) ssthresh = cwnd/2
cwnd = 1MSS
dup ACKcount = 0
retransmitCA ➜ fast Recovery 약한 Loss 발생(dup ACKcount==3) ssthresh = cwnd/2
cwnd = ssthresh + 3
retransmit
cwnd = cwnd + MSS*(MSS/cwnd)
는 linear하게 증가함을 뜻한다.
예를 들어, cwnd가 100이고 MSS가 10이면 cwnd는 1만큼 증가한다.
즉, ACK가 10번 와야 1 MSS만큼 증가된다.
Fast Recovery
State Event Action FR ➜ SS Time out ssthresh = cwnd/2
cwnd = 1
dup ACKcount = 0
retransmitFR ➜ CA New ACK 수신 cwnd=ssthresh
dup ACKcount = 0루프 duplicate ACK 수신 cwnd += 1MSS
새로운 세그먼트 전송
W_max: Loss가 발생한 지점의 cwnd 값
여유가 있으면(Congestion이 일어나려면 한참 멀었다) cwnd를 많이 증가시키고, W_max와 가까우면 천천히 증가시키는 방법이다.
Congestion은 Bottleneck link에 연결된 라우터에서 발생한다.
sending rate를 늘려도 Bottlenect link 때문에 throughput은 증가되지 않는다.
이전까지의 알고리즘은 Loss를 경험한 뒤에 cwnd 값을 조정했다.
Delay Based Congestion Control은 Loss를 경험하지 않고, RTT를 기반으로 cwnd 값을 조정한다.
RTTmin: Congestion이 발생하지 않은 가장 좋은 상황
위의 Throughput에 가깝다
➜ 여유가 있다.
➜ cwnd를 증가시킨다.
위의 throughput에 한참 못미친다
➜ 여유가 없다.
➜ cwnd를 감소시킨다.
TCP는 공평하다.
TCP Session은 공평하게 link를 공유한다.
처음에는 공평하지 못하지만, 통신을 지속하다보면 공평해진다.
ex) TCP Session이 2개 존재한다.
1. 처음에는 Throughput이 불공평하게 분배될 수 있다.
2. Addictive하게 증가하다보면 Loss가 발생한다.
3. 각각 cwnd를 절반으로
4. 조금 fair 해짐
5. 2-4 과정 반복
결국 fair 해진다.
이미 9개의 Session이 열려져 있는 경우,
Session을 많이 열수록 유리하다는 문제가 존재한다!
UDP는 Congestion Control이 없다.
따라서 fairness하지 않다.
TCP, UDP는 40년 전에 만들어진 protocol이기 때문에, 새로 발생한 문제점들을 해결하기 위해 Protocol을 각각의 link에 맞게 재설계 또는 수정했다.
link | 문제점 |
---|---|
Long, high speed pipe | 너무 많은 패킷이 link안에 존재 |
Wireless network | 간섭으로 인한 loss 발생 |
Long-delay link | Long RTT |
Data center Networks | Latency에 민감함 |
Background traffic flows | 우선순위 낮음 |
따라서, 새로운 protocol들이 많이 나왔다.
QUIC는 application layer protocol이다.
실제로는 application layer에서 동작하지만 transport 기능을 해준다.
⚠️ TCP는 3 way handshake를 해야했지만, QUIC은 1RTT 안에 끝난다.
⚠️ Reliability는 stream 단위, Congestion Control은 connection 단위
Computer Networking, A Top Down Approach - JAMES F.KUROSE