Answer A: OpenAI GPT-5.6
System design: scalable URL shortener
Assumptions
- Redirect traffic peaks at 10,000 requests per second. A nominal 100:1 read-to-write ratio implies approximately 100 creates per second at that peak.
- Thirty billion links in five years requires approximately 190 creates per second on average, so the storage and write path will be provisioned for at least 1,000 creates per second to reconcile this figure and absorb bursts.
- Links are immutable by default. If deletion or destination editing is later supported, it uses explicit versioning and cache invalidation.
- Basic analytics may be eventually consisten...
Show Full Answer ▼
System design: scalable URL shortener
Assumptions
-
Redirect traffic peaks at 10,000 requests per second. A nominal 100:1 read-to-write ratio implies approximately 100 creates per second at that peak.
-
Thirty billion links in five years requires approximately 190 creates per second on average, so the storage and write path will be provisioned for at least 1,000 creates per second to reconcile this figure and absorb bursts.
-
Links are immutable by default. If deletion or destination editing is later supported, it uses explicit versioning and cache invalidation.
-
Basic analytics may be eventually consistent and can lose a very small number of events during catastrophic failures. Redirect correctness does not depend on analytics.
-
Redirect responses use HTTP 302 or 307 rather than permanent 301 redirects, preserving operational control and improving analytics visibility.
-
The service runs active-active in at least three geographic regions and uses a globally replicated link datastore.
-
High-level architecture
Components are global DNS or Anycast routing, regional load balancers, stateless redirect services, stateless creation services, local in-process caches, regional distributed caches, a partitioned link datastore, a durable event stream, and analytics processors and storage.
Create path
- A client sends the long URL and optional custom alias to the nearest healthy region.
- The API authenticates or rate-limits the caller, validates URL syntax, limits URL length, permits only supported schemes such as HTTP and HTTPS, and checks reserved aliases.
- For an automatically generated link, the service creates a cryptographically random code. For a custom alias, it normalizes the alias according to a documented, case-sensitive or case-insensitive policy.
- The creation service performs a conditional insert into the authoritative datastore: insert only if the code or alias does not already exist.
- On a random collision, it generates another code and retries. On a custom alias collision, it returns HTTP 409 without silently changing the requested alias.
- After the database acknowledges the write, the service inserts the new mapping into the local regional cache and broadcasts a cache-fill or invalidation message to other regions.
- It returns the short URL. A request idempotency key can map repeated client requests to the same result.
The write is acknowledged only after a quorum or consensus commit. This adds cross-zone and, depending on the datastore configuration, cross-region write latency, but creates an authoritative global uniqueness guarantee. Creation is much less latency-sensitive than redirect traffic.
Redirect path
- Global routing sends the request to the nearest healthy region.
- The redirect service validates and extracts the code.
- It checks a small in-process cache. If absent, it checks the regional distributed cache.
- On a cache miss, it performs a point lookup in a local datastore replica using the code as the primary key.
- If found and active, it populates both cache levels, asynchronously emits a click event, and immediately returns a 302 or 307 response containing the destination.
- If absent, it returns 404. Negative results are cached only briefly.
The redirect path has no synchronous analytics operation and no cross-region network hop under normal conditions. Stateless services horizontally scale behind regional load balancers.
- Short-code generation and uniqueness
A seven-character base62 space contains 62^7, approximately 3.52 trillion, values and can technically hold 30 billion links. However, at 30 billion stored links, about 0.85 percent of that namespace is occupied. A random bulk scanner would therefore discover roughly one valid link per 117 guesses, which does not satisfy the requirement that codes be difficult to guess in bulk.
The default code will therefore use 11 URL-safe base62 characters generated from a cryptographically secure random source. This provides approximately 65.5 bits and 5.2 × 10^19 possibilities. With 30 billion active links, a random guess succeeds with probability around 5.8 × 10^-10. Rate limiting and abuse detection further constrain enumeration. The trade-off is a four-character longer link. Seven-character aliases may still be allowed when explicitly chosen by users, but they do not receive the same non-enumerability guarantee.
Random generation avoids exposing creation order and distributes keys evenly. A primary-key conditional insert is the final uniqueness authority. Birthday collisions across the complete history are expected in a random system, but only simultaneous candidate collisions matter operationally: every attempted insert is checked and retried. At the planned occupancy of the 11-character space, retries are effectively nonexistent.
An alternative would be encrypting or applying a keyed permutation to a sequence number. That guarantees unique generated inputs but requires key lifecycle management and sequence allocation. Random generation plus conditional insertion is simpler, removes centralized ID allocation, and is sufficiently efficient at this namespace size.
Custom aliases share the same primary-key namespace as generated codes. Alias normalization occurs before insertion, and one globally consistent conditional insert decides the winner of concurrent requests. Reserved paths such as health, API, admin, and static are rejected. If aliases are case-insensitive, the normalized lowercase form is the key while the requested display form may be stored separately.
- Data model and datastore
Authoritative link record fields are:
code: primary key
long_url: destination URL
created_at: timestamp
owner_id: optional account identifier
status: active, disabled, or deleted
ttl_or_expiry: optional
version: monotonically increasing value for cache invalidation
custom_alias: boolean
Click counts are not updated in this record on each redirect because that would turn popular links into write hotspots.
The link store is a distributed, partitioned key-value database optimized for primary-key access, such as DynamoDB, Bigtable, Cassandra with carefully managed consistency, or an equivalent internally operated system. For globally unique conditional writes, the selected implementation must provide linearizable conditional creation for a key, either natively or through per-shard consensus leaders. Relational joins and range scans are not needed on the redirect path.
The primary partition key is a hash of the full code. Hash distribution prevents chronological hotspots and evenly spreads both generated codes and custom aliases. The logical keyspace is divided into thousands of virtual shards, which are reassigned as nodes are added. Each shard has at least three replicas across availability zones, with additional cross-region replicas.
Capacity estimate
Assume an average URL of 400 bytes and approximately 200 bytes for keys, metadata, encoding, indexes, and storage-engine overhead. At roughly 600 bytes per record, 30 billion records require about 18 TB of logical data. Allowing for longer URLs, compaction overhead, tombstones, and operational headroom, budget 30 TB logical. Three durable replicas require approximately 90 TB, and backups plus cross-region copies can raise the fleet allocation to roughly 150–250 TB. This is well within the intended range of horizontally partitioned key-value stores but is unsuitable for a single conventional database instance.
At 10,000 redirects per second, even a complete cache outage generates only 10,000 random point reads per second. The datastore is provisioned for at least 20,000–30,000 reads per second per serving region during failover and at least 1,000 conditional creates per second. Capacity is governed more by dataset size, replication, and failover reserve than by normal request throughput.
Analytics uses separate storage. A stream processor writes per-code, time-bucketed counts to an analytics key-value or columnar store with a model such as code plus day or hour as the key and count as the value. A compact total can be maintained asynchronously. Keeping analytics separate prevents hot-link counters from contending with redirect lookups.
- Caching strategy
Each redirect process has a bounded LRU or TinyLFU in-memory cache for the hottest mappings. A regional Redis or Memcached-compatible cluster forms the second level. Cached values include destination, status, expiry, and record version.
A representative target is a 95–99 percent regional cache hit rate. Zipf-like URL popularity generally makes this feasible even though the total corpus is very large. The cache stores hot objects, not all 30 billion links. For example, 100 million entries at approximately 600 bytes each consume about 60 GB before cache overhead and perhaps 100–150 GB in practice, distributed across a regional cache cluster.
Mappings are immutable by default, so positive entries can have a long TTL, such as 6–24 hours with jitter. If editing, disabling, or deleting is supported, the authoritative write commits first and then publishes an invalidation containing the code and new version to all regions. Shorter TTLs bound stale-serving time if an invalidation is lost. Safety-sensitive disable operations can also place a small global deny-list in every redirect process.
Negative results are cached for approximately 5–30 seconds to resist repeated scans. The creation path invalidates negative cache entries after successfully claiming a code. The short negative TTL limits a race in which another region briefly cached a miss before replication or invalidation arrived.
On a cache miss, the redirect service reads the regional datastore replica and fills both cache levels. Request coalescing ensures that concurrent misses for a newly popular code issue one database request rather than thousands. TTL jitter avoids synchronized expiration. The datastore is sized to carry the entire 10,000-request-per-second load if the distributed cache fails, accepting somewhat higher latency while remaining functional.
The trade-off of long cache TTLs is potential staleness after edits. Immutability, versioned invalidations, and bounded TTLs make that trade-off explicit. Redirect correctness for newly created links can be improved by synchronously filling the creating region and routing an immediate read to that region when necessary.
- Scaling and latency
Redirect services are stateless and scale horizontally based on requests per second, CPU, and p99 latency. If one instance safely processes 1,000 requests per second, each region might run at least 15–20 instances for a 10,000-request-per-second regional failover load, plus deployment and zone-failure headroom. Actual sizing is established through load testing.
A normal cache-hit latency budget is approximately 2–5 ms for load balancing and application work, 1–3 ms for an in-process lookup or 2–8 ms for a regional distributed-cache lookup, and a few milliseconds to construct the response. A cache-miss budget allocates approximately 10–25 ms to a local replicated datastore point lookup. These budgets leave room to keep origin server-side p99 below 50 ms.
Strict per-hop timeouts prevent a damaged cache or replica from consuming the entire latency budget. Cache access may be limited to roughly 8 ms and datastore access to roughly 25–30 ms, with retries only when enough budget remains. Hedged reads to a second local replica may be used for the slowest percentile, but they are delayed and rate-limited to avoid doubling normal load.
Keys are hash-partitioned across virtual shards. Random generated codes naturally balance traffic, while an exceptionally hot individual link is absorbed by in-process and regional caches. If a hot key reaches the datastore, request coalescing and replicated reads prevent one storage node from becoming the bottleneck.
Autoscaling maintains enough capacity for a complete availability-zone loss and at least one region receiving redirected traffic from a failed peer. Regions run below roughly 50–60 percent peak capacity. The trade-off is higher idle cost in exchange for the 99.99 percent availability objective.
- Reliability and failure handling
Availability target
A 99.99 percent monthly target permits about 4.4 minutes of unavailability in a 30-day month. No single cache node, application instance, availability zone, or region may be required for redirects.
Application instance or zone failure
Health checks remove failed instances and load balancers distribute requests across at least three zones. Services use rolling or canary deployments, connection draining, and automated rollback. Regional capacity survives losing one zone.
Cache-node or cache-cluster failure
Cache nodes are sharded and replicated within a region. If an individual node fails, its replica takes over. If the whole cache is unavailable, redirect services use circuit breakers, skip cache calls, and query the datastore directly. Database capacity and application connection pools are explicitly provisioned for this mode. Admission control protects the datastore from unbounded scanner traffic.
Datastore-node failure
Each shard is replicated across zones using quorum or consensus. A failed leader is replaced automatically; reads use another healthy local replica. Conditional creates remain unavailable for a shard during the brief election rather than risking duplicate ownership. Redirects can continue from replicas and caches. This favors correctness for creation while preserving read availability.
Region failure
Global health-based routing removes the failed region and sends traffic to the nearest healthy region. Every serving region has a replicated copy of link data and independent redirect, cache, and event-ingestion infrastructure. Cache hit rate will initially be lower after failover, so standby regions retain warm caches for globally hot links and enough datastore/read capacity for the cold-cache surge.
For generated codes, global replication may be asynchronous after a consensus-backed authoritative insert if the datastore architecture routes each key to a home shard. For custom aliases, the authoritative conditional insert must remain globally serialized. If a newly created link has not reached a surviving region before catastrophic loss, the service may briefly return a retriable error rather than an incorrect mapping. Stronger synchronous multi-region replication reduces this recovery-point window but increases create latency. The preferred configuration commits link creation across replicas in at least two regions because writes are relatively low volume.
Backups and corruption
The datastore uses checksums, point-in-time recovery, immutable snapshots, and regularly tested restore procedures. Deletes use tombstones and a retention period rather than immediate physical removal. Backups protect against logical corruption but are not part of normal redirect failover.
Overload behavior
Rate limits apply by source, account, and suspicious code-scanning pattern. Creation and analytics traffic have lower priority than redirects. Load shedding rejects abusive or excess creation requests before redirect capacity is affected. Circuit breakers, bounded queues, and deadlines prevent cascading failures.
- Click analytics
After selecting the redirect destination, the service creates a compact event containing an event id, code, timestamp, region, and optionally coarse referrer or user-agent fields. It places the event into a bounded local asynchronous buffer and returns the redirect without waiting for analytics acknowledgement.
A regional collector batches events into a durable replicated stream such as Kafka, Pulsar, or Kinesis. Stream processors aggregate events by code and time bucket, then write batched increments to the analytics store. Periodic compaction produces total click counts. Dashboards and APIs read the analytics store, never the authoritative redirect table.
Event ids allow downstream deduplication when collectors retry. Partitioning the stream directly by code would concentrate a viral link on one partition, so the ingestion key can be code plus a random stripe. Processors first aggregate striped counters and then merge them. This permits hot-link analytics to scale horizontally.
A purely in-memory asynchronous buffer can lose events if a redirect process crashes. If stronger durability is required, each host or sidecar can append batches to a local write-ahead log before forwarding them, but redirect responses should still not wait for the central stream. The accepted trade-off for basic analytics is eventual consistency and a small, measured undercount during severe failure in exchange for preserving redirect latency and availability.
Result
The normal redirect path is a local cache lookup followed, only on misses, by a local partitioned key-value lookup. Random 11-character codes prevent sequential exposure and make successful bulk guessing impractical. Conditional inserts provide uniqueness, hash partitioning supports the 30-billion-record corpus, active-active regional serving removes regional single points of failure, and asynchronous striped analytics keeps counter writes entirely off the latency-critical path.
Result
Winning Votes
3 / 3
Average Score
Total Score
Overall Comments
Answer A is an exceptionally thorough and technically rigorous design document. It ties every major decision back to the stated constraints: it derives the write rate from both the 100:1 ratio and the 30B/5yr figure and reconciles the discrepancy, explicitly computes that a 7-character space would be enumerable at 0.85% occupancy (roughly 1 hit per 117 guesses) and therefore moves to 11-character random codes, provides a defensible per-record and fleet-level storage estimate (~18 TB logical, 90 TB replicated, 150-250 TB with backups), gives a concrete p99 latency budget broken into per-hop allocations with timeouts and hedged reads, and translates 99.99% into 4.4 minutes/month with layered failure handling for instances, cache, datastore shards, and full regions. Trade-offs are named honestly throughout (longer codes vs. enumerability, cross-region write latency vs. global uniqueness, idle capacity vs. failover headroom, analytics undercount vs. redirect latency). Weaknesses are minor: the answer is long and dense, some sizing numbers are asserted rather than derived, and a diagram-style summary would improve scanability. Overall it exceeds benchmark expectations on nearly every axis.
View Score Details ▼
Architecture Quality
Weight 30%Coherent active-active multi-region architecture with clearly separated create/redirect paths, conditional inserts for uniqueness, two-level caching with request coalescing, and a correct quantified rejection of 7-character codes (0.85% occupancy makes bulk guessing feasible) leading to 11-character CSPRNG codes. Every component decision is tied to a constraint. Minor deduction for density and some asserted rather than derived sizing figures.
Completeness
Weight 20%All seven numbered requirements are addressed with concrete specifics: assumptions stated up front, write-rate reconciliation, full code-generation analysis with alias collision policy, storage math for 30B records, explicit cache-miss and invalidation behavior, per-hop latency budget for p99 under 50 ms, failure handling at every layer mapped to the 4.4 min/month budget, and striped asynchronous analytics with durability trade-offs.
Trade-off Reasoning
Weight 20%Trade-offs are named and quantified throughout: 4 extra characters vs. enumerability with actual probability math, cross-region consensus write latency vs. global uniqueness, long TTLs vs. staleness bounded by versioned invalidations, idle capacity below 50-60% utilization vs. availability, and accepted analytics undercount vs. redirect latency. Alternatives (keyed permutation of sequences) are considered and rejected with reasons.
Scalability & Reliability
Weight 20%Concrete scaling story: hash-partitioned virtual shards, instance sizing with failover headroom, datastore provisioned to absorb full 10K RPS on total cache outage, hedged reads and per-hop timeouts, translation of 99.99% into 4.4 minutes/month, and layered failure handling covering instance, zone, cache, shard-leader election, and full region loss with warm standby caches. RPO trade-off for cross-region replication is explicitly discussed.
Clarity
Weight 10%Well-organized with numbered sections matching the prompt, explicit assumptions, and a closing summary. The prose is dense and long, and a few sections pack many numbers into paragraphs where tables or bullets would help, but the argument flow is always traceable.
Total Score
Overall Comments
Answer A is a very strong, concrete system design. It explicitly ties the architecture to the 10K RPS, 100:1 read/write ratio, p99 under 50 ms, 30 billion-link corpus, 99.99% availability target, and non-guessability requirement. It provides coherent read and write flows, a strong short-code strategy, plausible storage sizing, detailed caching behavior, partitioning, multi-region reliability, and asynchronous analytics. Its main weakness is that it is somewhat elaborate, but the detail is mostly relevant and well justified.
View Score Details ▼
Architecture Quality
Weight 30%Answer A gives a coherent end-to-end architecture with separate create and redirect paths, local and distributed caching, authoritative key-value storage, event streaming, active-active regions, and clear normal and failure request flows. The design choices fit the workload and latency constraints.
Completeness
Weight 20%Answer A addresses every required section in detail: write/read flows, uniqueness, custom alias collisions, datastore and capacity estimate, cache miss and invalidation behavior, scaling and sharding, node/cache/region failures, and asynchronous analytics. It also states assumptions clearly.
Trade-off Reasoning
Weight 20%Answer A consistently states trade-offs, such as longer codes versus enumeration resistance, quorum or multi-region write latency versus uniqueness, cache TTL staleness versus speed, spare capacity cost versus availability, and analytics loss risk versus redirect latency.
Scalability & Reliability
Weight 20%Answer A gives credible scaling and reliability details: stateless horizontal scale, hash partitioning with virtual shards, cache sizing and fallback, datastore provisioning for cache outage, active-active multi-region deployment, regional failover, quorum/consensus behavior, and asynchronous analytics that avoids hot-path writes.
Clarity
Weight 10%Answer A is well organized, structured around the required sections, and uses concrete numbers and mechanisms. It is long, but the structure makes the design easy to follow.
Total Score
Overall Comments
Answer A provides an outstanding and comprehensive system design. It excels by directly addressing every constraint with specific, well-reasoned technical choices. Its analysis of short code guessability and the proposal of an 11-character random code is a key strength. The capacity planning is detailed and realistic, and the multi-region, active-active architecture provides a credible path to achieving the 99.99% availability target. The discussion of failure modes at every level (node, cache, region) is thorough and demonstrates a deep understanding of building resilient systems.
View Score Details ▼
Architecture Quality
Weight 30%The architecture is excellent. It correctly proposes a multi-region, active-active setup from the start, which is appropriate for the global nature and high availability requirements. The components are well-defined, and the request flows for both read and write paths are detailed and logical.
Completeness
Weight 20%The answer is exceptionally complete, addressing all seven required sections in significant detail. Every functional and non-functional requirement is covered with a specific design choice.
Trade-off Reasoning
Weight 20%Trade-off reasoning is a major strength of this answer. For nearly every significant decision (e.g., code length, datastore choice, cache TTL, replication strategy), the specific trade-off is explicitly stated and justified in the context of the requirements.
Scalability & Reliability
Weight 20%This is the strongest part of the answer. It correctly identifies that 7-character codes become guessable at 30 billion scale and proposes a robust solution. The capacity estimate is thorough and realistic. The reliability plan is excellent, covering failures at the instance, zone, cache, datastore, and regional levels, providing a credible path to 99.99% availability.
Clarity
Weight 10%The document is very well-structured, clear, and technically dense. It follows the requested format precisely, making it easy to evaluate the design against the requirements.