Open marcblanchet opened 10 months ago
Yes. There are a few well known issues, and also a few subtle ones.
Reno embed time constants that makes it very inefficient on links with a large Bandwidth*Delay product. In congestion avoidance mode, Reno increases the bandwidth by one packet per RTT -- and then shrinks the window by half in case of packet loss. This is a well known issue, discussed for example by Sally Floyd in RFC3649. Bottom line, Reno cannot be used on deep space links.
Cubic is in theory a bit better, but there is a catch. Cubic grows the window as a function of time spent from the beginning of the epoch, with the formula:
Wcubic(t) = C * (t - K)**3 + Wmax
In that formula, C is a scaling constant determining the aggressiveness of the protocol in packets per second**3, and t is the time in seconds since the beginning of the epoch -- the recommended value being 0.4. The variable K in this formula acts as some kind of pseudo period. The window grows from an initial value at the beginning of the epoch to the nominal value "Wmax" after K seconds, after what it increases to probe the capacity of the link.
K is computed at the beginning of the epoch as:
K = cubic_root((Wmax - cwnd(epoch))/C)
In stable operation, Wmax is the congestion window at the end of the previous epoch, and "cwnd(epoch)" is the desired congestion window at the beginning of the epoch. Normally, cwnd(epoch) is set to beta*Wmax, the recommended value of beta being 0.7. We can assume that Wmax is the bandwidth*delay product, in packets, to get the formulas:
Wmax = BDP cwnd = beta*BDP K = cubic_root(BDP*(1-beta)/C)
Now, let's plot the values for a variety of delays:
C | Beta | Packet size (bytes) | RTT(sec) | Data rate (Mbps) | BDP (packets) | K (sec) |
---|---|---|---|---|---|---|
0.4 | 0.7 | 1500 | 0.1 | 1 | 8 | 2 |
0.4 | 0.7 | 1500 | 0.1 | 10 | 83 | 4 |
0.4 | 0.7 | 1500 | 0.1 | 100 | 833 | 9 |
0.4 | 0.7 | 1500 | 2 | 1 | 167 | 5 |
0.4 | 0.7 | 1500 | 2 | 10 | 1667 | 11 |
0.4 | 0.7 | 1500 | 2 | 100 | 16667 | 23 |
0.4 | 0.7 | 1500 | 600 | 1 | 50000 | 33 |
0.4 | 0.7 | 1500 | 600 | 10 | 500000 | 72 |
0.4 | 0.7 | 1500 | 600 | 100 | 5000000 | 155 |
0.4 | 0.7 | 1500 | 1200 | 0.1 | 100000 | 20 |
0.4 | 0.7 | 1500 | 1200 | 1 | 1000000 | 42 |
0.4 | 0.7 | 1500 | 1200 | 10 | 10000000 | 91 |
0.4 | 0.7 | 1500 | 1200 | 100 | 100000000 | 196 |
What we can see is that the value of K gets larger than the RTT as soon as the RTT is above several minutes. This is a very different behavior from the "terrestrial" or even "GEO" conditions, in which each "saw tooth" lasts many RTT. Basically, that means Cubic, too, is not going to work. Yes, it is possible to pick different values of C that restore some sanity, but that means creating a loop between RTT measurement and Cubic parameters, something that Cubic designers expressly did not want. They wanted the grow curve to be independent of RTT, so connections with different RTT would still be treated fairly.
BBR does perform much better, because it does not have constants with time dimension. It simply adapts to the RTT. It will work, as long as the RTT does not increase too much during the connection.
need a section on congestion control algorithm: cubic vs newreno vs bbr vs bbrv2