In golang.org/x/time/rate, what do the 10 and the 100 in rate.NewLimiter(10, 100) mean?
answer
- one number is per second, one is a capacity
- what can happen in the first instant?
- an idle limiter has saved up allowance
- raising it changes spikiness, not throughput
- capacity divided by rate is the refill time
basics
~20 sThe first argument is the sustained rate: 10 tokens refilled per second. The second is burst, the bucket's capacity: after an idle spell up to 100 calls go out back-to-back, then the pace settles to 10 per second.
solid answer
~50 s`rate.NewLimiter(10, 100)` is a token bucket that refills at 10 tokens per second and holds at most 100. A freshly created or long-idle limiter is full, so the first 100 requests are approved instantly; after that the bucket is empty and requests are approved at the refill rate. So the first minute can carry at most 100 + 600 = 700 calls, and every minute after that about 600. Burst is therefore a **latency and spikiness** knob, not a throughput knob — raising it lets a queue of work drain at once without changing the long-run average. A burst of 1 gives strict pacing with no bunching; a burst of 0 with a finite rate rejects everything. For slow rates, `rate.Every(2*time.Second)` is the readable way to express one token every two seconds, and `SetLimit` and `SetBurst` retune a live limiter.
go deeper
Recall which argument is which: first the per-second refill, second the bucket capacity. Being able to say that an idle limiter has saved up allowance is enough at this level.
Do the arithmetic out loud — the first instant, the first minute, the steady state, and the refill time — and explain why increasing burst does not increase sustained throughput.
Justify a burst value against the receiving side's own measurement window, and show you know that your instantaneous spike can trip someone else's shorter-window limit even when your average is compliant.
Frame rate and burst as a negotiated allowance rather than a constant: who sets it, how it is retuned when the contract changes, and why it belongs in configuration that can move without a code release.
## The two numbers `rate.NewLimiter(r rate.Limit, b int) *rate.Limiter` takes exactly the two parameters a token bucket needs. - **`r`, the limit**, is a `rate.Limit` — a `float64` counting **tokens per second**. It sets the long-run average: over a long enough window, the number of approved operations divided by elapsed seconds converges on `r`. - **`b`, the burst**, is the bucket's capacity in tokens. It caps how much unused allowance can accumulate while nothing is asking, and therefore how many operations can be approved in a single instant. So `rate.NewLimiter(10, 100)` means "ten per second on average, but up to a hundred at once if we have been quiet". ## The arithmetic that interviews actually probe A new limiter starts **full**, and so does one that has been idle longer than `b/r` seconds — that is how long a completely empty bucket takes to refill (100/10 = 10 seconds here). Given a full bucket and a flood of requests: - instant zero: 100 approvals, one per token in the bucket; - from then on: approvals arrive at 10 per second, because each one waits for the next refill; - first minute total: at most 100 + 10×60 = 700; - every subsequent minute: about 600. That one-off extra 100 is the whole point of burst. It is spent once per idle period and never again while traffic is continuous. People who size burst as though it were throughput are usually surprised that raising it from 100 to 1000 changes the sustained rate not at all — it only makes the initial slug bigger. ## Choosing burst Burst trades **smoothness against latency**. - **Burst 1** is strict pacing: one operation, then a full inter-arrival gap, then the next. Nothing ever bunches. This is what you want when the thing on the other end genuinely cannot take two calls in the same millisecond, or when you are being polite to a partner who measures instantaneous rate. - **A large burst** lets a batch of queued work leave immediately, which is much better for tail latency when traffic is spiky and the downstream is fine with clumps. The risk is that the receiving side is *also* rate limiting you, on a shorter window than yours: your burst of 100 in one instant can trip a limit expressed as "no more than 20 in any one second" even though your average is well under their ceiling. - **Burst 0** with a finite limit is a degenerate configuration: no operation can ever be approved, because a request for one token can never fit in a zero-capacity bucket. `Allow` is always false and `Wait` fails immediately. It is almost always a bug, usually from a config value that defaulted to zero. The useful heuristic: pick the sustained rate from the contract or the capacity you are protecting, then pick burst from how bunched you can afford to be in the worst instant. ## Expressing slow rates Writing `rate.Limit(0.5)` for one operation every two seconds is easy to misread. `rate.Every(2 * time.Second)` returns the same `rate.Limit` and says what it means. Note that `rate.Every` returns `rate.Inf` for a zero or negative duration, and `rate.Inf` is a limiter that never restricts anything — which is a clean way to express "disabled" without special-casing the call sites. ## Retuning at runtime `SetLimit` and `SetBurst` change a live limiter, and the `…At` variants let you specify the instant those changes take effect. This matters when the allowance is negotiated rather than compiled in — a vendor raises your tier, or you read the new value from configuration — because it avoids swapping the limiter pointer under concurrent callers. Note that tokens accumulated under the old settings are trimmed to the new burst, so lowering burst takes effect straight away rather than after the surplus drains. ## The check to run in your head Given a proposed `NewLimiter(r, b)`, answer three questions: how many can go out in the first instant (b), how many in a long minute (about 60r), and how long a quiet period must be before the full burst is available again (b/r seconds). If any of those three numbers surprises the person who owns the quota you are respecting, the configuration is wrong regardless of how reasonable the two constants looked.
- What does a burst of 1 give you, and when would you want it?Strict pacing: one operation per inter-arrival gap with no bunching at all. You want it when the receiving side measures instantaneous rate on a very short window, or when a downstream resource genuinely cannot absorb two calls in the same instant. The cost is tail latency — queued work drains one gap at a time instead of leaving together.
- What does rate.NewLimiter with a burst of 0 and a finite rate do?It rejects everything. A request for one token cannot fit in a zero-capacity bucket, so Allow is always false and Wait fails immediately rather than blocking. It is nearly always an unset configuration value rather than an intentional setting.
- How do you express one operation every 250 milliseconds readably?`rate.Every(250 * time.Millisecond)`, which returns the equivalent `rate.Limit` of 4 per second. It is clearer than writing the reciprocal by hand, and for a zero or negative duration it returns `rate.Inf`, a limit that never restricts anything.
The rate is the tap filling a bucket; the burst is the bucket's size. You can never scoop out more at once than the bucket holds, and over a long day you can only scoop what the tap delivered.
saying these in an interview costs you the question
- Thinks burst raises the sustained throughput
- Assumes a new limiter starts empty and must fill
- Sets burst to zero expecting no bursting
- Confuses tokens per second with tokens per call
- Cannot say how long a drained bucket takes to refill