Expand description
Distributed rate limiting for Rust services: one global limit across a fleet, no datastore, no network call on the request path.
Every instance of the service runs a Guard. The nodes find each other
over UDP and agree, every 200 ms, on how the limit is shared out; each
request is then decided locally, with no I/O and no lock shared with the
network.
use rateguard::{Decision, Guard};
let guard = Guard::builder()
.bind("0.0.0.0:7946")
.advertise("10.0.0.3:7946")
.seeds(["10.0.0.1:7946", "10.0.0.2:7946"])
.limit(1_000) // per key, across the whole fleet, per second
.spawn()?;
match guard.check("api:tenant-42") {
Decision::Allow => { /* serve */ }
Decision::Deny { retry_after } => { /* 429, Retry-After */ }
}The gossip is not encrypted, and by default not authenticated either:
run the nodes on a network you trust, or have them sign it with a
shared secret, see Builder::gossip_auth.
Structs§
- Builder
- Configures and starts a node; see
Guard::builder. - Checked
- A decision and what the key’s shadow limit would have decided: see
Guard::check_in_traced. - Denied
Key - A key denied lately; see
Stats::most_denied. - Guard
- The handle every request goes through: cheap to clone,
Send + Sync. The node runs as long as one clone is alive. - KeyStats
- What this node knows of one key; see
Guard::key_stats. - Limit
- A limit for each key of a class: a count of requests per second, minute
or hour across the whole fleet, and the burst one instance may admit
back to back on top of its share. See
Builder::classandGuard::set_class. - Rejected
Datagrams - Datagrams refused since the node started; see
Stats::rejected_datagrams. - Secret
- A secret shared by every node of a cluster, at least 32 bytes. Never
shown: its
DebugprintsSecret(..). - Stats
- A node’s state, as of the last tick of its background task: a quarter
of the protocol period ago at most, 50 ms by default. See
Guard::stats.
Enums§
- Auth
Error - Why secrets or a mode were refused. Never carries secret bytes.
- Decision
- The answer to a request. Two answers and no more, ever: matching both is safe across versions.
- Error
- Why a node could not start, or a class could not be set.
- Gossip
Auth - How a node signs what it sends and checks what it receives.
- KeyLimit
- The limit of one key, set with
Guard::set_key_limit: its own numbers, or those of a class. - Partition
Policy - What a node does when its cluster shrinks: the CAP trade-off as a setting. When the network splits into k groups, each sees only itself.
Functions§
- key_
hash - The 64-bit hash a key travels and is stored under. xxh3: fixed by its
specification, the same on every node and every Rust version. The key
table reserves 0 (an empty slot) and
u64::MAX(a slot being reset), so a key hashing to either is moved next door. - key_
hash_ in - The hash of
keyin the classclass: xxh3 with the class’s hash as its seed, so that one key in two classes is two keys. The default class,"", has seed 0, and its hashes arekey_hash’s. Public so that the hashes ofStats::most_deniedcan be matched to keys. Without a salt only: a node given aBuilder::key_salthashes asGuard::key_hash_indoes.