Section 5: One Limit, Five Shapes - Data Modeling
Executive Summary: A rate limit exists in five forms, each with its own lifetime and its own store: the durable rule an owner writes, the compiled snapshot a load balancer reads, the 64-bit runtime key a request maps to, the 64-byte bucket that makes the decision, and the allocator state that sets each bucket's rate. Telemetry rows come out the other end. This section models each one with Contoso's rule, resolves precedence, and defends each store. Redis is missing on purpose.
The interviewer points at Section 4's API. "What sits behind PUT /v1/rules and decide()?"
A weak answer is one rate_limits table with a counter column. A strong answer asks how fast each piece changes. Rules change about 50K times a day across the whole fleet. A bucket changes 30,000 times a second on every load balancer. Those two shouldn't share a schema, a store or a failure mode.
The rule record: slow, versioned, audited
Rules are the only state that has to survive, so they go in a relational source of truth:
CREATE TABLE rules (
rule_id TEXT PRIMARY KEY, -- 'dir-users-contoso', caller-chosen for idempotent PUT
service TEXT NOT NULL, -- 'directory'
api TEXT NOT NULL, -- 'GET /v1/users' or '*'
scope_json JSONB NOT NULL, -- {"tenant":"contoso"} or {"sku":"premium"}
rate BIGINT NOT NULL, -- 10000
per_ms INT NOT NULL, -- 1000
burst BIGINT NOT NULL, -- 10000
algorithm TEXT NOT NULL, -- 'TOKEN_BUCKET'
mode TEXT NOT NULL, -- 'SHADOW' | 'ENFORCE'
fail_mode TEXT NOT NULL, -- 'OPEN' | 'STATIC'
priority INT NOT NULL,
version BIGINT NOT NULL, -- per-rule ETag for If-Match, not the snapshot version
created_by TEXT NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
-- plus rule_versions: append-only history for audit and rollback
At 10M rules × ~200 B ≈ 2 GB and about 0.6 writes a second, SQL is the boring right answer. It gives you transactions for If-Match, history for "who changed this", and cheap per-service reads for the compiler.
Interviewer: "Millions of tenants. Is there a row per tenant?"
You: "No. A tenant inherits its SKU template, one rule per tier (Free, Standard, Premium, Enterprise) per API. Only an override, like Contoso's 10,000 req/s, gets its own row."
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson