Original text:
recovery.  Packets containing only ACK frames SHOULD therefore not be paced, to avoid delaying their delivery to the peer.  Sending multiple packets into the network without any delay between them creates a packet burst that might cause short-term congestion and losses.  Implementations MUST either use pacing or limit such <del> bursts to the initial congestion window, which is recommended to be the minimum of "10 * max_datagram_size" and "max(2 * max_datagram_size, 14720))", where max_datagram_size is the current maximum size of a datagram for the connection, not including UDP or IP overhead. As an example of a well-known and publicly available implementation of a flow pacer, implementers are referred to the Fair Queue packet scheduler (fq qdisc) in Linux (3.11 onwards). </del>  6.10.

Reviewer comments:
This isn't code, because I don't think we need to do any more than point at the leaky bucket algorithm, but it does provide more concrete advice than we've had. It removes the reference to fqdisc as that isn't especially helpful, as the original issue observes.
Leaky bucket sidesteps the issue of shaping multiple streams, but I agree you do not need that level of detail here. I don't understand the motivation for the N factor from a casual read. I guess it requires a deeper insight into the congestion controller. If it is a burst thing, it couldn't be for every interval ?
N exists to deal with the potential for the CWND to increase. Let's say that you have a CWND of 10 packets and an RTT of 1 second. If you pace evenly over that period, you will send one packet every 100ms. If the CWND doubles, you want to send every 50ms instead, but that only starts from the point you apply the increase. This allows you to send a little faster prior to the increase and not need to wait as long for the increase to take effect. N also exists because timers are terrible and you don't want to lag, which would force the pacer to be an extra constraint on send rate. Maybe that's too fancy and it should just be N is a number a little larger than 1.
So you are consuming the CNWD a bit too fast in anticipation of it growing before you run out and if it shrinks instead, I suppose you enter a period of silence because you over-consumed. But couldn't that also be detrimental? Perhaps more so for unreliable transmission with a timing aspect.
The definition of the pacer should not ever limit the congestion window. If the window collapses, then the cap on rate can apply the higher value. I should make that clearer.
Oh, I went back to my code and found why I wanted N. With the same example as before, you are sending 10 packets per second and the congestion window doubles. If you apply the formula in one way, you can get some odd spikes in the rate. Say that you measure over 10s (i.e., 100p/10s), and the rate doubles. If you attempt to reach the new target in the next second (200p/10s), your send rate goes up by a factor of 10 briefly. There is less incentive to do that sort of compensation if you have been sending at a higher rate previously.
I'm using exponential smoothing in other contexts: x + (1 - x). URL
I've taken a little of each suggestion here. I think that the difference between suggesting N=1.25 and N=2 is largely philosophical, so I don't want to get drawn on that. The only constraints that matter is that it be small and >= 1.
I reflowed, then reworded to s/timer/alarm and explain a little more.
The current text in recovery says: Could we change this recommendation to something like "a Fair Queue packet scheduler using an algorithm such as "Weighted Round Robin" or "Deficit Round Robin"? The specific Linux reference is not very helpful in online searches.
The interesting part about the the Linux qdisc is its support for rate-based packet pacing, not it's fair queueing algorithm. Would it help to make that more clear or provide a reference such as: URL
Not really, this is the first (and almost only) thing you find and it tells you very little about queueing algorithms.
I agree. I found this reference pretty odd and it could become dated in time. I don't think we need to refer implementers to any particular implementation.
I think NAME was going to write a more crisp definition of a pacer and remove this reference?
I was . If the formula I described is acceptable, then I'm happy to contribute text, but I hadn't planned to.
NAME I think it is good to have a clear definition of what pacing means when QUIC has that as a requirement for one operational mode. I'm not sure it is really helpful by itself in guiding the user towards queueing disciplines such as deficit round robin. I'd prefer at least a mention of such an algorithm as one way to achieve the desired behaviour rather then referring to qdisc. Such a name can searched and Wikipedia will answer.
We had tried to provide a clearer definition of pacing here: URL This includes specification for how long should an implementation wait between two consecutive bursts: To effectively avoid creating these large packet bursts, a sender SHOULD also enforce a minimum time between sending the above mentioned bursts. To achieve high throughput while at the same time minimizing the bursts it is considered safe to wait for (RTT maximumburstsize / (cwnd 2)) seconds between each burst (multiplying the congestion window by two allows the the rate to increase during slow-start). If the text in looks close to what we want, I can recreate the PR and we can go from there.
Thanks for working through this! I'll wait for NAME to take a look.I have one editorial change on top of this, but I'd like to do it separately.

Revised text:
recovery.  Packets containing only ACK frames SHOULD therefore not be paced, to avoid delaying their delivery to the peer. <ins> Endpoints can implement pacing as they choose.  A perfectly paced sender spreads packets exactly evenly over time.  For a window-based congestion controller, such as the one in this document, that rate can be computed by averaging the congestion window over the round- trip time.  Expressed as a rate in bytes: Or, expressed as an inter-packet interval: Using a value for "N" that is small, but at least 1 (for example, 1.25) ensures that variations in round-trip time don't result in under-utilization of the congestion window.  Values of 'N' larger than 1 ultimately result in sending packets as acknowledgments are received rather than when timers fire, provided the congestion window is fully utilized and acknowledgments arrive at regular intervals. Practical considerations, such as packetization, scheduling delays, and computational efficiency, can cause a sender to deviate from this rate over time periods that are much shorter than a round-trip time. </ins> Sending multiple packets into the network without any delay between them creates a packet burst that might cause short-term congestion and losses.  Implementations MUST either use pacing or limit such  <ins> bursts to the initial congestion window; see initial-cwnd. One possible implementation strategy for pacing uses a leaky bucket algorithm, where the capacity of the "bucket" is limited to the maximum burst size and the rate the "bucket" fills is determined by the above function. </ins> 6.10.