Configurable pacing rate modes via TransportConfig#2543
Conversation
Add PacingRateMode enum to control rate calculation: - RttDependent: rate = cwnd × 1.25 / RTT (default, standard QUIC) - Fixed: constant bytes/sec rate, ignoring RTT and cwnd - RttDependentWithFloor: max(floor, cwnd × 1.25 / RTT) Fixed and RttDependentWithFloor are useful for latency-sensitive high-RTT connections. With default Quinn's RTT-dependent pacing, cwnd bytes worth of traffic are spread over 80% of the RTT window. This approach doesn't impact overall throughput for large downloads, but it does impact latency. For example, given two connections with RTT of 10ms and 100ms sending 128 transactions, and assuming both congestion and flow control allow this in 1 RTT, it will take 13ms and 130ms (50ms one-way plus 80ms pacing) respectively for these clients to deliver the same data. High-RTT clients are penalized twice: once by RTT, and again by the slower pacing rate.
096c49c to
bed3c81
Compare
|
Thanks for working on this. I think this could be made easier to review:
Please rebase and force push (avoiding merge commits). Note that our style prescribes top-down item ordering, so constants go near the bottom and high-level logic goes near the top. |
|
Also note Does it still make sense to do both? |
|
Whoops, sorry, this slipped off my stack! The motivation here makes sense to me in abstract, but it's not obvious to me that this patch is the best solution. Some thoughts:
I think |
Thank you for the feedback! Here is some additional context for our use case: Communication nodes are expected to have very good links (at least no last mile issues). Think of a distributed financial database. Senders have a short slot [t, t + duration) where duration is on the order of hundreds of ms to deliver their transactions, and the earlier they deliver them, the better. Some senders have high RTT, which already puts them at a disadvantage. They can of course use a larger initial cwnd, or try to keep connections "hot" cwnd-wise one way or another. But the issue here is different: this is about sending the existing cwnd faster, not allowing more bytes in flight (which can be restricted on purpose by flow control, so cwnd won't grow further). What we want here is to reduce the extra latency from spreading that already-allowed data over RTT. Some senders even choose to relax or disable congestion control, since slow-start (or classical CC algos in general) is arguably not a great fit for this kind of workload. In that case, |
|
It makes sense to me that, on a known network, a minimum pacing rate is useful. I still think we can simplify this API:
Hence, it seems like the only thing we need to cover all cases is a "minimum pacing rate" setting. Does that make sense? |
Add
PacingRateModeenum to control rate calculation:RttDependent: rate = cwnd × 1.25 / RTT (default, standard QUIC)Fixed: constant bytes/sec rate, ignoring RTT and cwndRttDependentWithFloor: max(floor, cwnd × 1.25 / RTT)FixedandRttDependentWithFloorare useful for latency-sensitive high-RTT connections.With default Quinn's RTT-dependent pacing, cwnd bytes worth of traffic are spread over 80% of the RTT window. This approach doesn't impact overall throughput for large downloads, but it does impact latency. For example, given two connections with RTT of 10ms and 100ms sending 128K of data, and assuming both congestion and flow control allow this in 1 RTT, it will take 13ms (5ms one-way + 8ms pacing) and 130ms (50ms one-way + 80ms pacing) respectively until the last byte is delivered to the server. High-RTT clients are penalized twice: once by RTT, and again by the slower pacing rate.
With fixed-rate pacing (Fixed(rate)), both connections use the same pacing rate, so the delivery spread is independent of RTT.