File Storage Service at Scale

📋 Jump to Takeaways

Step 1: File Storage Requirements

File Storage Functional Requirements

  • Upload/download files: support files up to 10GB
  • File versioning: maintain history of changes, allow rollback
  • Sharing: shareable links (public/private), granular permissions (view, edit, owner)
  • Sync across devices: changes on one device reflect on all others in near real-time
  • Folder structure: hierarchical organization with nested directories
  • Offline support: clients work offline and sync when reconnected

File Storage Non-Functional Requirements

  • 500M total users, 100M DAU
  • 99.99% durability: never lose a file once uploaded
  • 99.9% availability for reads, 99.95% for writes
  • Average file size: 500KB
  • 2 files uploaded per user per day
  • Sync latency < 5 seconds for online devices

Step 2: File Storage Estimation

File Storage Storage

  • Uploads/day: 100M DAU × 2 files = 200M files/day
  • Storage/day: 200M × 500KB = 100TB/day
  • Storage/year: 100TB × 365 = ~36.5PB/year

File Storage Bandwidth

  • Upload: 100TB/day = ~1.2GB/s sustained
  • Download (assume 3:1 read-to-write): ~3.6GB/s sustained
  • Peak (5× average): ~18GB/s download bandwidth

Metadata

  • Each file: ~500 bytes of metadata (name, path, owner, timestamps, permissions, block list)
  • 200M files/day × 500B = 100GB metadata/day
  • After 3 years: 100B files × 500B = **50TB metadata**

QPS

  • Upload QPS: 200M / 86400 = ~2,300 uploads/sec (peak: ~12K/sec)
  • Download QPS: ~7,000/sec (peak: ~35K/sec)

Step 3: File Storage High-Level Design

┌──────────┐         ┌──────────────┐        ┌──────────────────┐
│  Client  │────────▶│  API Gateway │───────▶│  Upload Service  │
│  (App)   │◀────────│  (Auth/Rate) │        └────────┬─────────┘
└────┬─────┘         └──────┬───────┘                 │
     │                      │                         ▼
     │                      │               ┌──────────────────┐
     │                      │               │  Block Storage   │
     │                      │               │  (S3 / GCS)      │
     │                      ▼               └──────────────────┘
     │              ┌───────────────┐
     │              │ Metadata DB   │ (PostgreSQL, sharded)
     │              │ (files, blocks│
     │              │  versions)    │
     │              └───────────────┘

     │    ┌─────────────────┐       ┌──────────────────┐
     └───▶│  Sync Service   │◀─────▶│ Notification Svc │
          │ (change log)    │       │ (WebSocket/SSE)  │
          └─────────────────┘       └──────────────────┘

                                    ┌─────────▼─────────┐
                                    │  Message Queue    │
                                    │  (Kafka/SQS)      │
                                    └───────────────────┘

Downloads: Client → CDN (CloudFront) → Block Storage (cache miss)

File Storage Component Responsibilities

  • API Gateway: authentication, rate limiting, routing
  • Upload Service: receives chunks, writes to block storage, updates metadata
  • Metadata DB: file tree, block references, versions, sharing permissions
  • Block Storage (S3): immutable file blocks, replicated across AZs
  • Sync Service: tracks change log per user, serves diffs to clients
  • Notification Service: pushes change events to connected devices via WebSocket
  • CDN: caches popular files close to users for fast downloads

Step 4: File Storage Deep Dive

Chunked Uploads

Large files are split into 4MB blocks on the client side:

  1. Client splits file → computes SHA-256 hash per block
  2. Client sends block list to server: [{hash, size, index}]
  3. Server responds with which blocks are already stored (dedup check)
  4. Client uploads only missing blocks in parallel
  5. On failure, client resumes from the last unacknowledged block

Benefits: resumable uploads, parallelism, deduplication at block level.

File Storage Deduplication

  • Each block is identified by its content hash (SHA-256)
  • Before storing, check if hash already exists in block index
  • If it exists → just add a reference (no new storage)
  • Cross-user dedup: common files (OS installers, libraries) stored once
  • Saves 40-60% storage in practice (Dropbox reported similar numbers)

Metadata vs Data Separation

Concern Storage Why
File metadata PostgreSQL (sharded by user_id) ACID, complex queries, permissions
Block data Object storage (S3) Cheap, durable (11 nines), scalable
Block index Key-value store (DynamoDB) Fast hash lookups

Schema (simplified):

files: id, user_id, name, parent_folder_id, latest_version_id, created_at, updated_at
versions: id, file_id, block_list[], size, created_at, created_by
blocks: hash (PK), size, storage_path, ref_count
sharing: file_id, user_id, permission_level, share_token

Sync Protocol

  1. Client maintains a local snapshot (file tree + block hashes)
  2. On file change, client computes diff → uploads new blocks → updates metadata
  3. Server appends to change log (per-user ordered event stream)
  4. Other devices poll or receive push: "changes since cursor X"
  5. Client applies remote changes to local state, downloads new blocks as needed

Change notification delivery:

  • WebSocket for active/online clients (low latency)
  • Long-polling as fallback for restricted networks
  • Push notification for mobile devices (wake app to sync)

Conflict Resolution

When two devices edit the same file offline:

  1. Both upload their versions
  2. Server detects conflict (parent version doesn't match)
  3. Strategy: last-writer-wins for the primary copy
  4. Losing edit saved as a conflict copy (e.g., report (Serjik's conflicted copy).docx)
  5. User manually resolves by choosing which to keep

This matches Dropbox's approach: simple, predictable, no data loss.

Versioning

  • Each version stores a new block list, not a full copy
  • If only 2 of 100 blocks changed, version references 98 existing + 2 new blocks
  • Old versions can be garbage-collected after retention period (e.g., 30 days for free tier)
  • Delta encoding between versions for additional savings on text-heavy files

Storage Optimization

  • Compression: blocks compressed with LZ4 (fast) or Zstandard (better ratio) before storage
  • Tiered storage: hot (S3 Standard) → warm (S3-IA after 30 days) → cold (Glacier after 90 days)
  • Garbage collection: background job decrements ref_count when versions are deleted; blocks with ref_count=0 are purged
  • Encryption: blocks encrypted at rest (AES-256); per-user keys for enterprise tier

Key Takeaways

  • Chunking is fundamental: it enables resumable uploads, parallel transfers, deduplication, and efficient versioning all at once.
  • Separate metadata from data: SQL for structure/permissions, object storage for raw bytes. They scale differently and have different consistency needs.
  • Content-addressable storage (hash-based) gives you deduplication for free and makes integrity verification trivial.
  • Sync is the hardest problem: maintain an ordered change log per user, use cursors for incremental sync, and push notifications for low-latency updates.
  • Conflict resolution must never lose data: last-writer-wins with conflict copies is simple and battle-tested (Dropbox, Google Drive both use variants of this).
  • Storage costs dominate at scale: tiered storage, compression, and dedup are not optimizations but requirements at petabyte scale.
© 2026 ByteLearn.dev. Free courses for developers. · Privacy