List the key functional requirements for the system (Ask the AI for hints if stuck)...
Given a short Url redirect to original long url
Given a long url generate short url n redirect
Generating alias
List the key non-functional requirements (performance, scalability, reliability, etc.)...
Scale: how many URLs created/day, how many redirects/day
redirect should be fast
reads more less writes sort of 100:1 ratio
should redirects basically never go down
a stored short URL should never get lost
Estimate the scale of the system. Consider daily active users, read/write ratio, storage requirements, bandwidth, and any relevant QPS calculations...
Define the APIs expected from the system. This is your chance to analyze and define the read and write paths so that you can come up with the high-level design...
Write flow (create short URL): Client → Load Balancer → App Server → ID Generator (get next unique number) → base62-encode it → store {short_code: long_url} in DynamoDB → return the short URL to the client
Read flow (redirect): Client → Load Balancer → App Server → check Redis cache for short_code → if hit, return long_url immediately (302 redirect) → if miss, query DynamoDB, populate cache, then return the redirect
POST /api/v1/shorten
Request: { "long_url": "..." }
Response (201): { "short_url": "...", "short_code": "..." }
GET /{short_code}
Response: 302 redirect → Location:
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
when ever a user makes a request at client app/browser i place a loadbalancer which will efficently distributes the loads among the application server can be horizontal scabable depending on the traffic and then Id generator service api call wil be made n depending read call or write call the process will take place for example if reads I place a cache of elasticcache (redis) bcoz we need quicker reads than writing no joins are required and needs ot be fast if not in cache the database will be accessed n brought into the cache similarly for writes the write api call will call id generator n stores writes the new short url against orginal one using Base62 endoing which works using new code generator using increment 1 concept and stores into dynamo db bcoz these are key value pairs n again we dont need much of joins and all n writes can take time as its more reass than write system we can add additional CDN in front just incase of far away region issue
Define the data model. Identify the main entities, their attributes, and relationships. Consider the choice of database type (SQL vs NoSQL) and justify your decision based on access patterns...
Dynamo DB for all reads/writes I will use elastic cache redis for hot links read which will improve the reads
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
Load Balancer: AWS ALBs are managed and multi-AZ by default, but you should explicitly state you're deploying across multiple Availability Zones, not just one
App servers: run at least 2-3 instances across different AZs, behind the load balancer, with auto-scaling group health checks so a failed instance gets replaced automatically
DynamoDB: this is actually already highly available by default — it automatically replicates data across multiple AZs within a region. Worth saying this explicitly rather than assuming the interviewer knows you know it.
Redis/ElastiCache: by default, a single Redis node is a single point of failure. Fix: use ElastiCache with Multi-AZ replication — a primary node plus replica(s), with automatic failover if the primary goes down.
Cross-region: for true disaster recovery (not just AZ failure), you could replicate DynamoDB globally using DynamoDB Global Tables, though this adds complexity/cost — worth mentioning as an option, framed as "if the business requires surviving a full region outage."
Load Balancer
2. Application Servers
3. ID Generator Service
Pre-allocated ID ranges (simplest, most common answer): each app server requests a block of IDs upfront from a coordinator (e.g., "give me IDs 5000-5999"), then hands them out locally without needing to call the generator on every single request. If a server crashes with unused IDs in its block, those IDs are simply wasted — acceptable trade-off, since ID space is effectively infinite. This avoids split-brain entirely because ranges are only ever assigned once, from one authoritative store (e.g., a single row in DynamoDB with a conditional atomic increment).
4. Cache Layer (Redis/ElastiCache)
Cache miss handling: this is the cache-aside pattern we already named — on a miss, the app server queries DynamoDB directly, gets the long_url, writes it into Redis, then returns the redirect to the client. Worth stating explicitly that this write-back-on-miss step exists, since the earlier answer implied it but didn't spell it out.
TTL (Time To Live): you don't want the cache growing forever — set a TTL per cache entry (e.g., 24 hours), after which Redis automatically evicts it. If that link is still popular, the next request just re-fetches from DynamoDB and re-populates the cache — a brief moment of extra latency, not a failure.
Eviction policy: also worth naming — Redis supports policies like LRU (Least Recently Used) for when memory fills up, evicting the least-recently-accessed entries first, which naturally keeps your "hot" links cached and lets cold ones fall out.
5. Database (DynamoDB)
6. CDN (CloudFront) — optional/enhancement layer