System Design Fundamentals and Capacity Estimation - Complete Notes
A language-neutral method for turning an unclear product idea into measurable requirements, capacity estimates, architecture decisions, failure plans, and a design that can be explained, tested, operated, and improved.
00. The system-design mental model
System design is the disciplined process of choosing boundaries, data flows, state, and failure behavior that satisfy a specific workload under explicit constraints.
A design is not a collection of fashionable components. It is an argument. Requirements describe the result users and the business need. Estimates describe the expected pressure. The architecture describes how work and state move through the system. Trade-offs explain why this shape is more suitable than credible alternatives. Measurements and tests show whether the argument remains true in production.
Think of designing a bridge. The answer is not "use steel." The engineer first asks what must cross the bridge, how often, in what weather, how much failure is tolerable, how repairs will happen, and what budget exists. Software design follows the same pattern. A database, queue, cache, or framework is a material selected after the load and constraints are understood.
| Question | Design output | Failure when skipped |
|---|---|---|
| What must the system do? | Functional requirements and critical user flows | Solving the wrong problem well |
| How well must it do it? | Latency, availability, durability, security, and cost targets | No objective way to judge the design |
| How much work and data exist? | Traffic, concurrency, bandwidth, storage, and growth estimates | Overbuilding, underbuilding, or missing a bottleneck |
| Where does state live and move? | APIs, events, data models, ownership, and consistency boundaries | Hidden coupling and unreliable dual writes |
| What fails? | Failure modes, fault domains, degraded modes, and recovery plans | A happy-path diagram mistaken for a production design |
| How will we know? | SLIs, SLOs, tests, dashboards, alerts, and review triggers | Opinions replace evidence |
Clarify, quantify, design, challenge, measure, and revise. Every later topic in distributed systems adds tools to this loop, but never replaces it.
01. Start with requirements, not components
Requirements define the decision space. Components are possible answers inside that space.
Functional requirements
Functional requirements describe observable capabilities. They should be written as user or system flows with clear inputs, outputs, and important state changes. "Build a URL shortener" is not precise enough. A useful first scope might say:
- Create a short URL for a valid destination URL.
- Redirect a short code to its active destination.
- Allow an owner to disable or expire a link.
- Record aggregate click counts without slowing the redirect path.
- Prevent a disabled, malicious, or expired link from redirecting.
Separate must-have behavior from optional behavior. Custom aliases, detailed analytics, link previews, geographic routing, QR codes, and campaign management can radically change the design. Do not silently include them. State what is excluded and when the decision should be revisited.
Critical flows and correctness
Not every flow has the same importance. Identify the business-critical and safety-critical paths. A payment authorization may require stronger consistency and auditability than an analytics counter. A redirect may prioritize latency and availability, while link creation can accept a slightly slower response.
| Flow | Correctness rule | Likely priority |
|---|---|---|
| Create link | One allocated code identifies exactly one destination | Correctness, durability, then latency |
| Redirect | Return the current allowed destination or a clear failure | Availability and tail latency |
| Disable link | Disabled links stop redirecting within the stated propagation bound | Security and bounded staleness |
| Count click | Approximate analytics may lag but must not block redirects | Throughput and cost |
High-value clarification questions
- Who are the users, tenants, administrators, and dependent systems?
- Which operations are reads, writes, streams, jobs, or scheduled work?
- Which result must be immediately consistent, and which may be stale?
- What data loss, duplication, or reordering is acceptable?
- What happens when a dependency is slow, unavailable, or returns an uncertain result?
- Which regions, devices, protocols, accessibility needs, and regulations apply?
- What is the expected launch load, peak load, growth rate, and retention period?
- Which requirement is expensive enough that changing it would simplify the design?
If the stakeholder does not know a number, choose a documented assumption and continue. A visible assumption can be corrected. A hidden assumption silently corrupts every downstream decision.
02. Non-functional requirements and quality attributes
Non-functional requirements describe how the system must behave while delivering its functions.
| Attribute | Useful question | Example target |
|---|---|---|
| Latency | How quickly must a user-visible operation finish? | 99% of redirects complete within 150 ms |
| Throughput | How much useful work must finish per unit of time? | Sustain 20,000 redirects per second at peak |
| Availability | What fraction of valid requests must succeed? | 99.95% successful redirects per calendar month |
| Durability | What acknowledged state may be lost? | No acknowledged link creations lost after a single-zone failure |
| Consistency | How current and coordinated must observations be? | A disabled link stops resolving globally within 60 seconds |
| Scalability | How efficiently does capacity grow with resources? | Double redirect capacity with at most 2.2 times the serving cost |
| Security | What must be protected from whom? | Only an owner or administrator can mutate a link |
| Privacy | Which personal data is collected, retained, or shared? | Do not store raw client IP addresses in long-term analytics |
| Operability | Can people detect, diagnose, mitigate, and recover? | On-call can disable link creation independently of redirects |
| Cost | What budget and cost-per-unit are acceptable? | Keep redirect infrastructure below a stated cost per million requests |
Quality attributes conflict. Stronger durability may add synchronous replicas and latency. Lower tail latency may require more idle capacity. More detailed analytics can increase storage cost and privacy risk. A design review should expose these tensions and state which attribute wins for each critical flow.
03. SLIs, SLOs, SLAs, and error budgets
A reliability statement is useful only when its event, threshold, population, and measurement window are explicit.
- Service level indicator, or SLI
- A quantitative measure of service behavior, such as the proportion of valid redirect requests that succeed or the distribution of end-to-end latency.
- Service level objective, or SLO
- A target for an SLI over a defined window, such as 99.95% successful redirects over a calendar month.
- Service level agreement, or SLA
- A business or contractual commitment that normally includes consequences when the commitment is not met. An internal SLO is commonly stricter than the public SLA.
- Error budget
-
The allowed amount of unsuccessful service implied by an SLO. For a success-rate SLO, the budget
is usually
1 - SLOover the measurement window.
SLI =
valid redirect requests returning the correct redirect or approved not-found response
-------------------------------------------------------------------------------
all valid redirect requests received at the public edge
SLO =
SLI >= 99.95% over each calendar month
Latency objective =
99% of successful redirects complete within 150 ms at the public edge
Define which requests count. Exclude synthetic load only if it is separately controlled. Decide whether client cancellations, invalid input, rate-limited abuse, and dependency-caused failures count. Measure as close to the user as practical. A server may report success after the client has already timed out.
Availability and budget math
Time-based availability is intuitive but request-based availability often matches user experience better. A ten-minute outage at peak traffic affects more requests than a ten-minute outage during an idle period.
| Monthly availability target | Approximate unavailable time in a 30-day month | Error budget per 1,000,000 requests |
|---|---|---|
| 99% | 7 hours 12 minutes | 10,000 failed requests |
| 99.9% | 43 minutes 12 seconds | 1,000 failed requests |
| 99.95% | 21 minutes 36 seconds | 500 failed requests |
| 99.99% | 4 minutes 19 seconds | 100 failed requests |
More nines are not free. They demand smaller failure domains, more automation, safer changes, faster detection, tested recovery, dependency alignment, and spare capacity. Choose a target from user and business needs, not prestige.
04. Build a workload model
Capacity estimates start with counts and distributions, not machine types.
Record at least these workload dimensions:
- Daily and monthly active users, tenants, devices, or producers.
- Operations per active user and the read-to-write ratio.
- Average, peak, and exceptional traffic rather than one average value.
- Request and response sizes, object sizes, and batch sizes.
- Data retention, update frequency, deletion policy, and annual growth.
- Geographic distribution and time-zone-driven peaks.
- Interactive, background, scheduled, and replay traffic.
- Hot-key, celebrity, tenant-skew, and large-payload distributions.
Average is a baseline, not a capacity target
Average requests per second are useful for checking arithmetic. Production capacity must account for peaks, retries, maintenance, deployments, failures, uneven balancing, and future growth. Model at least:
- Normal peak: a predictable busy interval the system must serve routinely.
- Failure peak: the same demand after losing a zone, replica, or dependency path.
- Exceptional event: a campaign, breaking-news event, customer import, or replay.
- Recovery load: queued work, cache warming, replication catch-up, and retries.
average requests per second =
requests per day / 86,400
peak requests per second =
average requests per second * measured or assumed peak factor
concurrent in-flight requests =
arrival rate per second * average time in system in seconds
annual objects =
writes per second * 86,400 * 365
raw storage =
object count * average stored bytes per object
A guessed five-times peak is not a law. Record it as an assumption, instrument real traffic, and replace it with observed percentiles. Some workloads are nearly flat. Others can jump by hundreds of times in seconds.
05. Back-of-the-envelope estimation
Estimation finds orders of magnitude, impossible assumptions, and likely bottlenecks before detailed implementation begins.
Traffic and concurrency
Separate operations because their costs differ. A cached lookup, database write, full-text search, image upload, and analytics aggregation cannot share one meaningful requests-per-second number. Estimate each critical flow.
Concurrency connects throughput and latency. Little's Law states that, for a stable system, average items in the system equal average arrival rate multiplied by average time in the system. At 20,000 requests per second and 0.1 seconds average completion time, approximately 2,000 requests are in flight. If latency rises to one second while arrivals stay constant, concurrency becomes 20,000. That can exhaust sockets, threads, memory, database connections, and queues.
Storage
Estimate more than payload bytes:
logical data
+ row or document metadata
+ primary and secondary indexes
+ write-ahead or replication logs
+ replicas
+ temporary compaction or migration space
+ backups and retained snapshots
+ safety headroom
= provisioned storage
Compression, deletion, index structure, update rate, and replication can move the result substantially. State a range and identify the inputs that need measurement.
Bandwidth
Estimate ingress and egress separately. Include protocol overhead, replication, backups, cache fills, internal fan-out, and cross-region traffic. A 500-byte response at 20,000 responses per second is 10 MB/s of application payload, or about 80 Mb/s before overhead. If one external request causes five internal requests, internal network traffic can dominate.
Compute and instance count
Convert load into instances only after benchmarking representative work. Use a safe operating capacity below the observed breaking point. If one instance can sustain 5,000 requests per second in a realistic test but latency begins to rise sharply above 60% CPU, design around the tested safe capacity, not the final successful request.
safe capacity per instance = 3,000 requests/second
normal peak = 20,000 requests/second
instances for traffic = ceil(20,000 / 3,000) = 7
Three-zone layout:
4 instances per zone = 12 total
lose one zone = 8 remaining
remaining capacity = 8 * 3,000 = 24,000 requests/second
This simple model has deliberate spare capacity and survives a zone loss at normal peak. It still requires tests for balancing efficiency, dependency capacity, deployment overlap, and exceptional traffic.
Small TypeScript estimation helper
A script can make assumptions repeatable, but the model matters more than the language. Keep the variables readable and store the assumptions beside the result.
type EstimateInput = {
monthlyWrites: number;
readsPerWrite: number;
peakFactor: number;
averageLatencyMs: number;
bytesPerRecord: number;
retentionYears: number;
};
function estimate(input: EstimateInput) {
const secondsPerMonth = 30 * 24 * 60 * 60;
const averageWriteRps = input.monthlyWrites / secondsPerMonth;
const averageReadRps = averageWriteRps * input.readsPerWrite;
const peakReadRps = averageReadRps * input.peakFactor;
const concurrentReads = peakReadRps * (input.averageLatencyMs / 1000);
const retainedRecords = input.monthlyWrites * 12 * input.retentionYears;
const rawStorageBytes = retainedRecords * input.bytesPerRecord;
return {
averageWriteRps,
averageReadRps,
peakReadRps,
concurrentReads,
retainedRecords,
rawStorageBytes,
};
}
Production models should include ranges and sensitivity analysis. If doubling one assumption changes the architecture, that assumption deserves measurement and an explicit review trigger.
06. Latency, throughput, and percentiles
Throughput says how much work completes. Latency says how long individual work takes. Both change under load.
Averages hide users in the slow tail. Report a distribution using percentiles such as p50, p95, p99, and p99.9. If p99 is 400 ms, approximately one request in one hundred is slower than 400 ms during the measurement window. Percentiles must identify the population, location, and window.
| Measure | What it reveals | Common mistake |
|---|---|---|
| p50 | Typical request experience | Treating it as proof that almost everyone is fast |
| p95 | Broad tail behavior | Ignoring the remaining 5% at high volume |
| p99 or p99.9 | Rare but user-visible slow paths | Using a sample too small to estimate it reliably |
| Throughput | Completed useful work per interval | Counting accepted or queued work as completed work |
| Saturation | How close a constrained resource is to its useful limit | Watching CPU while a connection pool or lock is exhausted |
Latency normally rises nonlinearly near saturation because work waits in queues. A service can appear healthy at average load and cross a performance cliff during a modest spike. Load tests should find both the sustainable capacity and the failure behavior beyond it.
07. Availability, reliability, durability, and recoverability
These words describe different promises and should not be used interchangeably.
- Availability
- The system can provide the defined service when requested.
- Reliability
- The system continues to perform correctly over time under stated conditions.
- Durability
- Acknowledged data remains intact over the promised retention period.
- Recoverability
- The system can restore service and data within stated recovery targets.
- Resilience
- The system can absorb, adapt to, and recover from faults without unacceptable harm.
A service may be highly available but return stale or incorrect data. A storage system may keep data durably while its read API is unavailable. A replicated database may lose multiple copies through one bad deletion propagated everywhere. Backups improve recoverability only after restore tests demonstrate that they are complete and usable.
Dependency availability
A serial critical path cannot be more available than its required dependencies. If a request
requires services A and B, each with 99.9% independent availability, the rough combined
availability is 0.999 * 0.999 = 99.8001%. Real failures are often correlated, so
simple multiplication can be optimistic.
Remove unnecessary hard dependencies from critical paths. Cache stable configuration, make optional analytics asynchronous, define degraded modes, and ensure the control plane is not required for every data-plane request.
08. Boundaries, state, and critical paths
A useful high-level design shows ownership and communication, not every class or cloud icon.
For each component, answer:
- What responsibility and data does it own?
- Which API, event, or protocol crosses its boundary?
- Is the interaction synchronous or asynchronous?
- What is the timeout, retry, and idempotency behavior?
- What happens if it is slow, unavailable, duplicated, or partitioned?
- How does it scale, deploy, observe, secure, and recover?
Client
|
v
Public edge and rate limit
|
v
Stateless redirect service
| cache hit
+----------------------> Return redirect
|
| cache miss
v
Durable link store ------> Fill cache ------> Return redirect
|
+---- asynchronous click event ----> Analytics pipeline
The critical redirect path excludes analytics. A slow analytics system should not make redirects fail. This is an architectural decision derived from flow priority, not a preference for queues.
Single points of failure and hidden shared fate
Multiple instances do not create redundancy when they share one database, one network path, one certificate, one deployment, one configuration service, or one operator mistake. Identify shared fate across compute, storage, network, identity, configuration, deployment, and people.
09. Failure domains, redundancy, and headroom
Redundancy is useful only when replicas do not fail together and the remaining capacity can carry the load.
Common failure domains include a process, host, rack, zone, region, network provider, identity provider, deployment wave, software version, account, and administrative control plane. Map each critical component to the failures it must survive.
| Design question | Evidence required |
|---|---|
| Can one zone fail? | Remaining-zone capacity, data placement, routing, and a fault test |
| Can one deployment fail? | Progressive rollout, compatibility, fast rollback, and separated waves |
| Can the control plane fail? | Data plane continues with last known safe configuration |
| Can a credential be revoked? | Rotation procedure that does not require simultaneous global change |
| Can backup recovery meet the promise? | Timed restore tests and verified application-level integrity |
Headroom is deliberate spare capacity for peaks, failures, deployments, and uncertainty. It is not waste when it protects an explicit reliability target. Measure headroom at every constrained dependency, not only at stateless application servers.
10. Diagrams and decision records
Different diagrams answer different questions. One overloaded diagram answers none of them well.
- Context diagram: users, external systems, trust boundaries, and the system.
- Container or component diagram: deployable units, data stores, and ownership.
- Data-flow diagram: where sensitive or durable data enters, moves, and rests.
- Sequence diagram: ordering, timeouts, retries, and failures in one flow.
- Deployment diagram: zones, regions, networks, replicas, and fault domains.
- State machine: valid states, transitions, retries, and terminal outcomes.
Label arrows with protocols and whether they are synchronous or asynchronous. Label stores with the data they own. Add trust and failure boundaries. A diagram that says only "service talks to database" hides the decisions that reviewers need.
Architecture decision records
An architecture decision record, or ADR, captures context, the chosen decision, alternatives, consequences, and review triggers. It prevents a current decision from becoming an unexplained permanent rule.
Title:
Status:
Context and constraints:
Decision:
Alternatives considered:
Positive consequences:
Negative consequences and risks:
Measurements and safeguards:
Revisit when:
11. A repeatable design method
A consistent sequence keeps interviews and real design reviews focused on the highest-risk decisions.
- Clarify scope. Identify actors, must-have flows, exclusions, correctness rules, and business priorities.
- Define quality targets. State latency, availability, durability, consistency, security, privacy, retention, recovery, and cost requirements.
- Estimate load. Calculate average and peak traffic, concurrency, bandwidth, storage, growth, and failure capacity.
- Define contracts and data. Sketch APIs, events, idempotency, primary entities, ownership, indexes, and state transitions.
- Draw the high-level design. Show critical synchronous paths, asynchronous work, stores, caches, and external dependencies.
- Deep-dive the risks. Examine hot paths, contention, consistency, partitions, security boundaries, data loss, overload, and migrations.
- Challenge failures. Remove a process, zone, dependency, credential, network path, and operator assumption. Describe degraded behavior and recovery.
- Make it operable. Define SLIs, dashboards, alerts, runbooks, capacity signals, deployment safety, and restore tests.
- Summarize trade-offs. State what the design optimizes, what it sacrifices, and which changes would force a redesign.
Clarify before drawing. Estimate before scaling. Present one simple correct design before evolving it. Spend depth on the largest risk instead of naming every technology you know.
12. Worked design: URL-shortening service
This first-pass design demonstrates the method. It is not the only correct design.
Requirements and assumptions
- Create 100 million short links per month.
- Serve 100 redirects for every link creation.
- Retain links for five years unless an owner deletes or expires them.
- Normal peak is five times average traffic.
- Redirect SLO is 99.95% successful requests per month.
- Redirect latency target is p99 below 150 ms at the public edge.
- A disabled link must stop redirecting globally within 60 seconds.
- Click analytics may be delayed and may use approximate aggregates.
Custom aliases, detailed visitor analytics, preview generation, and billing are outside the first version. The design leaves places to add them later.
Capacity calculation
100,000,000 creates/month
/ 2,592,000 seconds/month
= about 38.6 average creates/second
100 redirects per create
= about 3,860 average redirects/second
5x normal peak
= about 200 creates/second
= about 20,000 redirects/second
At 100 ms average redirect time:
20,000 * 0.1 = about 2,000 concurrent redirects
100,000,000 links/month * 12 * 5 years
= 6,000,000,000 retained links
Assume 250 bytes logical storage/link:
6 billion * 250 bytes = about 1.5 TB raw
With 3 replicas:
about 4.5 TB before indexes, logs, backups, migration space, and headroom
Planning range:
about 7 to 10 TB provisioned for primary serving data and indexes,
with backups budgeted separately
The range matters more than false precision. Measure actual destination length, metadata, index size, compression, expiration, and backup policy before provisioning.
Short-code space
Eight base-62 characters provide 62^8, or roughly 218 trillion combinations. Six
billion retained links occupy a small fraction of that space. Random generation still needs a
uniqueness check and retry. An allocated numeric ID encoded as base 62 avoids random collisions
but introduces an ID-allocation and predictability decision. The API must also prevent enumeration
from exposing private metadata.
Minimal API contracts
POST /links
Idempotency-Key: client-generated-key
{ "destination": "https://example.com/article", "expiresAt": null }
201 Created
{ "code": "aZ91kLm2", "shortUrl": "https://sho.rt/aZ91kLm2" }
GET /{code}
302 Found
Location: https://example.com/article
DELETE /links/{code}
204 No Content
Creation uses an idempotency key so a client timeout and retry do not create multiple links. Redirect returns not found or gone for missing, expired, disabled, or blocked codes according to a documented policy.
Data model
| Field | Purpose |
|---|---|
code |
Unique primary lookup key |
destination |
Validated destination URL |
owner_id |
Authorization and tenant boundary |
status |
Active, disabled, expired, or blocked |
created_at, expires_at |
Lifecycle and retention |
version |
Cache invalidation and concurrent update control |
The primary access pattern is an exact lookup by code. The owner-management path needs a secondary access pattern by owner and creation time. Click analytics should not update the primary link row on every redirect because that creates contention on popular links.
High-level architecture
+----------------------+
Client -> Edge -> Router | Redirect service |
+----------+-----------+
|
cache | lookup
v
+----------------------+
| Distributed cache |
+----------+-----------+
| miss
v
+----------------------+
| Durable link store |
+----------------------+
Redirect service -> durable event buffer -> analytics consumers -> aggregate store
Authenticated client -> management service -> durable link store -> cache invalidation
Redirect instances are stateless and spread across failure domains. The cache serves hot codes and reduces database reads. Cache misses fall through to the durable store and fill the cache. The redirect response does not wait for analytics. Management writes commit to the durable store before invalidation is published.
Consistency and failure behavior
- Cache unavailable: fall back to a protected database path with concurrency limits. Do not allow cache failure to overload the database.
- Store unavailable: cached active links may continue during a carefully bounded degraded mode, but new links and cache misses fail clearly.
- Invalidation delayed: cache entries use a TTL no greater than the promised disable propagation window, and urgent blocks may use an edge denylist.
- Analytics unavailable: buffer events durably up to a capacity limit, sample or drop noncritical analytics according to policy, and keep redirects serving.
- One zone unavailable: routing removes the zone and remaining zones have enough tested capacity for peak traffic.
Evolution triggers
Do not shard on day one only because the long-term count is large. Begin with a store that meets the current load and has a measured growth path. Revisit partitioning when storage size, write rate, index maintenance, replica lag, or operational windows approach tested limits. Revisit global placement when user latency or regional recovery targets require it.
13. Security, privacy, and abuse requirements
Security is a design input, not a final checklist added after components are chosen.
At minimum, identify:
- Assets: credentials, destinations, ownership, click metadata, and administrative controls.
- Actors: anonymous users, owners, administrators, services, attackers, and insiders.
- Trust boundaries: public edge, internal services, data stores, operations, and third parties.
- Abuse: phishing, malware redirects, enumeration, scraping, denial of service, and quota evasion.
- Privacy: IP addresses, user agents, location, referrers, retention, deletion, and access logs.
Validate destination schemes and length, prevent unsafe internal destinations where server-side fetching exists, rate-limit creation and redirect abuse separately, authorize mutations by owner, audit administrative actions, encrypt traffic and durable data, rotate credentials, and define a fast block mechanism. Avoid collecting analytics fields that have no product purpose.
Authentication, encryption, malware scanning, audit logging, and rate-limit checks consume CPU, storage, and dependency capacity. Include them in the critical path and benchmark, not only in a policy document.
14. Production readiness and observability
A design is incomplete until operators can understand its health and safely change it.
Signals
- Request rate, success rate, latency percentiles, and payload distributions by operation.
- Queue depth, age of oldest work, consumption rate, retries, and dead-letter volume.
- Cache hit ratio, miss latency, eviction rate, hot keys, errors, and memory pressure.
- Database latency, throughput, connection use, lock waits, replication lag, and storage growth.
- CPU, memory, garbage collection where applicable, sockets, threads, event-loop lag, and saturation.
- Error-budget consumption and burn rate for each critical SLO.
Break down metrics only by bounded-cardinality dimensions. A short code, URL, user ID, or request ID must not become a metric label. Use logs or traces for high-cardinality investigation, with redaction and access controls.
Safe change
- Backward-compatible API, event, and schema changes.
- Progressive rollout with automated health comparison and rollback.
- Capacity for old and new versions during deployment.
- Feature flags with owners, expiry, safe defaults, and failure behavior.
- Runbooks for dependency failure, overload, data corruption, credential loss, and rollback.
- Regular restore, failover, and degraded-mode tests.
15. Testing the design assumptions
Tests should target the claims that justify the architecture.
| Test | Question answered |
|---|---|
| Unit and property tests | Are estimators, ID rules, state transitions, and validators correct? |
| Integration tests | Do contracts, persistence, timeouts, and error mappings work with real dependencies? |
| Contract tests | Can clients and services evolve independently without accidental breakage? |
| Load test | Does the system meet SLOs at normal peak and expected data size? |
| Stress test | Where is the performance cliff and how does overload fail? |
| Soak test | Do leaks, compaction, cache churn, or background work appear over time? |
| Fault test | Does losing a process, zone, network path, cache, or store match the failure plan? |
| Recovery test | Can operators restore service and data within the promised time? |
Use production-shaped data and traffic. A database with ten rows does not exercise index depth, cache behavior, compaction, query planning, or storage limits. A load test with no failures does not validate failure capacity.
16. Trade-offs and review triggers
A good design makes reversible decisions cheaply and records when expensive decisions must be revisited.
Classify decisions by cost of reversal. Naming, payload shape, public API semantics, data ownership, partition keys, and externally visible consistency can be costly to change. Instance sizes and many internal libraries are easier to replace. Spend review time accordingly.
| Decision | Current reason | Revisit when |
|---|---|---|
| One primary link store | Current write rate and data size fit tested limits | Storage, write rate, maintenance, or recovery approaches a limit |
| Asynchronous analytics | Analytics is not required for redirect correctness | A product contract requires real-time exact counts |
| Bounded cache staleness | Fast redirects with a 60-second disable guarantee | Safety policy requires immediate global revocation |
| Single-region write ownership | Simpler correctness and current recovery target | Regional write availability or latency becomes a hard requirement |
17. Common mistakes and corrections
| Mistake | Why it fails | Correction |
|---|---|---|
| Starting with a technology list | The design has no workload or requirement argument | Clarify flows, targets, and estimates first |
| Using only daily averages | Peaks and failure capacity determine saturation | Model normal peak, failure peak, events, and recovery |
| Giving one exact capacity number | Inputs are uncertain and distributions matter | Use ranges, headroom, sensitivity analysis, and measurements |
| Treating p99 as a maximum | One percent of requests are slower | Define timeout, failure, and extreme-tail behavior |
| Calling replicas highly available | They may share fate or lack remaining capacity | Map fault domains and test the intended loss |
| Ignoring dependency objectives | A hard dependency can consume the service budget | Align objectives, remove hard paths, and design degradation |
| Equating durability with backup | Untested backups may be incomplete or too slow to restore | Define RPO and RTO and perform restore tests |
| Adding cache, queue, or microservices automatically | Each adds failure modes and operational cost | Add a component only for a named requirement or bottleneck |
| Designing only the happy path | Partial and slow failures dominate distributed incidents | Write failure timelines and degraded behavior |
| Claiming infinite scale | Every design has finite resources and coordination points | Name the next bottleneck and its review trigger |
18. Practice exercises
- A service receives 120 million requests per day with a six-times peak factor. Calculate average and peak requests per second. Add 40% headroom.
- Peak traffic is 50,000 requests per second and average latency is 240 ms. Estimate in-flight concurrency. Recalculate at 1.5 seconds during overload and explain the operational effect.
- Design SLIs and SLOs for redirect, creation, disable, and analytics flows. State which failures count and where measurements are taken.
- Estimate five-year storage for 20 million 800-byte records per month with three replicas, 60% index overhead, and 30% headroom.
- Draw a context, data-flow, sequence, and deployment diagram for the URL shortener. Explain the different question each diagram answers.
- Remove the cache, primary store, one zone, event buffer, and identity provider one at a time. Define user behavior, protection, signals, mitigation, and recovery.
- The product changes link-disable propagation from 60 seconds to one second. Identify every design, cost, capacity, and operational decision that must be revisited.
- Write an ADR comparing random short codes with allocated numeric IDs encoded as base 62.
- Create a load-test plan that finds sustainable capacity and the failure mode beyond saturation.
- Review a design that uses ten services, three databases, two queues, and a cache for 100 requests per minute. Identify unnecessary complexity and propose a simpler baseline.
19. Interview questions and model answers
1. Functional versus non-functional requirements?
Functional requirements describe capabilities and state changes, such as creating and resolving a short link. Non-functional requirements describe qualities and constraints, such as p99 latency, availability, durability, privacy, and cost. The distinction helps select architecture, but both must be testable.
2. Why estimate before choosing components?
Estimates reveal the order of magnitude and workload shape. A design for 100 requests per second and 10 GB differs from one for 100,000 requests per second and 10 PB. Estimates also expose whether the main problem is compute, storage, bandwidth, concurrency, or operational complexity.
3. Why is average requests per second insufficient?
Capacity is consumed during peaks, failures, deployments, retries, and recovery. An average hides bursts and uneven distributions. Model normal peak, failure peak, exceptional events, and backlog recovery, then validate with real traffic.
4. How does Little's Law help?
For a stable system, average in-flight work equals arrival rate multiplied by average time in the system. It connects throughput and latency to concurrency. If latency rises while arrivals remain, in-flight work grows and can exhaust bounded resources.
5. Why use latency percentiles?
Latency distributions are normally skewed. A mean can remain acceptable while a meaningful fraction of users is very slow. p50 describes typical behavior, while p95, p99, and p99.9 reveal different parts of the tail. Always state population, location, and window.
6. SLI versus SLO versus SLA?
An SLI is the measured behavior. An SLO is the target for that measurement. An SLA is a business or contractual commitment with consequences. Teams usually operate to an internal SLO stricter than the public SLA.
7. What is an error budget?
It is the amount of unreliability allowed by an SLO. A 99.9% success SLO permits 0.1% unsuccessful events in the window. Teams use budget consumption to balance release velocity and reliability work.
8. Availability versus durability?
Availability means the service can be used now. Durability means acknowledged data remains intact. A system can be unavailable while data is safe, or available while returning data that will later be lost.
9. Why not always require more availability nines?
Each additional nine reduces the error budget and demands more isolation, redundancy, automation, testing, and spare capacity. It can slow delivery and increase cost. The target should follow user harm and business need.
10. What is a critical path?
It is the sequence of work and dependencies that must succeed for a critical operation to complete. Optional work should be removed from it when possible. Every hard dependency adds latency and failure exposure.
11. What is a single point of failure?
Any one failure whose loss makes the required service unavailable or incorrect. It can be a process, data store, zone, network path, certificate, deployment, control plane, or human procedure. Multiple replicas are not independent when they share the same failure.
12. Why keep headroom?
Headroom absorbs normal peaks, forecast error, deployments, retries, zone loss, cache warming, and recovery work. It should be tied to a failure and growth model, not chosen as an unexplained percentage.
13. Scalability versus performance?
Performance describes behavior at a particular load and resource level. Scalability describes how performance or throughput changes as load and resources change. A fast single instance may scale poorly because of shared locks or centralized state.
14. Why identify state early?
State determines ownership, consistency, durability, recovery, migration, and scaling boundaries. Stateless compute is easy to replace, while state movement and coordination are usually the hard parts of system evolution.
15. What belongs in an ADR?
Context, constraints, decision, alternatives, positive and negative consequences, safeguards, and review triggers. It records why the decision made sense at the time without pretending it is permanent.
16. How do you find a bottleneck?
Trace the critical path, estimate demand per resource, measure utilization, wait time, queue depth, and throughput, then increase load until useful throughput stops scaling or latency rises sharply. The saturated resource or coordination point is the current bottleneck.
17. How should a system-design interview begin?
Clarify users, must-have flows, scale, quality targets, constraints, and exclusions. State assumptions, estimate the workload, sketch a simple correct design, then deep-dive the largest risks and trade-offs.
18. Why start simple?
Simplicity reduces failure modes, cost, and cognitive load. It establishes a correct baseline and makes each later component answer a named need. Premature distribution can make ordinary correctness and operations much harder.
19. How do you validate a paper design?
Turn assumptions into tests and measurements: representative integration tests, production-shaped load, stress beyond saturation, fault injection, long-running soak tests, restore drills, security tests, and SLO monitoring.
20. What makes a trade-off explanation strong?
It names the requirement being optimized, credible alternatives, costs accepted, risks introduced, safeguards, and the condition that would trigger reevaluation. "Technology X scales" is not enough.
20. Concise cheat sheet
- Requirements first, estimates second, components third.
- Separate must-have functions from optional scope.
- Make latency, availability, durability, consistency, security, and cost measurable.
- Average RPS equals daily requests divided by 86,400.
- Concurrency is approximately arrival rate multiplied by time in system.
- Model normal peak, failure peak, exceptional events, and recovery load.
- Storage includes data, metadata, indexes, logs, replicas, backups, migration space, and headroom.
- Use percentiles for skewed latency, and state the population and window.
- An SLI is a measurement, an SLO is a target, and an SLA is a commitment.
- Error budget is the allowed unreliability implied by the SLO.
- Availability, reliability, durability, recoverability, and resilience are different.
- Every hard dependency adds latency and failure exposure to a critical path.
- Replicas need independent failure domains and enough remaining capacity.
- Draw context, data-flow, sequence, deployment, and state diagrams for different questions.
- Record costly decisions and review triggers in ADRs.
- Name the next bottleneck. No real system scales infinitely.
- Test the claims: capacity, overload, fault behavior, and recovery.
- A good design explains why, what it sacrifices, and when it must change.
21. Official references
- Google SRE Book: Service Level Objectives
- Google SRE Workbook: Implementing SLOs
- Google SRE Workbook: Example Error Budget Policy
- Google SRE Book: Availability Table
- Google SRE Book: Monitoring Distributed Systems
- Google SRE Book: Addressing Cascading Failures
- Google SRE: Non-Abstract Large System Design Workbook
- AWS Builders' Library: Static Stability Using Availability Zones
- AWS Well-Architected Framework
- Microsoft Azure Well-Architected Framework
- Microsoft Azure Reliability Design Review Checklist
- Microsoft Azure Architecture Center: Design to Scale Out