System-design interview · Extended interviews
Design a distributed object store
Store large immutable byte sequences behind named keys, with safe publication, authorized reads and measured durability.
You will learn to
- Explain a complete upload and download before distributing storage.
- Separate immutable bytes from mutable names, permissions and upload state.
- Defend multipart completion, replication, retries and deletion without promising impossible atomic uploads.
Practice in this chapter
8 interview questions with model answers and follow-ups.
Go to interview practiceUseful foundations: Replication and durability · Data partitioning and sharding · Quorums, consensus, leases, and fencing · Databases, data models, and ACID transactions
Workload and timing examples are interview assumptions.
Dotted concept links open the relevant explanation in a new tab.
01Separate an object’s name from its bytes
An object store accepts a named sequence of bytes and later returns those bytes. Unlike a filesystem, it does not need to support in-place edits to arbitrary byte offsets. Our product stores tenant-owned videos, exports and backups. Clients create or replace a whole object, read a range, list names and delete a name. Every successful replacement creates an immutable version.
Ask whether clients replace whole objects or need filesystem-style edits, whether reads must immediately see a completed replacement, and which failure must an acknowledged upload survive. This walkthrough chooses whole immutable versions, authoritative current-key reads and one storage-node failure within a region.
Use tenant T7 uploading a 2 GiB video as the running example. Its logical key is videos/launch.mp4; version V5 identifies one exact byte sequence under that key. Keeping those identities separate lets a download finish on V4 while a new upload prepares V5. A key is an address, while a version is a particular saved object.
The complete flow is authorize upload → store temporary bytes → verify them → publish a version → authorize download → read that version. Publication means making a completed object visible under its logical name. Upload progress alone does not make an object readable. This distinction is the basis of retries, concurrent replacements and cleanup throughout the design.
02Functional requirements
Agree on what the service must do before choosing its components.
- Create and replace objects. Support PUT of tenant-owned bytes under a logical key, creating a new immutable version on each successful replacement.
- Read object data and metadata. Support GET, HEAD and ranged GET, plus reads naming an exact version. An existing version-specific reader may finish on the version it selected.
- Resume large uploads. Support multipart sessions, part inspection/retry, explicit completion and abort. Partial bytes must remain invisible as a completed object.
- List and delete names. Support DELETE and paginated key listing with a stable ordering and cursor. Listing is not a snapshot across concurrent changes unless an additional snapshot feature is requested. Filesystem-style in-place edits and cross-region disaster recovery are outside the initial scope.
03Non-functional requirements
Use these hypothetical requirements for the worked interview. Confirm the assumptions with the interviewer; the numerical targets require testing and are not measured results. For latency, p95 and p99 mean that 95% and 99% of measured delays, respectively, are no greater than the reported value.
- Workload. Assume ten million new objects/day averaging 10 MB and one billion reads/day averaging 4 MB returned. The sizing exercise retains thirty days; versions, temporary uploads and peaks require extra capacity.
- Visibility and integrity. After completion succeeds, a new lookup of the logical key must return the new version. Each download returns one complete immutable version with verified length/checksum, never a mixture of versions. Concurrent conditional replacements must detect a conflict.
- Regional durability. An acknowledged upload must survive one storage-node failure, and acknowledged metadata must survive one metadata-node failure. Required durable copies must exist before success; background replication alone does not establish this promise. Region loss needs a separately designed recovery point, recovery time and cost.
- Latency and transfer rate. Target metadata-read p95 below 100 ms and read time-to-first-byte p95 below 250 ms on regional test paths. For large transfers, target at least 50 MiB/s per transfer when the client and network can sustain it. Test under admitted load; a 2 GiB video cannot share a tiny-object completion-latency target.
- Bounded uploads and quotas. For this exercise, accept objects up to 64 GiB and expire incomplete uploads after 24 hours. Start with a default 1 TiB logical-byte quota, including temporary and retained versions, and ten active upload sessions per tenant; larger tiers require explicit configuration. With 64 MiB parts the largest object uses 1,024 parts. Reclaim only unreferenced expired parts.
- Tenant access. Authorize metadata lookup, upload capabilities and byte delivery. A tenant prefix only names data; it does not authorize access. Short-lived download URLs are bearer grants until expiry, so immediate revocation would require an online enforcement path.
04Make one server publish only complete objects
Start with an API, a metadata database and a filesystem on one storage server. A client requests an upload session U31 for T7’s key. The API checks permission and returns an upload identifier. The server writes incoming bytes to a temporary file named by that session, computes a checksum and verifies the declared length. A checksum detects accidental corruption; it does not establish who is allowed to upload.
After the file is complete and durably flushed, establish its immutable version name durably as well; a filesystem rename may require flushing the containing directory before publication. In a metadata transaction, create V5 and change the key’s current-version pointer to V5. Only then return success. A reader first authorizes access, resolves the current version and reads that exact file. It never streams a partially written temporary file.
If the server crashes before metadata publication, an unreferenced file may remain for later cleanup. If it crashes afterward but before replying, retrying completion for U31 returns the recorded V5 result. This ordering avoids a published pointer to bytes that were never durably stored. The baseline is complete but has one storage failure domain and limited disk/network capacity.
The metadata pointer is the visibility boundary.
Read each connection in order
- syncAuthorized uploadUploader or reader → Object API
- syncWrite and verify bytesObject API → Temporary and immutable files
- syncCommit completed versionObject API → Keys and versions
- returnResolve exact versionKeys and versions → Object API
- returnRead selected bytesTemporary and immutable files → Uploader or reader
05Size stored bytes separately from requests
Assume ten million new objects per day with an average size of 10 MB. That is approximately 100 TB of new logical data per day. Retaining thirty days gives 3 PB before versions, temporary uploads and overhead. Three complete replicas require about 9 PB. Use consistent decimal units for this estimate; the running 2 GiB multipart example uses binary units deliberately.
One billion reads per day at an average returned range of 4 MB gives 4 PB/day of output, about 46.3 GB/s on average. Peak demand and popular-object skew require additional capacity. Caching immutable versions can save origin traffic, but an average cache hit rate can hide a single very large hot download.
For the example video, 64 MiB parts produce 32 parts. Four parallel transfers can improve throughput until the client, gateway or storage network saturates. More parallelism then adds connections and retry pressure without speeding the disk.
Metadata entries are much smaller than payloads and follow different access patterns. Scale the metadata database for key lookups and publication transactions; scale storage nodes for bytes, capacity and repair bandwidth. Do not route all large payloads through a single database or control server.
06Give upload sessions and versions different APIs
Create the upload session
POST /uploads
Example request body for the 2 GiB video
{
"tenant": "T7",
"key": "videos/launch.mp4",
"expectedCurrentVersion": "V4",
"totalSizeBytes": 2147483648
}
The request may also include a content checksum. The API validates the 64 GiB size ceiling, reserves the declared logical bytes against the tenant quota, checks the ten-active-upload limit and creates U31 with a 24-hour expiry. Account for concurrent reservations atomically so several uploads cannot each spend the same free quota.
Continue or read an upload
| Operation | Request or result |
|---|---|
PUT /uploads/U31/parts/7 |
Send bytes, part identity, length and checksum. |
POST /uploads/U31/complete |
Supply the ordered part list for publication. |
GET /objects/key |
Resolve the current version of the logical key. |
| Version-specific GET | Read the explicitly named immutable result. |
Metadata records
| Record | Fields | Purpose |
|---|---|---|
| Key | Current version and deletion state | Resolve a mutable logical name. |
| Upload | Owner, expected version, expiry and status | Track the preparation and completion of one upload. |
| Part | Exact stored object identity and checksums | Identify and verify the precise bytes being referenced. |
| Version manifest | Ordered parts and total length | Reconstruct one immutable byte sequence. |
The manifest lists the parts and their order so a reader can reconstruct the video without storing another complete copy.
Use conditional replacement when the caller wants to avoid overwriting another edit. If U31 expects V4 but another upload already published V6, reject U31’s completion with a conflict. An unconditional replacement may instead use an explicit last-committed-writer policy.
Returned object metadata
| Field | Meaning |
|---|---|
| Version identity | The exact immutable object. |
| Length | The object’s byte length. |
| Checksum metadata | Information for verifying the bytes. |
| ETag | An opaque validator under this API. |
Do not teach clients that an ETag must equal the whole object’s MD5 checksum, especially for multipart objects.
07Make completion a small metadata operation
Each part is stored under an immutable identity. A retry of the same part can reuse verified identical bytes; a replacement creates another part generation instead of silently overwriting bytes that a manifest may already reference. The upload record names the exact part generation that completion may include. Before accepting an additional replacement generation, atomically reserve its extra bytes against the same tenant quota; the original declared-size reservation does not cover unlimited superseded parts. Reusing the same verified immutable bytes needs no additional charge. Keep superseded generations charged until safe cleanup reclaims them.
Complete U31 in this order
- Validate the session. Check ownership, expiry, ordered part numbers, lengths and checksums against the reserved total size.
- Freeze exact part identities. Select the generations that the published object will reference.
- Verify durable bytes. Check that those parts meet the required durability policy.
- Publish atomically. In one metadata transaction, mark the upload completed, create V5’s immutable manifest, conditionally change the key pointer and save the completion result.
- Return the saved result. Retrying completion returns V5.
If part 7 is still missing, completion fails while U31 remains recoverable. The client can inspect uploaded parts and send the missing one. If another completion already succeeded, the response identifies that success rather than creating a second version accidentally.
This mechanism avoids copying 2 GiB inside the publication transaction. The transaction changes a small manifest and pointer while the large bytes already exist. It also explains why upload completion is an explicit operation: the service cannot infer that an interrupted connection meant the client intended a complete video.
Retry the upload identity instead of inventing another publication.
Read each connection in order
- syncComplete U31 with verified partsClient → Upload service
- syncPublish V5 and save U31 resultUpload service → Metadata database
- returnResponse lostUpload service → Client
- syncRetry complete U31Client → Upload service
- syncRead completed resultUpload service → Metadata database
- returnReturn V5 againUpload service → Client
08Replicate bytes and keep metadata authoritative
Replace the one disk with storage nodes across independent failure domains. Choose three copies across independent storage failure domains and require all three to be durable before publication. If one required write is unavailable, wait or fail that completion without publishing it. Existing reads can use surviving copies. Three processes on the same disk do not provide this separation.
Use a synchronously replicated metadata authority whose acknowledged commits survive one metadata-node loss. Its conditional transactions prevent two concurrent replacements from both winning an expected-version check. Large transfers can go directly to selected storage endpoints using scoped capabilities. The control service still authorizes sessions and publication; it need not proxy every byte.
Serve public immutable objects through a CDN. Private objects need a cache and delivery policy that preserves authorization; do not accidentally turn a private origin into an anonymously readable cache. Cache identity includes the immutable version and requested range where appropriate.
Background workers check replica health and repair missing copies. Reserve bandwidth for repair during a failure, when serving demand may also rise. Erasure coding is an optional later storage optimization: it uses data and parity fragments to lower storage overhead at the cost of more complex repair and small-read behavior. Replication remains the final interview design.
The API authorizes an upload or read. Scoped transfer permissions address immutable bytes on storage nodes. Completion publishes the metadata pointer only after all three required copies are durable. The CDN path is for public objects; background repair restores missing copies.
Read each connection in order
- syncAuthorize read / upload / completeObject client → Object control API
- syncSession and version transactionObject control API → Replicated metadata authority
- mediaScoped upload or range readObject client → Three durable byte replicas
- syncVerify required durable copiesObject control API → Three durable byte replicas
- mediaRead public immutable versionObject client → Public-object CDN
- mediaFetch missing public bytesPublic-object CDN → Three durable byte replicas
- asyncVerify and restore copiesReplica repair workers → Three durable byte replicas
09Trace a download while a replacement commits
A reader asks for T7’s current video. The API authenticates the actor, checks read permission and resolves V4. It returns or internally retains V4’s immutable manifest. The storage path reads the requested byte range from its listed parts, using another verified replica if a copy is unavailable or corrupt.
Meanwhile U31 publishes V5. A new current-key lookup sees V5, but the existing reader continues with V4. Mixing the first half of V4 and the second half of V5 would produce an object that nobody uploaded. Binding the download to a version prevents that error without blocking replacement for the entire transfer.
A short-lived signed download URL is a bearer capability. Anyone who possesses it may use its allowed scope until expiry, so issue it only after authorization and keep its lifetime appropriate. Immediate revocation requires an authenticated serving gateway or another online enforcement path; a signature alone cannot retract bytes already delivered.
Record whether a failed read is missing metadata, unavailable replicas or corrupt bytes. Those outcomes lead to different recovery actions. A published version whose replicas are temporarily unreachable should not be silently reported as an object that never existed.
10Recover uploads and delete without damaging readers
An upload that never completes consumes temporary space. Expiry and an explicit abort operation let cleanup reclaim its unused parts. Before deleting a part, cleanup checks whether an upload or retained version still needs it. An old upload session does not make a completed version’s bytes disposable.
DELETE first changes the key’s visible metadata according to the retention policy. Version retention may preserve older bytes for recovery, legal policy or active downloads. Apply these cleanup and accounting rules:
| Situation | Permitted action |
|---|---|
| A retained version, active upload or protected reader still needs bytes | Keep the bytes. |
| No such owner remains | The background collector may reclaim the bytes under the retention/grace policy. |
| Stored retained or temporary bytes are reclaimed | Release their storage charges only after reclamation. |
| Upload aborts or expires | Close further part admission and release unused capacity reservations; keep charges for parts still stored. |
| Upload completes | Convert the selected reservation to retained usage without charging twice. Superseded part generations stay separately charged until cleanup. |
Start with conservative retention and a grace period; an exact reference-management protocol is an advanced implementation topic.
After a lost completion response, U31’s durable status answers whether V5 was published. After a node failure, reads use another replica and repair recreates the missing copy. After a metadata outage, reject publication rather than acknowledging an update that cannot be recorded safely.
Keep checksums for corruption detection and independently verify restoration from backups. Replication copies accidental deletion and application mistakes as readily as legitimate updates; retention and backups address different failure modes. Test the complete metadata-plus-byte restore, because restoring only filenames does not reconstruct their contents.
11Observe the promises at their actual boundaries
Measure upload throughput, completion latency, metadata conflicts, time to first byte, range-read failures, replica health, repair backlog and temporary-storage age. Track storage growth by tenant and data class. A service can return fast metadata responses while repair falls behind and durability risk grows.
Enforce byte and request quotas, maximum part counts and concurrency limits. Upload capabilities should bind tenant, session, destination, expiry and permitted operation. Protect storage nodes from arbitrary paths supplied by callers. Verify content length and checksums rather than trusting client declarations as evidence that bytes arrived intact.
Exercise two completions expecting V4, a lost completion reply, a missing part, a corrupt replica, a read spanning a replacement and deletion during a long read. The expected outcomes should be explicit: one conditional winner, stable replay result, recoverable upload, replica fallback and one unchanged download version.
Close the design by identifying its limits. It provides whole-version publication and replicated regional durability, not cross-region survival, a POSIX filesystem or instantaneous revocation of bearer URLs. Add those features only after the interviewer changes the contract and you can explain the new cost.
12Check the design against its requirements
Before closing, check the final design against the agreed requirements. FR means functional requirement and NFR means non-functional requirement; the numbers refer to the lists above. These are proposed validation checks, not test results.
| Requirement | Mechanism in the final design | Validation and remaining limit |
|---|---|---|
| FR 1–3; NFR 2 | Temporary immutable parts precede a transaction publishing the manifest, key pointer and replay result. | Race two replacements, omit a part, lose completion’s reply and read across publication. Require one conditional winner and one unchanged download version. |
| FR 4; NFR 2, 5 | Ordered listing and conservative lifecycle cleanup separate visible names from retained versions. | Delete during a read and expire an incomplete upload. Keep referenced bytes; disclose that a cursor alone is not a listing snapshot. |
| NFR 3 | Three durable byte copies and a synchronously replicated metadata authority precede success. | Lose one storage or metadata node after acknowledgment, verify reads and repair, and reject unsafe publication during loss of authority. Region loss remains outside scope. |
| NFR 1, 4, 5 | Separate metadata and byte paths, scoped transfer endpoints and quotas bound resource use. | Benchmark metadata p95, first byte and large-transfer rate with capable clients, hot objects and repair traffic. Reject oversize or over-quota uploads; measure peak capacity rather than extrapolating averages. |
| NFR 6 | Tenant-bound sessions/capabilities and version-bound reads protect private bytes. | Try another tenant’s key/session and an expired grant. Test the stated bearer-URL lifetime without claiming instant revocation. |
13Rapid revision
Rehearse the numbered functional requirements and non-functional targets first. Use this table to recall the mechanisms, then close with the requirements check above.
Remember: Durable bytes → atomic publication → saved reply.
| Question | Mechanism and boundary |
|---|---|
| What is an object version? | One unchanging byte sequence; the same logical key can later point to another version |
| Why temporary upload state? | Keep partial uploads unreadable until completion verifies the whole object |
| What makes completion atomic? | After durable bytes exist, one metadata transaction publishes the manifest and key pointer |
| Why expected version? | Reject a replacement if another upload already changed the version it expected |
| Why multipart? | Transfer and retry bounded pieces in parallel without restarting the whole upload |
| What survives a lost reply? | The completed upload record returns the same published version |
| Why version-specific reads? | One download cannot mix bytes from old and new versions |
| What do replicas provide? | Survival of the specified copy failures; backups and retention address other losses |
| What may cleanup delete? | Only bytes no active upload, retained version or protected reader still needs |
| What does a signed URL mean? | Time-limited access for its holder; it does not check the current user’s permission on every use |
A useful close is: “I keep names and immutable versions separate. Uploads prepare durable bytes before a small transaction publishes them, and readers bind to one version. Replication handles the selected node failure; conservative lifecycle cleanup and explicit access grants make the limits visible.”
Practise the interview questions
Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.
Why separate a key from a version?
Reveal a model answer
The key is the mutable name users request; a version identifies exact immutable bytes. Replacement changes the pointer while an existing reader finishes on its selected version. This prevents mixed downloads.
Interviewer follow-up
Does a key prefix authorize access?
Reveal the follow-up answer
No. Verify actor, tenant and operation separately at metadata and delivery boundaries.
What the answer must demonstrate: The key is the mutable name users request; a version identifies exact immutable bytes.
What if the process crashes after bytes are written but before publication?
Reveal a model answer
The bytes remain unreferenced temporary work, and the logical object has not changed. A retry can finish the session or cleanup can later reclaim it. Reversing the order could publish a pointer to missing bytes.
Interviewer follow-up
What if the reply is lost after publication?
Reveal the follow-up answer
The completed session records the version and returns that same result on retry.
What the answer must demonstrate: The bytes remain unreferenced temporary work, and the logical object has not changed.
Why split the 2 GiB example into 64 MiB parts?
Reveal a model answer
It creates 32 independently transferable pieces. The client retries a failed part and can use bounded parallelism. Completion verifies the ordered immutable parts and publishes their manifest without copying the entire video in a transaction.
Interviewer follow-up
Can part replacement mutate a published version?
Reveal the follow-up answer
No. Store a new immutable part identity and preserve the identity referenced by the published manifest.
What the answer must demonstrate: It creates 32 independently transferable pieces. The client retries a failed part and can use bounded parallelism.
Two uploads both expect V4. Who wins?
Reveal a model answer
The metadata authority conditionally updates the key. The first committed replacement wins; the other receives a conflict when V4 is no longer current. This is an explicit lost-update policy rather than accidental last-response-wins behavior.
Interviewer follow-up
Can unconditional PUT still be supported?
Reveal the follow-up answer
Yes, if its last-committed-writer semantics are explicit and the caller chooses them.
What the answer must demonstrate: The metadata authority conditionally updates the key.
When may a durable upload be acknowledged?
Reveal a model answer
After all three required independent byte copies are durable and the synchronously replicated metadata publication commits. If a required copy cannot be written, wait or fail completion without publishing it. Merely queueing replication cannot promise survival immediately after success.
Interviewer follow-up
Do three replicas equal three failure domains?
Reveal the follow-up answer
Only if placement actually separates the relevant disks, hosts or zones.
What the answer must demonstrate: After all three required independent byte copies are durable and the synchronously replicated metadata publication commits.
V5 is published midway through a V4 range download. What happens?
Reveal a model answer
The existing download continues against the exact V4 manifest and immutable bytes. A new current-key lookup can select V5. Cleanup retains versions needed by active or retained readers.
Interviewer follow-up
What if a V4 replica is corrupt?
Reveal the follow-up answer
Verify integrity and fetch the same V4 bytes from another replica, then repair the bad copy.
What the answer must demonstrate: The existing download continues against the exact V4 manifest and immutable bytes.
Does revoking membership immediately invalidate a signed URL?
Reveal a model answer
Not necessarily. An ordinary signed URL is a bearer grant until its effective expiry. Short expiry limits exposure; an authenticated gateway can enforce current permission on new delivery requests. Neither recalls bytes already received.
Interviewer follow-up
Can private content use a CDN?
Reveal the follow-up answer
Yes, with an authorization and cache policy designed for private delivery, not an accidentally public object cache.
What the answer must demonstrate: Not necessarily. An ordinary signed URL is a bearer grant until its effective expiry.
Why not delete every old upload part after a day?
Reveal a model answer
A completed version may reference that part, and a retained or active reader may still require it. Cleanup must distinguish expired unreferenced uploads from published data. Conservative retention is the simple starting point.
Interviewer follow-up
Why are backups still needed with replicas?
Reveal the follow-up answer
Replicas can reproduce mistaken deletion or corruption; recoverable historical state addresses different failures.
What the answer must demonstrate: A completed version may reference that part, and a retained or active reader may still require it.
Blank-page exercise · 45 minutes
Build the answer yourself
Design regional object storage for large private videos, including multipart upload, overwrite conflicts and a lost completion response.
- Agree the numbered functional requirements and non-functional targets, including version visibility, regional failure, transfer performance, size limits and quotas.
- Draw the one-server upload/read flow.
- Separate byte and metadata capacity.
- Explain multipart identity and conditional publication.
- Trace a lost response and concurrent replacement.
- Check upload/read/list/delete behavior, durability, transfer targets, access and cleanup against the numbered requirements; distinguish proposed tests from proven results.
Check that each component and design decision follows from your requirements and workload.
Recall the key ideas
Answer from memory before opening each card. Explain why the choice works and what it costs. Revisit missed cards tomorrow.
Design a distributed object storeU31’s completion succeeds but its reply is lost. What does retry return?Recall first, then reveal
Return the saved V5 result. Completion first verifies durable bytes, then commits the manifest, current-version pointer and result together. A retry does not publish another version.
Durable bytes → atomic publication → saved reply.
Return to lessonDesign a distributed object storeA new version is published during a download. Which bytes should the download use?Recall first, then reveal
Keep the same immutable version selected at the start, and read every part from it.
One read, one version
Return to lessonFinal revision
Summary and interview notes
Save and verify immutable bytes first. Then one small metadata transaction makes the complete version available to readers.
Remember these points
- Agree the numbered functional requirements and non-functional targets before designing components; validate the final design against them.
- Keys and versions have different identities.
- Multipart completion saves a replayable result.
- Readers bind to a version.
- Repair, retention and authorization have distinct jobs.
Interview tips
- Trace a replacement while a download is active.
- Express large-transfer performance as throughput as well as latency.
Important qualifications
- Cross-region disaster recovery and exact garbage-collection protocols are optional expansions.
Continue after the core interview
Explore the advanced version
The advanced lesson keeps the full detailed design. Use these sections when you want to examine the stronger requirements and failure cases.
- Erasure coding and repair amplification
Useful when replicated storage cost dominates measured requirements.
- Exact reference-aware reclamation
Requires coordinating upload, version and reader lifetimes at deletion.
- Cross-region disaster recovery
A stronger regional-loss contract needs explicit replication and recovery objectives.
- Fine-grained upload capability enforcement
Expand provider-specific immutable writes and capability constraints during implementation review.
Technical references
- Amazon S3 overview and consistencyProvider-specific object, versioning, permissions, and strong read-after-write capabilities.
- Amazon S3 multipart uploadDocuments upload sessions, ordered part completion, integrity checks, and multipart ETag limitations.
- Amazon S3 presigned URLsDocuments delegated method/key access, reuse, expiry, and credential dependencies.
- Amazon S3 conditional writesProvider-specific create-only and conditional-update options; enforce conditions at storage, not through key naming alone.
Practice marks stay in this browser.