shortenUrl()
redirectUrl()
Entry layer: An AWS Application Load Balancer (ALB) sits at the edge. It terminates TLS, health-checks service instances, distributes traffic across them, and routes by path: POST /shorten → Shortener Service, GET /{shortCode} → Redirect Service. ALB is chosen because it natively supports path-based routing and automatic failover, so no single server is a point of failure.
Write path (shorten URL): The Shortener Service (a stateless service, horizontally scalable) receives the long URL, requests a unique identifier from the ID Generation Service, and stores the mapping shortCode → longURL as a key-value record in DynamoDB. DynamoDB is chosen because every redirect is a single-key lookup — it serves these in single-digit milliseconds, scales horizontally without manual sharding, and has built-in TTL support for expiring links. The short URL (e.g., tinyurl.com/abc123) is returned to the client.
Identifier generation: Short codes come from a Snowflake-style generator — 41-bit timestamp + 8-bit server ID + 14-bit sequence counter — base62-encoded into an ~11-character code. Because each server's ID is unique, no two servers can produce the same code, so uniqueness is guaranteed with no collision-check retry loop. The time-based component also makes codes non-sequential, so users can't enumerate or guess other short links.
Read path (redirect): The Redirect Service handles GET /{shortCode}. It first checks Redis:
The client receives a 302 Found response with the long URL in the Location header; the browser follows it to the destination. (302, not 301, so every click hits our service — enabling click analytics and letting us update or disable links instantly.)
Caching layer: Redis runs in cluster mode — keys are sharded across nodes, with replicas for read scaling and automatic failover. A cache outage degrades to DB reads but never takes the system down.
Storage layer: DynamoDB stores the shortCode → longURL mapping, partitioned on hash(shortCode). Since codes are random, traffic spreads evenly across partitions; a viral link's reads are absorbed by Redis so the database never sees the spike.
Scaling & availability summary: All services are stateless → scale by adding instances behind the ALB. DynamoDB scales automatically. Redis scales via cluster mode. The ALB health-checks and routes around dead instances, and Redis replicas handle node failure — giving high availability without a single point of failure.
Security: All traffic is HTTPS-only (TLS 1.3), terminated at the ALB — data is encrypted in transit end to end. Data at rest is encrypted via DynamoDB's server-side encryption (AES-256 with AWS KMS); Redis data is encrypted the same way. DDoS protection comes from AWS Shield (absorbs volumetric attacks at the network edge) plus AWS WAF filtering malicious patterns (SQLi, XSS) before requests reach the ALB.
"A rate limiter at the gateway throttles abusive clients (429 + Retry-After on exceed). Security: HTTPS/TLS, AWS Shield + WAF at the edge, encryption at rest via KMS."
1. ID Generation Service
Avoiding collisions under concurrency: IDs come from a Snowflake-style generator: 41-bit timestamp + 8-bit server ID + 14-bit sequence counter, base62-encoded into an ~11-character code. Because the server ID is unique per instance, no two servers can produce the same (timestamp, server ID, sequence) triple — uniqueness is guaranteed with no collision-check retry loop, even under heavy concurrent creates.
Hard to guess: Codes are time-derived and base62-encoded, so they're non-sequential and opaque. A user cannot enumerate or predict valid short links — attempting to scan the space is infeasible.
Generator outage / split-brain: Each instance runs its own generator with a server ID assigned at startup. If one generator dies or is partitioned, the remaining instances keep issuing unique IDs — there is no central generator to fail, so no split-brain window exists.
2. Caching Layer
Cache-aside pattern: The read path checks Redis first. On hit, the long URL returns in <1ms. On miss or TTL expiry, the Redirect Service queries DynamoDB, serves the redirect, and populates Redis — so the next request is served from cache.
TTL & eviction: Each entry gets a 24-hour TTL. Viral links refresh their TTL on every hit, so hot entries stay cached; cold links expire naturally, preventing memory bloat without manual eviction logic.
Purging on update/disable: When a link is edited or disabled, the service actively deletes the key from Redis so changes take effect immediately — no stale redirects.
Viral link protection: Redis absorbs the read spike for a suddenly popular link, so the database never sees the full load. For extreme virality, a CDN edge layer can cache the 302 response at the network edge.
3. Partitioning (Database Sharding)
Single-shard lookups: The database is partitioned on hash(short_code). Every redirect routes to exactly one shard — no scatter/gather, so latency stays consistent at any scale.
Even spread + hotspots: Because short codes are random, traffic distributes evenly across shards. A viral link is served by Redis/CDN before reaching the DB, preventing any single shard from being overwhelmed.
4. Rate Limiting
Mechanism: A distributed token bucket runs at the API gateway, backed by Redis. Each client (keyed by IP or API token) has a bucket — e.g., 100 tokens/min for creates, 1,000 tokens/min for redirects. Every request consumes a token.
Burst handling & backoff: Bursts are smoothed by the refill rate. When a bucket is empty, the gateway returns 429 Too Many Requests with a Retry-After header so clients back off automatically.
Management: Because the bucket state lives in Redis, all gateway instances share it — a client can't bypass limits by hitting different instances. Limits are configurable per tier (anonymous vs. registered users), adjustable at runtime without redeploy, and monitored for anomalies (e.g., a client suddenly spiking).
5. Scaling & High Availability
Scaling: Services are stateless → scale horizontally behind the ALB. DynamoDB scales automatically via partitioning. Redis scales via cluster mode (keys sharded across nodes, replicas for read scaling).
High availability: Services run across multiple availability zones; the ALB health-checks and routes around dead instances. DynamoDB replicates synchronously within the region (immediate durability) and asynchronously to a standby region for disaster recovery. Redis uses replica sets with automatic failover — a cache loss degrades to DB reads, never downtime.
6. Security
In transit: HTTPS-only (TLS 1.3), terminated at the ALB.
At rest: DynamoDB and Redis use server-side AES-256 encryption via AWS KMS.
SQL injection: DynamoDB is NoSQL — there is no SQL to inject; all lookups are parameterized key-value gets. The gateway additionally enforces a strict character allowlist for short codes ([a-zA-Z0-9]), so malicious payloads never reach the data layer.
XSS: Short URLs are opaque identifiers, never rendered as content. On create, the service validates and sanitizes the long URL — rejecting javascript: URIs and non-http(s) schemes — so redirect targets are always safe. Responses never echo user input.
DDoS: AWS Shield absorbs volumetric attacks at the network edge; AWS WAF blocks known attack signatures (SQLi patterns, XSS payloads, bad bots); rate limiting prevents application-layer exhaustion.
Schema: The core table is URL_MAPPINGS with id (BIGINT PK), short_code (VARCHAR(10), unique indexed), long_url (TEXT), created_at, expires_at (nullable, for expiring links). A unique index on short_code is the primary lookup path for redirects.
Storage engine: DynamoDB (or Cassandra). Single-key lookups match the workload perfectly, it scales horizontally, supports strong reads on create, and has built-in TTL for expires_at. A relational DB would require manual sharding later.
Partitioning: Shard on hash(short_code). Each redirect hits exactly one shard (no scatter/gather), and since codes are random, traffic distributes evenly.
Consistency: Strong on creation — guarantees a short code is never duplicated. Eventual on redirect reads — a brief delay before a new code propagates only risks a transient miss.