System Design Case Study
Cloud File Storage
A 2 GB video drops into Google Drive or Dropbox on a laptop; a doc is edited offline on a phone; the same folder opens on a desktop, and every rename, share link, and conflict still has to make sense. To the user it is one folder. Under the hood it is a catalog plus a warehouse.
The hard part is not "put a blob in S3." It is keeping correct across devices while storing bytes efficiently with and .
What happens first?
Upload only new pieces to object storage.
One transactional write for name, ACL, chunk list.
Wake sync, search, and notifications.
Other devices catch up without full rescan.
Try it: upload, metadata, and download for file storage
Large uploads use multipart to object storage while a metadata DB owns permissions and tree listings.
- Client
- API
- Metadata DB
- Object store
- CDN
- Parts done
- 0
- Metadata writes
- 0
- Mode
- upload
- Path hop
- 0
Consistency
metadataListing truth lives in the DB; objects alone are not enough for ACLs.
Capacity
multipart0 transfer steps completed.
Security
signed URLTokens expire; revoke by rotating signing keys or object ACL.
Switch between upload and download, then advance the transfer path hop by hop.
What actually happens
The client splits the file with , hashes each piece, and asks whether that hash already exists. Known chunks skip the network; new ones upload via into object storage. Only when every required chunk is durable does the service commit : path, version, , and the ordered chunk list.
That commit also appends to a change log. Other devices later call sync with a and apply added, modified, and deleted entries. If two offline edits race, the product policy creates a conflict copy or last-writer-wins, never silently drops an edit the user thought was saved.
At HLD scale: roughly 1B users, 200M DAU, and petabytes of logical data: metadata stays strongly consistent while chunk storage can garbage-collect eventually. Sharing is just another metadata check before issuing download URLs.
Client chunks file
Hash each piece; skip known hashes
Upload new chunks
Presigned PUT to object storage
Commit metadata
Name, ACL, version, chunk list
Publish change log
Kafka wakes sync and search
Devices sync deltas
Cursor-based catch-up + conflict rules
How to choose the shape of the system
1. Is this a catalog fact or a byte? Names, folders, versions, and permissions belong in . Raw bytes belong in object storage keyed by hash. Mixing them makes sync and sharing brittle.
2. Can the upload resume? Large files fail mid-flight. Design and session state so retries are cheap and the final commit is atomic.
3. What if two devices diverge? Decide conflict policy early. A conflict copy is usually safer than last-writer-wins for user documents; either way, sync must converge without losing either edit.
Simple rule of thumb
Treat Drive as a strongly consistent tree pointing at . Commit metadata only after chunks are durable, fan out through a change log, and let devices catch up with a . Check before every download URL.
In simple terms: the folder view is the hard system; S3 is the warehouse. Design the catalog first.
Related building blocks
Object storage, queues, caching, and CDN for shared downloads.
High-level design diagram
Follow section 13 data flow: upload → chunk → metadata → Kafka → sync → share/download.

API waits for metadata response
Kafka change log fan-out
Chunks to object storage
Sync, permissions, conflicts
Design highlights (from the diagram)
Architecture layer by layer
01Clients, edge, and gatewayWeb, desktop, mobile, and CLI hit a secure front door.
Web, desktop, mobile, and CLI hit a secure front door.
In plain terms: The reception desk before anyone touches the filing room.
Web and mobile clients interact with APIs, while desktop agents also watch local changes and maintain a sync database. DNS routes them to an available service region; a CDN serves static application assets and permitted downloads. The gateway authenticates users and devices, applies quotas and request limits, and routes metadata operations without proxying every large file through the application tier.
Account sign-in can use OAuth or OpenID Connect, with multi-factor authentication and device management where the product requires them. Those mechanisms establish identity; each file operation still needs a current permission decision. A device with an open sync connection must lose access when its session or membership is revoked, so long-lived connections cannot bypass policy changes.
02File operations servicesUpload, download, metadata, sync, sharing, trash.
Upload, download, metadata, sync, sharing, trash.
In plain terms: Specialist clerks: intake, checkout, catalog, and lending desk.
An upload session records the intended file, base version, expected chunks, and expiry. The client uploads missing chunks with checksums and resumes only failed parts after interruption. Download authorization returns the exact committed version and supports ranged or parallel chunk reads. A completed transfer is distinct from publishing a new file version in the catalog.
Metadata operations create, move, rename, share, and delete stable file identifiers; paths are mutable views of those identifiers. Sync returns ordered changes since a device cursor, including deletion markers. Trash and restore preserve references according to a retention policy. These services must agree on version and permission checks so a stale rename or restore cannot overwrite a newer change.
03Metadata, search, and change logStrong consistency for names, permissions, and versions.
Strong consistency for names, permissions, and versions.
In plain terms: The card catalog and audit ledger, not the warehouse shelves.
The authoritative catalog stores stable file and folder identifiers, parent relationships, permissions, version pointers, and the chunk manifest for each retained version. Pick a database and transaction model that can enforce these invariants; naming a distributed key-value store does not automatically make a move, permission update, or version commit strongly consistent. Use conditional writes or appropriate transactions for the actual access pattern.
A committed metadata mutation also records a durable journal or outbox entry. A relay publishes that change to Kafka for sync notifications, search indexing, and audit processing, with replay-safe identifiers. Search can lag, but its results still need authorization before content is disclosed. The audit trail records who changed which version or permission, allowing failures and unexpected access changes to be reconstructed.
Separate . Permission checks run on every read/write path; invalidate caches when ACLs change.
04Object storage and deduplicationBytes live in S3/GCS; files are ordered lists of chunk hashes.
Bytes live in S3/GCS; files are ordered lists of chunk hashes.
In plain terms: Warehouse bins labeled by fingerprint: many files can share one bin.
Store immutable chunks under a verified content hash and represent a file version as an ordered manifest of hashes. Fixed-size chunks are simple; content-defined chunking finds boundaries in the bytes so some small edits preserve more existing chunks. Savings depend on the workload, chunk sizes, and encryption design, so measure reuse rather than assuming a fixed percentage. Deduplication must stay within the intended tenant and authorization boundary.
Publish a manifest only after all referenced chunks are durably available and their references are protected from garbage collection. Retained versions, trash, and active uploads can all keep chunks live. A delayed reference-count event is insufficient proof that deletion is safe. Coordinate reference creation with a deleting state or pins, wait through the retention grace period, and recheck authoritative reachability before removing bytes.
changes chunk boundaries according to content; compare its reuse rate and CPU cost against fixed-size chunks using representative edits. Chunk deletion depends on the reachability of every retained file version, not merely a momentary zero counter. Upload pins and a metadata-coordinated deletion state prevent a collector from removing a chunk while a new version is acquiring a reference.
05Sync and conflict resolutionKeep laptops, phones, and web in sync without losing edits.
Keep laptops, phones, and web in sync without losing edits.
In plain terms: Two people editing the same shared notebook: need rules when both change page 3 offline.
Each device keeps a local database, pending edits, and the last journal position it applied successfully. A sync response contains added, changed, and deleted entries after that cursor. Apply the delta and advance the local cursor together so a crash causes safe replay instead of skipping changes. WebSockets or SSE can announce that newer changes exist, but the client still fetches authoritative deltas.
An edit names the version on which it was based. If another device already committed a newer version, the server detects the conflict rather than silently replacing it. Preserve both versions, create a conflict copy, or apply a content-specific merge policy. If a cursor is older than journal retention, request a fresh snapshot and reconcile pending local edits instead of pretending the missing history was empty.
Clients poll or push using a . When versions diverge, apply policy, never silently drop both edits without a rule.
06Permissions, links, and collaborationWho can view or edit; public links with expiry.
Who can view or edit; public links with expiry.
In plain terms: Library lending cards and guest passes with expiration dates.
Permissions combine account or workspace roles with the product’s file and folder inheritance rules. Specify how inherited grants, explicit exceptions, and moves between folders interact; deny-overrides is one possible policy, not a universal filesystem rule. A share link delegates a bounded capability, such as viewing one file until expiry, and should not silently grant editing or access to sibling files.
Revocation must reach download authorization, existing sync subscriptions, and relevant caches. A previously issued signed download URL may remain usable until its own expiry unless the delivery system provides a stronger revocation mechanism, so choose the lifetime deliberately. Sharing and commenting publish asynchronous notification events, while real-time collaborative editing requires an additional merge protocol beyond ordinary file synchronization.
07Platform, ops, and scalePreview, virus scan, quota, observability, multi-region.
Preview, virus scan, quota, observability, multi-region.
In plain terms: Building maintenance, security scans, and usage meters.
Upload completion can enqueue scanning, preview, and thumbnail jobs while metadata tracks whether the file is pending, ready, or rejected. Workers use a file-version identifier so an old preview cannot replace the output for a newer edit. Quota accounting must define logical bytes, retained versions, and physical deduplicated bytes separately; otherwise concurrent uploads can exceed a workspace limit or make the bill impossible to explain.
Measure upload completion, metadata latency, device catch-up age, failed transformations, and unreferenced-byte growth. Keep backups of the catalog and chunks with compatible recovery points, and test a restore that reconstructs an actual folder tree. Multiple regions need explicit metadata ownership, permission behavior, and recovery objectives; cache clusters, orchestration, and key management support those decisions rather than replace them.
Metadata vs chunk bytes
Keep the catalog strongly consistent; let the warehouse store hashed chunks.
Strong consistency for the catalog. This is what users mean when they say "my Drive folder."
The catalog binds a stable file identifier to its name, parent, permissions, and current version. A version holds an ordered chunk manifest, so a rename changes metadata without copying the file body. A conditional version update detects edits based on an old version instead of silently discarding concurrent work.
Upload bytes first, verify their durability, and then atomically publish the new manifest within the metadata store. This is not a distributed transaction that simultaneously writes every object. Uncommitted chunks remain protected by an upload session until they are referenced or become eligible for delayed cleanup.
Chunks
warehouse bytes. Many files can share one hashed object without copying the payload.
can preserve unchanged chunks across edits, while fixed-size chunking is cheaper to implement. The manifest supplies ordering; a hash supplies identity and an integrity check, not permission to read the bytes. Reuse must honor encryption and tenant boundaries.
Garbage collection starts from all retained version manifests, trash entries, and protected uploads. Before deletion, coordinate with concurrent reference creation and recheck the chunk’s live state. A grace period handles delayed cleanup, but it cannot replace that coordination: otherwise a newly committed file may point to bytes the collector just removed.
Core flows
Upload commits metadata only after chunks are durable.
Upload and commit
Upload chunks first and verify that every referenced chunk is durable before committing the new file version in the metadata transaction. Until that commit, the upload is incomplete and can be retried or abandoned without changing the visible file. Publish a metadata-change event with the committed version so other devices can sync. This ordering prevents a folder entry from pointing to bytes that were never successfully stored.
Read the diagram definition
sequenceDiagram
autonumber
participant C as Client
participant GW as API gateway
participant UP as Upload service
participant DD as Dedup index
participant S3 as Object storage
participant MD as Metadata service
participant K as Kafka
C->>GW: start upload session
GW->>UP: allocate upload_id
loop each chunk
C->>UP: report chunk hash
UP->>DD: lookup hash
alt chunk exists
DD-->>UP: ref exists (skip upload)
else new chunk
UP-->>C: presigned PUT URL
C->>S3: PUT chunk bytes
UP->>DD: register hash ref
end
end
C->>GW: commit upload
UP->>UP: verify all chunks durable
MD->>MD: txn write file metadata + chunk list
MD->>K: metadata-changed
MD-->>C: file readyMulti-device sync
Delta since cursor; optional push hint.
Read the diagram definition
sequenceDiagram
autonumber
participant C as Client device
participant GW as API gateway
participant SY as Sync service
participant MD as Metadata store
participant K as Kafka
participant N as Notifier
C->>GW: POST /sync (since_cursor)
GW->>SY: get delta
SY->>MD: changes after cursor
MD-->>SY: added / modified / deleted
SY-->>C: delta + new_cursor
Note over C: apply locally, upload local edits
C->>GW: POST local change (version)
GW->>SY: apply edit
SY->>MD: compare server version
alt version match
MD->>MD: commit update
MD->>K: metadata-changed (async)
K->>N: consume event
N-->>C: WebSocket hint (optional)
else version mismatch
SY->>MD: write conflict copy
MD-->>C: conflict file + server version
endDownload
Authenticate the requester and check current file or sharing-link permissions before issuing short-lived download access to the required chunks. A client that already has verified chunks can fetch only missing ones. Signed URLs are bearer capabilities until they expire, so revoking a share may require a short validity window or a download path that rechecks policy. Content hashes identify bytes; they must not bypass ownership checks.
Read the diagram definition
sequenceDiagram
autonumber
participant C as Client
participant GW as API gateway
participant DL as Download service
participant MD as Metadata
participant S3 as Object storage
C->>GW: GET download (file_id)
GW->>DL: auth + ACL check
DL->>MD: load chunk hash list
DL-->>C: presigned URLs per chunk (or CDN)
loop missing chunks
C->>S3: GET chunk by hash
S3-->>C: bytes
end
C->>C: assemble file locallyWhat users experience
Upload a large file
You: You drop a 2 GB video into your Drive folder.
System: Client chunks file, hashes each piece, uploads only new chunks to S3, then commits metadata in one transaction.
Edit on two laptops
You: You change a doc offline on your laptop; your desktop had an older copy.
System: Sync detects version conflict; creates conflict copy or applies last-writer-wins per product policy.
Share a folder link
You: You send a view-only link to a colleague.
System: Sharing service stores token + expiry; download checks ACL before presigned URLs.
Requirements
Upload / download
- Resumable multipart
- Range download
- TB-scale files
Sync
- Delta sync
- Offline queue
- Conflict handling
Sharing & versions
- Link + user ACL
- Version restore
- Trash retention
Numbers that drive the design
30% dedup saves ~600 PB physical
200M DAU × 5% uploaders
3 devices × 20 checks/day
On 2 EB logical storage
Assume 200M DAU, 5% upload daily (10M uploaders), 50 TB/day at 4 MB chunks (12.5M chunks/day). Sync checks: 200M × 3 devices × 20/day = 139K QPS average. Logical storage is 2 EB; 30% dedup saves ~600 PB physical.
Case-study upgrade
File Storage and Sync Math
File sync stores bytes, metadata, permissions, versions, and sync cursors. Metadata correctness is usually harder than storing raw bytes.
Assumptions and formulas
- Daily active users: 200M. Five percent upload daily. Chunk size: 4 MB. Logical storage: 2 EB.
- Upload volume: 50 TB/day. Users may have multiple devices and offline edits.
- Deduplication saves about 30% on 2 EB logical storage (~600 PB physical savings).
Concrete math
- Uploaders: 200M x 5% = 10M uploaders/day.
- Chunks: 50 TB/day / 4 MB = about 12.5M chunks/day = ~145 chunk commits/sec average; 10x ingest peak ≈ 1.45K dedup hash lookups/sec.
- Chunk index: 12.5M chunks/day x 64 bytes = 800 MB/day raw; 5 years is about 1.46 TB before indexes and replication.
- Metadata rows: 1B users x 2K files = 2T file metadata rows; at ~400 bytes/row = ~800 TB raw before indexes and replication.
- Metadata QPS: chunk commits ~145/s avg + ACL checks and folder list ops during sync; sync-driven metadata reads share the 139K QPS sync budget.
- Sync checks: 200M users x 3 devices x 20/day = 12B/day = 139K QPS average.
- Sync notifications: push to 600M device endpoints (200M x 3 devices) can cut polling QPS by 80-90% versus pure pull sync.
- Version retention: if average 5 versions per active file, physical storage multiplier is ~1.5-2x logical after 30% dedup savings.
- Dedup savings: 30% savings on 2 EB logical storage saves about 600 PB physical storage.
Design decisions forced by numbers
- Shard namespace metadata separately from blob storage.
- Use upload sessions so object writes and metadata commits can be retried safely.
- Permission changes must invalidate folder and file access caches quickly.
Scaling to millions
- At 1M users: simple metadata store, object storage, and upload sessions are enough.
- At 10M users: add namespace sharding, chunk index, and sync cursor service.
- At 100M+ users: add regional metadata partitions, conflict resolution, dedup filters, and orphan cleanup.
Readable flow
Interview follow-ups to expect
- How do rename and move work while another device edits offline?
- How are permissions inherited and invalidated?
- How do orphan chunks get garbage collected safely?
Operational readiness checklist
After the math, explain how this capacity plan is measured, protected, launched, and evolved.
Observability
- Attach each capacity estimate to a dashboard metric: p99 latency, queue age, cache hit rate, shard skew, error rate, and freshness lag.
- Alert on rate-of-change and saturation, not only hard failures; backlogs and hot keys usually warn before an outage.
Security and abuse
- Budget for auth checks, rate limits, quota isolation, audit logging, privacy filters, and abuse-review side paths.
- Separate trusted internal events from user-controlled input so retries and backfills cannot bypass policy checks.
Degraded modes
- Define the fallback when a dependency is slow: stale cache, partial results, read-only mode, delayed async work, or admission control.
- Protect the invariant first; reduce freshness, personalization, or analytics quality before risking duplicate or corrupt state.
Testing and rollout
- Test average, peak, and hot-object traffic; include retry storms, cold caches, lagging workers, and regional dependency loss.
- Use canaries, shadow reads, dual-write validation, feature flags, and explicit rollback criteria for risky path changes.
Rollout, backfill, and runbooks
- Make migrations and backfills idempotent, resumable, rate-limited, and visible through progress and error metrics.
- Write the runbook before launch: owner, dashboards, paging thresholds, mitigation switches, replay steps, and repair commands.
10x evolution
- For file storage and sync math, state which number forces the next move: cache memory, shard count, write amplification, queue lag, egress, or failover reserve.
- Add the next layer only when the metric forces it: sharding, regional reads, async replay, hot-key isolation, or stricter backpressure.
Sync operations and conflict drill
The byte store is easy; metadata and sync correctness are the hard parts.
SLOs and metrics
Metadata writes p99 <200ms, sync delta p99 <500ms for hot folders, 99% of device hints delivered within 30s. Watch sync cursor lag, conflict rate, orphan chunks, permission-cache age, and dedup lookup p99.
Degraded modes
If push hints fail, clients poll with backoff. If preview generation lags, raw file sync still works. If dedup index is down, upload new chunks and reconcile duplicates later.
Testing and backfill
Replay metadata change logs into a shadow sync index, chaos test metadata DB failover, load test login sync storms, and backfill permission changes through a versioned ACL invalidation queue.
10x evolution
Add namespace sharding, regional metadata partitions, chunk-index Bloom filters, selective sync, conflict analytics, and lifecycle garbage collection with sampled object existence checks.
Hard-part drill: offline conflict resolution
Two devices edit the same file offline from version 41. The first sync commits version 42; the second sees a version mismatch, uploads its chunks, creates a conflict copy linked to version 41, returns both server and local versions, and emits a metadata event so every device converges without losing either edit.
APIs worth naming
Use an upload session plus conditional commit. Chunks can arrive or retry independently; the commit verifies their hashes and protected references, checks that the base file version is still current, and publishes one manifest. Retrying the same commit returns its recorded version rather than creating duplicates. Interrupted sessions expire through cleanup, while a conflict preserves the uploaded work for the product’s merge or conflict-copy flow.
/api/v1/files/uploadStart/resume multipart upload session/api/v1/files/upload/{id}/commitVerify stored chunks; conditionally commit the file-version manifest/api/v1/files/{file_id}/downloadPresigned URLs or ranged stream/api/v1/syncDelta since sync cursor/api/v1/files/{id}/shareUser or link share with ACL/api/v1/files/{id}/versionsVersion historyChange log
How the change log fans out
drives multi-device sync and search, not the upload byte path.
Publishers
Metadata commits append durable journal events.
Every committed metadata change appends to the journal.
metadata-changedMetadata service
File/folder created, moved, renamed, deleted.
Record an outbox or journal entry in the same transaction as the metadata change, then publish it asynchronously. A crash between commit and broker publication is recovered by the relay. Devices use the stable change position to fetch authoritative deltas.
chunk-committedUpload service
New chunk hash durably stored.
This event can drive accounting or analytics, but it must not be the sole authority for liveness. A version commit protects its chunk references in authoritative metadata; duplicate or reordered chunk events must not cause premature deletion. Reuse an existing hash only after validating the allowed deduplication scope.
Consumers
Workers notify, index, and audit: must tolerate replay.
Side effects stay off the upload critical path.
metadata-changedSync notifier
Push WebSocket/SSE to online clients.
The client still pulls the delta via the sync API: events are hints, not full state.
metadata-changedSearch indexer
Update OpenSearch document.
The index can lag behind the committed catalog because it is off the upload path. Carry a file-version identifier so delayed events cannot resurrect a deleted entry or replace a newer one, and recheck access before showing private results.
metadata-changedNotification service
Email/push on share or comment.
A notification is an asynchronous reaction to a committed share or comment. Give it a stable event identifier and retry policy so a replay does not repeatedly alert the same recipient. A failed alert must not roll back the underlying file operation.
Simple rule of thumb
Events hint that something changed. Devices still reconcile with a and an authoritative delta API. Define before two offline editors can diverge.
Data model (core tables)
files
Metadata only; chunk bytes in S3 by hash.
file_versions
Immutable snapshots; share chunks across versions.
shared_access
Check on every read path.
chunk_index
Dedup lookup + GC when ref_count = 0.
Bottlenecks and failure modes
Metadata hot path
Risk: Login sync storm on metadata DB.
Mitigation: Shard by user_id; cache; read replicas for sync reads.
Orphan chunks
Risk: Upload aborted before commit.
Mitigation: GC upload sessions after TTL; ref_count on commit only.
Conflict surprise
Risk: User loses offline edit.
Mitigation: Conflict copy + clear UI; document LWW policy.
Shared link leak
Risk: Old token still works.
Mitigation: Revoke table; short TTL; audit log.
Beginner vs advanced answers
Beginner (5 min)
Keep a transactional catalog of folders, file names, permissions, and versions, while storing large immutable byte objects separately. A file version references its ordered chunk list. Resumable sessions track which chunks reached storage, and an atomic metadata commit makes the new version visible. This lets the system recover an interrupted transfer without presenting a half-uploaded file to other devices.
Advanced (deep dive)
The deeper design follows concurrent versions and their cleanup. A client uploads against a known base version; if another device committed first, a conditional update creates a conflict outcome rather than silently overwriting that edit. Devices consume a metadata journal with durable cursors. Garbage collection deletes chunks only after retained versions, active uploads, and readers can no longer reference them.
Choosing and explaining Cloud file storage
A complete explanation connects the mechanism to a requirement. Describe what improves when you introduce it, which new failure cases become possible, and how you would know that the trade-off is worthwhile.
Explain the core idea
Metadata transaction commits only after chunks are durable.
Files are ordered chunk hashes; storage is content-addressed.
Sync uses cursors; conflicts need an explicit policy.
When it belongs
Design Google Drive, Dropbox, or iCloud-style storage.
They ask about sync, dedup, or sharing permissions.
They probe offline edit conflicts.
How it fails
Metadata points at chunks not yet uploaded.
Full tree scan every sync instead of cursor.
Permission cache stale after revoke.
Trade-offs to weigh
Fixed-size vs content-defined chunking.
Last-writer-wins vs conflict copies.
Strong metadata consistency vs multi-region latency.
Common misunderstandings
Storing file bytes inside the metadata database.
Skipping ACL check on presigned download URLs.
No garbage collection for unreferenced chunks.
Deeper walkthrough
File storage deeper walkthrough
Hard part is metadata, permissions, sync, and versions, not storing bytes in S3.
Requirement refinements
Clarify max file size, folder sharing, offline edits, version retention, public links.
Rule: committed metadata references only durable chunks.
API design details
The upload session records the owner, expected base version, and each chunk hash and size. Verify uploaded bytes against the declared hash before marking a part complete. Final commit conditionally creates the new metadata version only when all required chunks are durable, making a lost response safely retryable with the same operation ID.
A sync cursor marks a position in the namespace change journal, not the current wall clock. Return changes after that position and a next cursor; the device saves the cursor only after applying the page locally. If the cursor predates retained history, request a fresh snapshot and resume from its boundary instead of pretending the device is current.
Data model and storage
Namespace metadata separate from content-addressed chunks.
Versions as metadata snapshots referencing chunk lists.
Scaling strategy
Shard metadata by owner/namespace; CDN for hot shared downloads.
Deduplication lets identical chunks share storage, but scope the dedup index according to tenant privacy and encryption boundaries. Identical plaintext encrypted under different random keys will not have identical ciphertext. Never reveal whether another tenant owns a chunk merely by exposing a dedup lookup result or skipping its authorization checks.
Reliability, recovery, and operations
An abandoned session can leave uploaded chunks with no committed file reference. Reclaim them after a grace period and a reference check that accounts for concurrent commits, retained versions, and active readers. Expiry alone must not delete a chunk that another completed file still uses. Measure orphan bytes and validate collection with sampled restore or download checks.
Monitor sync lag, upload failure rate, orphan chunk count, conflict rate.
Deepening reference
File Storage and Sync: realistic production notes
Beginner mental model: A file storage system is metadata consistency plus chunked object storage plus device sync.
Production scope: The hard part is not only storing bytes. It is reconciling offline edits, permissions, sharing links, version history, deduplication, and efficient sync across devices.
Choose what the first version must guarantee
Start by deciding which file storage and sync capabilities are essential. Describe the main read and write operations before choosing infrastructure. For each operation, identify the stored records it uses and the condition that makes its result correct. A fast response is useful only if it satisfies that condition.
Next, separate work the user must wait for from work that can finish later. Estimate requests per second, storage growth, and the busiest object or customer. Use those estimates to choose one bottleneck to investigate. The calculations below are example workloads with stated assumptions; they are not measured limits of a particular product.
Concrete capacity calculations
Users: 200M DAU. Five percent upload daily = 10M uploaders/day. Upload volume: 50 TB/day.
Chunks: 50 TB/day / 4 MB = about 12.5M chunks/day. Chunk index: 12.5M x 64 bytes = 800 MB/day raw; 5 years is about 1.46 TB before indexes and replication.
Sync checks: 200M users x 3 devices x 20/day = 12B/day = 139K QPS average; push notifications can reduce polling.
Logical storage: 2 EB before dedup. Dedup savings: 30% on 2 EB saves about 600 PB physical storage.
Metadata scale: 1B users x 2K files average = 2T file metadata rows; shard namespace metadata and cache active folders.
Upload throughput: 50 TB/day = about 580 MB/sec average ingest; plan for peak multipliers during business hours.
Scaling to millions of users
Separate metadata transactions from chunk/object storage. Commit file metadata only after required chunks are durable.
Partition namespaces by owner_id or team_id; partition chunks by content hash so duplicate content naturally maps to the same chunk key.
Use a durable change log per namespace so clients sync with a cursor instead of scanning folders.
Cache downloads at the edge only after permission checks issue short-lived signed references.
Handle offline conflicts by preserving both versions rather than silently overwriting.
Sequence and data-flow diagram
Walk this path after the high-level design so it is clear what is synchronous, what is asynchronous, and where the system can degrade safely.
Read the diagram definition
sequenceDiagram
participant Client
participant M as Metadata service
participant O as Object storage
participant L as Change log
participant Sync as Sync worker
Client->>M: Create upload session
Client->>O: Upload missing chunks
Client->>M: Commit file manifest
M->>L: Append namespace change
Sync->>L: Read changes by cursor
Sync-->>Client: Notify other devicesCore flow to walk through
Upload: split file into chunks, hash chunks, upload missing chunks, commit metadata atomically.
Sync: client sends local cursor, server returns ordered change log since that cursor.
Share: permission check resolves user ACL, folder inheritance, and optional public link token.
Production readiness
File Storage and Sync: ship, operate, and evolve
Now examine the same request flow during failures and deployments. Tie each operational control to the user behavior it protects.
Observability
Track file storage and sync p95/p99 latency, error rate, saturation, and user-visible freshness separately for read, write, and async paths.
Alert on leading indicators such as queue age, hot-key skew, cache miss storms, reconciliation mismatches, and error-budget burn.
Security and abuse
Enforce authentication, authorization, rate limits, input validation, audit trails, and privacy checks at the service boundary.
Treat abuse controls as a first-class path: throttling, quota isolation, moderation hooks, revocation, and safe handling of sensitive data.
Degraded modes
Name what still works if cache, search, ranking, stream processing, object storage, or a regional dependency is slow.
Prefer stale-but-safe reads, partial results, async retry, admission control, and feature disablement over corrupting core state.
Testing and rollout
Load test average, peak, and hot-object traffic; add failure-injection for retries, timeouts, backlog growth, and dependency outages.
Ship with canaries, shadow reads or dual writes when useful, rollback switches, schema compatibility checks, and replay validation.
Runbooks
Document dashboards, paging thresholds, owner actions, rollback steps, data repair commands, and customer-impact language.
Keep backfills and replays idempotent, resumable, rate-limited, and observable so repair work does not create a second incident.
10x evolution
Say which metric forces the next architecture change: shard count, cache footprint, write amplification, queue lag, p99 latency, or regional failover reserve.
Evolve one bottleneck at a time: partition by access pattern, isolate hot tenants, regionalize reads, add replayable async pipelines, then harden multi-region behavior.
Hard parts worth deepening
Use content-addressed chunks for dedup and resumable upload.
Keep metadata transactions separate from object storage writes; commit only after chunks are durable.
Conflict copies are often better UX than silent last-writer-wins.
Folder moves need careful subtree metadata updates or logical path indirection.
Failure modes and recovery
Upload completes but metadata commit fails; garbage collect unreferenced chunks later.
Two devices edit offline; create conflict versions and let user resolve.
Public share token leaks; support revocation and token rotation.
Hot shared file overloads origin; cache downloads through CDN with permission-aware URLs.
Signals to monitor
Sync lag measures how long a committed change takes to appear on another device. Pair it with metadata transaction latency to distinguish a slow authoritative write from delayed change-log consumption.
Upload resume success shows whether interrupted uploads recover without starting again. Deduplication savings compare logical file bytes with unique stored bytes, while share-permission errors reveal access checks that reject valid users or admit invalid ones.
| Choice | Best when | Cost |
|---|---|---|
| Chunk dedup | Large files and repeated content are common. | More metadata and chunk management. |
| Whole-file storage | Files are small and simplicity matters. | Poor resumability and dedup. |
| Change-log sync | Many clients sync incrementally. | Requires durable per-user or per-namespace log. |
Try this scenario
Explain how two laptops editing the same offline file converge without losing either version.
Takeaway
Remember the Drive drop: the folder tree is the product. Chunk and dedup the bytes, commit metadata only when storage is durable, fan out through a change log, and let devices catch up with a sync cursor. Protect every download with ACLs, and treat conflicts as a product decision, not an afterthought.
Primary sources
- Ghemawat et al.: Google File System: chunkservers and master metadata.
- Amazon S3 User Guide: object durability model.
- Dropbox Tech: Infrastructure: large-scale file storage lessons.
Practice and further reading
Use these exercises to connect the lesson to a design decision. State your assumptions, trace what happens to one request, and explain the rule that must remain true even during a failure. That rule is the design's correctness invariant.
Focus for this lesson: Design chunk upload, metadata atomicity, sync cursors, rename/move, offline conflict, dedup privacy, version recovery, quotas, and garbage collection.
Explain the decision
Why separate file metadata from immutable chunks?
Read the reasoning
Metadata needs transactional namespace operations while chunks need scalable durable blob storage and content/version lifecycle.
Apply it to a production scenario
Metadata commit fails after all chunks upload. What happens?
Read one approach
Keep upload intent and content hashes, retry finalize idempotently, and garbage-collect unreferenced chunks only after a safe grace window.
Work through the numbers
Ten million users store 20 GB each with 30% dedup and 1.5x protection overhead. Estimate physical bytes.
Read the worked calculation
200 PB logical × 0.70 × 1.5 = 210 PB, before versions, metadata, and temporary uploads.
Reason through a failure
What must rename guarantee?
Read the recovery reasoning
Namespace readers see the file at old or new path according to one atomic metadata version, never both as independent authoritative files.
Sources and further study
Continue with Design Notification System.