</> MAANG.io
system design · 301

Advanced

Master system design interviews with scalable architecture patterns, distributed systems, and real-world design challenges.

0/480 solved 0% complete

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

Sign in to MAANG.io

Use your Google or Microsoft account — no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.