그림처럼 두 노드가 1GB 링크를 통해 데이터를 전송하는데, 두 노드가 링크의 용량을 최대한으로 활용해서 데이터를 전송할 경우 중간 지점에서 데이터의 손실이 발생하는 것이다. TCP의 경우 전송하는 노드가 데이터의 손실을 감지하면 해당 데이터를 재전송하기 때문에, 위와 같은 경우 두 노드는 영원히 데이터를 전송하는 지옥에 빠질 것이다.
때문에 위와 같은 문제를 해결하기 위해서는 두 노드가 모두 데이터를 보내는 양을 조절해야하 하는데, 네트워크 상에서는 각 노드에게 얼마만큼의 데이터를 전송하라고 지시하는 중앙 노드가 없기에 이 문제를 해결하는게 쉽지는 않다. 한 가지 더 고려해야 할 점은, 노드가 자신이 사용하는 링크들의 용량을 알 수 없다는 것이다. 지금 내 노트북에서 어떤 서버로 접근한다면 링크 하나만을 통과하는 것이 아니라 수십 번 혹은 몇 백번까지 링크를 갈아탈 수도 있는 것이다. 때문에 내가 한 번에 보낼 수 있는 데이터의 양을 매번 체크하는 기능이 필요하다.
Congestion Window 혹은 flight size 라고 한다. Congestion Window란 ack을 확인하지 않고도 보낼 수 있는 데이터의 양 을 말한다. 예를 들어, 전송자에게 Congestion Window가 2로 세팅된다면, 전송자는 2 segments를 보낸 후 수신자로부터 ack이 올 때까지 기다려야 하는 것이다.
당연히 Congestion Window의 크기가 크면 한 번에 보낼 수 있는 데이터의 양이 많으니 데이터를 완전하게 보내는 데에 걸리는 시간이 줄어들 것이다. 그러나, 그 크기를 키우는 것은 Congestion을 발생시킬 수 있으니, 이 적당한 사이즈를 찾는 알고리즘이 필요하다.
이 방법은 80년대에 만들어진 것으로, 2가지 단계를 통해 Congestion Window의 크기를 키운다.
1 Slow start
이 알고리즘은 Slow start 라는 상태에서 시작한다. 이 상태에서 Congestion Window는 ack을 받을 때마다 크기가 1씩 커진다. 예를 들어, Congestion Window가 4이고, 4의 데이터가 전송된 후, 수신자가 각 데이터에 대한 ack을 보내면 Congestion Window가 8이 되는 것이다. 이러한 과정은 Slow start threshold에 도달할 때까지 반복된다. (이 숫자는 따로 세팅할 수 있다.)
2 Congestion avoidance
한 번 ssthresh에 도달하게 되면, Congestion Window의 성장 속도가 줄어든다. Congestion Window가 4이고, 4의 데이터가 전송된 후, 수신자가 각 데이터에 대한 ack을 보내면 Congestion Window는 8이 아닌 5가 되는 것이다.
중요한 것은 패킷 손실을 감지했을 경우다. 패킷 손실을 확인하면, 전송자는 해당 패킷을 재전송하면서 ssthresh는 현재 Congestion Window의 반이 되고 Congestion Window는 1이 된다.
ssthresh = congestion_window*0.5
congestion_window = 1
이렇게 커져버린 bandwidth에 맞춰진 것이 CUBIC이다. 다른 전송자의 bandwidth 크기를 줄이지 않으면서도 네트워크에 오버로드하지 않는 방법이다. CUBIC 은 y=x**3 함수에서 착안했다.
x의 값이 조금만 커져도 y의 값은 순식간에 커진다.
방법은 간단하다.
참고 : http://squidarth.com/rc/programming/networking/2018/08/01/congestion-cubic.html