TL;DR

1. The problem: why do we need object storage?

Every Instagram post starts as a multi-megabyte photo or video. Each upload becomes many files — the original plus several resized images and a ladder of video bitrates and segments (see Media Processing). Assume, purely for practice, 100 million photos and 20 million videos uploaded per day: that's hundreds of terabytes per day and hundreds of petabytes per year, kept essentially forever, any of which might be viewed at any moment.

Where could all that live?

Object storage is the answer: a giant, cheap, durable, HTTP-addressable key → bytes store that scales horizontally by adding disks.

🧠 Analogy Object storage is a coat check / valet service. You hand over your coat (the bytes) and get a ticket (the key). You don't know or care which rack or room your coat is on; you can't alter the coat while it's checked in — you can only collect it, replace it with a different coat, or throw it away. Because customers never walk into the back room, the valet company can reorganise, duplicate and move coats between warehouses freely, and serve millions of customers with the same simple counter.

2. Block vs file vs object storage

There are three fundamental ways to expose storage. Understanding the difference is a classic interview warm-up.

Block storage File storage Object storage #0#1#2#3 #4#5#6#7 #8#9#10#11 //home/var ana/photo.jpgnotes.txtlog.txt bucket: ig-media key: p/9f3a/1080.jpgbytes + metadata key: p/9f3a/640.webpbytes + metadata key: v/77c1/seg_001.m4sbytes + metadata Numbered fixed-size blocks.Read/write block #N in place.One server mounts it (a "disk"). Hierarchy of directories & files.Open/seek/write/lock via POSIX.Shared by many servers (NFS/SMB). Flat key → whole object.PUT/GET/DELETE over HTTP.Scales to trillions of objects.
Three abstractions over the same disks: blocks (a raw disk), files (a tree with in-place edits), objects (a flat key → immutable blob map).
Block storageFile storageObject storage
UnitFixed-size block (e.g. 4 KB) addressed by numberFile inside a directory treeObject = key + data + metadata in a bucket
InterfaceSCSI/NVMe, iSCSI — the OS puts a file system or DB on topPOSIX (open, seek, write, rename, lock) via NFS/SMBHTTP REST: PUT, GET, HEAD, DELETE, LIST
Modify in place?Yes, any blockYes, any byte rangeNo — replace the whole object (or new version)
MetadataNoneFixed (owner, permissions, times)Rich, custom key-value metadata per object
LatencyLowest (sub-ms)Low (ms)Higher (tens of ms to first byte)
ScaleSingle volume, TBs; attached to one hostPBs, but metadata servers limit file countEffectively unlimited: exabytes, trillions of objects
Cost / GBHighestHighLowest (plus cheaper cold tiers)
ExamplesAWS EBS, SAN LUNs, local NVMeAWS EFS, NetApp, Azure Files, CephFSS3, Google Cloud Storage, Azure Blob, MinIO, Ceph RGW
Instagram useDisks under PostgreSQL and Cassandra nodesRare (shared config, legacy tools)All photos, videos, renditions, backups, ML datasets

3. The object model

🪣 Bucket

A named container with a region, access policy, versioning and lifecycle settings, e.g. ig-media-prod-us. Bucket names are globally unique in S3.

🔑 Key

A string up to 1,024 bytes that uniquely names the object within the bucket, e.g. p/3049215820194820101/1080.jpg.

📦 Value (data)

The bytes: 0 B up to 5 TB per object in S3. Treated as opaque and immutable.

🏷️ Metadata

System metadata (size, Content-Type, ETag checksum, last-modified, storage class) plus user metadata (x-amz-meta-owner-id: 1001) and tags.

Flat namespace. There are no real directories. The key p/3049/1080.jpg is just a string containing slashes. When a console shows "folders", it is running LIST with prefix=p/3049/ and delimiter=/ and grouping keys that share a prefix. This is a big reason object stores scale: there's no directory tree to lock, no rename of a directory (renaming means copying every object), and the index is just a giant sorted key → location map that can be partitioned by key range.

Immutability. You can't append or overwrite bytes 100–200; a PUT replaces the entire object atomically — readers see either the old or the new object, never a mix. With versioning enabled, an overwrite creates a new version and a delete inserts a "delete marker", so older versions remain recoverable (protecting against bugs and ransomware, at the cost of storing every version until a lifecycle rule expires them).

For Instagram this model is a perfect fit: processed media is write-once, read-many and never edited. An "edit" (e.g. a new filter) produces new renditions under new keys.

4. The S3-style API

4.1 Basic operations

PUT    /ig-media/p/3049215820194820101/1080.jpg     (body = bytes, Content-Type: image/jpeg)
GET    /ig-media/p/3049215820194820101/1080.jpg     (optional Range: bytes=0-1048575)
HEAD   /ig-media/p/3049215820194820101/1080.jpg     (metadata only: size, ETag, type)
DELETE /ig-media/p/3049215820194820101/1080.jpg
GET    /ig-media?list-type=2&prefix=p/3049215820194820101/   (LIST keys by prefix, paginated, 1,000 per page)

Range GETs fetch part of an object — essential for video players seeking within a file and for parallel downloads. ETag is a checksum-like version identifier useful for conditional requests and CDN revalidation.

4.2 Multipart upload

A single PUT is fine for a 3 MB photo but terrible for a 2 GB video on a mobile network: one dropped connection at 95% means starting over. Multipart upload splits an object into parts uploaded independently and in parallel:

  1. CreateMultipartUpload → returns an UploadId.
  2. UploadPart (partNumber 1…10,000, each 5 MB–5 GB except the last) — in parallel, in any order, retrying only failed parts. Each returns an ETag.
  3. CompleteMultipartUpload with the list of (partNumber, ETag) → the store stitches parts into one object, atomically visible.
  4. Or AbortMultipartUpload. Incomplete uploads keep their parts (and keep costing money) until aborted — add a lifecycle rule AbortIncompleteMultipartUpload: 1 day.

Benefits: resumability on flaky mobile networks, higher throughput through parallelism, and the ability to start uploading before the whole file exists (e.g. while the phone is still encoding). See Media Upload for the client side.

4.3 Pre-signed URLs: let the client talk to storage directly

Routing upload bytes through the Upload Service would make those servers a bandwidth bottleneck. Instead the service issues a pre-signed URL: a URL for one specific operation on one specific key, containing an expiry and an HMAC signature computed with the service's secret credentials. Anyone holding the URL can perform exactly that operation until it expires — no AWS credentials on the phone.

 Phone                    Upload Service                 Object Storage (S3)          Kafka
   |-- POST /uploads ------------>|                               |                      |
   |   (auth token, size, type)   | authZ, quota, pick key        |                      |
   |                              | sign PUT URL (expires 15 min) |                      |
   |<-- {upload_url, media_id} ---|                               |                      |
   |-- PUT bytes (multipart) -----------------------------------> |                      |
   |<------------------------------------------------- 200 OK --- |                      |
   |                              |<-- ObjectCreated event -------|                      |
   |-- POST /posts {media_id,...}>|-- "media.uploaded" ------------------------------>  |
   |                              |                               |   media workers resize/transcode
import boto3
s3 = boto3.client("s3")
url = s3.generate_presigned_url(
    "put_object",
    Params={"Bucket": "ig-uploads-raw", "Key": f"raw/{media_id}",
            "ContentType": "image/jpeg"},
    ExpiresIn=900)            # 15 minutes; signature covers bucket, key, method, headers, expiry
# The phone PUTs to `url`. The signature can't be reused for another key or for GET.

Security details: keep expiries short; sign the content type and (with POST policies) a maximum size; upload into a separate raw/quarantine bucket that is never served publicly until the media pipeline validates it; generate keys server-side so clients can't overwrite others' objects. Pre-signed GET URLs work the same way for private downloads, though at Instagram's scale downloads go through CDN-signed URLs (see CDN).

5. Inside an object store

A distributed object store has three logical layers. Understanding them explains its performance and consistency behaviour.

Client / CDNHTTP request
→
Front-end / API tierauth, signatures, routing
→where is key?
Metadata (index) servicekey → chunk locations
→read/write chunks
Storage nodesdisks, chunks, checksums

A PUT streams the data to several storage nodes (replicas or erasure-coded fragments), waits until enough have durably written it, then commits the index entry — only then does it return 200. That ordering is why an acknowledged write survives failures.

6. Durability: replication and erasure coding

Durability is the probability that data you stored is still there (uncorrupted) later. It's different from availability (can I read it right now?). S3 Standard is designed for 99.999999999% ("11 nines") annual durability and 99.99% availability.

What does 11 nines mean? The annual probability of losing a given object is about 10−11. If you store 10 million objects, you'd expect to lose one object about once every 10,000 years. At Instagram's scale (say 1012 objects) the same rate still means ~10 objects per year — which is why hyperscalers add cross-region redundancy on top.

Disks fail constantly at scale: with a ~1–2% annual failure rate, a fleet of 500,000 drives loses on the order of 15–25 drives per day. Durability comes from storing redundant data in independent failure domains (disk, server, rack, power, availability zone) and repairing faster than further failures arrive.

6.1 Replication

Store N full copies (typically 3) on different nodes, ideally in different availability zones. Simple, fast to read (any copy) and fast to repair (just copy), but it costs 3× the raw storage — 200% overhead. For hundreds of petabytes that's hundreds of petabytes of extra disks.

6.2 Erasure coding — the intuition

Erasure coding is "RAID for the data center". Split the object into k data fragments, compute m parity fragments from them, and store all k + m fragments on different nodes. The magic property of a Reed-Solomon code: any k of the k + m fragments are enough to reconstruct the original. You survive the loss of any m fragments while storing only (k + m) / k times the data.

Simplest case — XOR parity (k = 2, m = 1):

D1 = 1011        D2 = 0110
P  = D1 XOR D2 = 1101             (store D1, D2, P on three different nodes)

Lose D2?  D2 = D1 XOR P = 1011 XOR 1101 = 0110  ✔
Lose D1?  D1 = D2 XOR P = 0110 XOR 1101 = 1011  ✔
Overhead: 3/2 = 1.5×, survives any 1 loss (replication would need 2× for the same).

XOR only survives one loss. Reed-Solomon generalises this: treat the k data fragments as coefficients of a polynomial over a finite field (Galois field arithmetic, so values stay in a byte range); the k + m fragments are the polynomial evaluated at k + m different points. A polynomial of degree k − 1 is uniquely determined by any k points (just as any 2 points determine a line), so any k surviving fragments let you recover all the data. Real systems use parameters like RS(6,3) (1.5×, survives 3 losses), RS(10,4) (1.4×, survives 4 losses) or wider.

Video part4 MB RS encoderk = 4, m = 2 D1 D2 D3 D4 P1 P2 Availability zone AAvailability zone BAvailability zone C 1 MB each · any 4 of the 6 fragments rebuild the data storage overhead 6/4 = 1.5× (vs 3× for triple replication) survives losing any 2 fragments — e.g. one whole AZ
Reed-Solomon RS(4,2): four data fragments plus two parity fragments, spread so that losing an entire availability zone loses at most two fragments.
3× replicationErasure coding RS(10,4)
Raw storage per logical TB3 TB1.4 TB
Failures toleratedAny 2 copiesAny 4 fragments
Normal readRead one copy (1 disk)Read k fragments from k disks (or one if stored systematically and you read a fragment range)
Degraded read / repair costCopy 1 replicaRead k fragments over the network to rebuild one — ~10× repair traffic
CPUNoneEncode/decode math (cheap with SIMD, but not free)
Small objectsFineWasteful/slow — pack small objects into big stripes first
Best forHot, small, latency-sensitive dataLarge, warm/cold, bulk data — most bytes in an object store

Practical systems often combine both: replicate fresh, hot data (fast writes, cheap repairs) and erasure-code it once it cools — exactly the Haystack → f4 journey in section 9. Durability also needs end-to-end checksums (detect silent bit-rot), background scrubbing, and fast repair: the shorter the window between a failure and its repair, the less likely a second and third failure land in the same stripe.

7. Consistency

For years S3 offered read-after-write consistency for new objects but only eventual consistency for overwrites, deletes and LIST — a reader might see an old version or a list missing a just-written key. Since December 2020, S3 provides strong read-after-write consistency for all PUTs and DELETEs of objects and for LIST operations, at no extra cost. Google Cloud Storage and Azure Blob Storage are also strongly consistent for object operations.

See CAP & Consistency Models for the vocabulary.

8. Storage classes, lifecycle policies and cost

Not all bytes are equal. A photo posted today might be fetched (by the CDN) thousands of times this week and almost never next year. Object stores offer storage classes that trade lower storage price for higher retrieval cost or latency. Approximate S3 US list prices at the time of writing (check current pricing; at Meta's scale, custom hardware replaces these):

Class≈ $/GB-monthRetrievalMin. durationUse for
Standard (hot)0.023ms, no feenoneNew and frequently accessed media
Intelligent-Tiering0.023 → lower tiers automaticallyms (archive tiers optional)none (small monitoring fee/object)Unknown or changing access patterns
Standard-IA (infrequent access)0.0125ms, ~$0.01/GB fee30 days; objects billed as ≥ 128 KBOlder media still viewable instantly
One Zone-IA0.01ms, fee30 daysRe-creatable data (e.g. derived renditions)
Glacier Instant Retrieval0.004ms, higher fee (~$0.03/GB)90 daysRarely accessed but must be instant (old posts)
Glacier Flexible Retrieval (archive)~0.0036minutes–hours90 daysBackups, raw originals for disaster recovery
Glacier Deep Archive~0.001~12–48 hours180 daysCompliance archives, legal holds

Lifecycle policies move or delete objects automatically based on age, prefix or tags:

{
  "Rules": [
    { "ID": "renditions-cool-down", "Filter": { "Prefix": "p/" }, "Status": "Enabled",
      "Transitions": [ { "Days": 60,  "StorageClass": "STANDARD_IA" },
                       { "Days": 365, "StorageClass": "GLACIER_IR" } ] },
    { "ID": "raw-uploads-cleanup", "Filter": { "Prefix": "raw/" }, "Status": "Enabled",
      "Expiration": { "Days": 7 },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 1 } },
    { "ID": "old-versions", "Filter": {}, "Status": "Enabled",
      "NoncurrentVersionExpiration": { "NoncurrentDays": 30 } }
  ]
}

8.1 Cost reasoning: when does a cooler tier pay off?

Moving from Standard ($0.023) to Standard-IA ($0.0125) saves $0.0105 per GB-month but adds ~$0.01 per GB retrieved. So IA wins only if each byte is fetched from the origin less than about once a month. That's true for most old Instagram media precisely because the CDN absorbs repeat views. Other traps:

9. Lessons from Facebook's Haystack and f4

Facebook's photo storage papers — Finding a needle in Haystack (OSDI 2010) and f4: Facebook's Warm BLOB Storage System (OSDI 2014) — are the best public explanation of how a social network stores billions of small media files. Instagram today runs on Meta's infrastructure, so these ideas are directly relevant.

9.1 The problem: per-file metadata overhead

Facebook originally stored each photo as a file on NFS-mounted network storage. The Haystack paper (which reported ~260 billion images and ~20 PB at the time) explains why that broke down:

Lesson: at billions of small objects, metadata, not bandwidth, is the bottleneck. The goal became "one disk operation per photo read".

9.2 The Haystack design: needles in big volume files

In-memory index (RAM) photo key, size → offset, len 8812, 1080 → 0, 240 KB 8812, 320 → 240 KB, 40 KB 9031, 1080 → 51.7 GB, 230 KB ~10 bytes per photo, not ~500 Physical volume file (~100 GB, append-only) needlendlneedle✗ delneedlefree → append Needle layout: magic | cookie | key | alt key | flags | size | DATA | checksum | pad cookie = random value in the URL, so URLs can't be guessed 1 seek
Haystack keeps a tiny per-photo index in RAM and packs millions of photos ("needles") into a few huge append-only files, so a read is one seek plus one sequential read.

Modern object stores use the same core idea internally: pack small objects into large append-only containers and keep a compact index — it's why S3 can store trillions of objects.

9.3 f4: warm storage with erasure coding

Haystack's replication (3 copies, each on RAID-6 disks) gave an effective replication factor of about 3.6×. But request rates for photos and videos drop sharply with age: the newest content is "hot", while the vast majority of bytes are "warm" — still occasionally viewed, still needing low latency, but rarely. Paying 3.6× for warm data is wasteful. The f4 paper describes moving BLOBs whose volumes have cooled (after some months) from Haystack into f4:

Takeaway: tier by temperature. Hot: replicated, fast, maybe cached. Warm: erasure-coded, still online. Cold: archived. The physical storage cost difference between 3.6× and 2.1× across tens of petabytes is enormous.

10. Key naming design

Keys look trivial but affect performance, security, operations and cost.

Good:   {hash4}/p/{post_id}/{version}/{rendition}.{ext}
        e.g. 7c2e/p/3049215820194820101/v2/1080.webp
Bad:    photos/2026/10/23/ana_k_beach_holiday.jpg

11. Cost and capacity math for Instagram

All inputs are assumptions for practice (see Back-of-the-Envelope Estimation):

Photos: 100M/day × (2 MB original + 0.5 MB of renditions: 1080/640/320/thumbnail, JPEG+WebP/AVIF)
        = 100M × 2.5 MB = 250 TB/day
Videos: 20M/day × 40 MB (original + bitrate ladder of HLS/DASH segments)
        = 800 TB/day
Total logical ≈ 1.05 PB/day  ≈ 380 PB/year  (and it accumulates forever)

Ingress bandwidth: 1.05 PB / 86,400 s ≈ 12 GB/s ≈ 100 Gbps average (peaks 2–3×)

Physical storage for one year of uploads:
  3× replication     → 380 × 3   ≈ 1,140 PB
  RS(10,4) (1.4×)    → 380 × 1.4 ≈   530 PB
  20 TB drives       → ~57,000 drives vs ~26,600 drives — erasure coding saves ~30,000 drives/year

At cloud list prices (just for intuition):
  380 PB in Standard  ≈ 380M GB × $0.023 ≈ $8.7M per month
  Tiered (most bytes in IA after 60 days, avg ≈ $0.0135) ≈ $5.1M per month
  … for ONE year of uploads; year 2 adds another 380 PB.

Egress if users downloaded directly from the bucket: assume 10 PB/day × ~$0.05/GB
  ≈ $500K per DAY → serving through a CDN / own edge network is mandatory.

These numbers explain why Meta builds its own storage (Haystack, f4 and successors) and edge network rather than renting: at exabyte scale, replication factor, disk density and egress pricing dominate the bill.

12. Deletion, privacy and GDPR

Deleting is harder than storing. When a user deletes a post (or their whole account), every copy must eventually disappear: all renditions, all replicas and erasure-coded fragments, CDN copies, cross-region replicas, old versions, and backups. Regulations such as the EU's GDPR ("right to erasure") require doing this without undue delay; Meta's public policy says deletion can take up to 90 days to fully complete across its systems.

  1. Soft delete immediately: mark the post deleted in the metadata DB. The API stops returning it and stops issuing URLs. Signed CDN URLs already handed out expire within minutes to hours.
  2. Purge caches: issue CDN purges for the media URLs (belt and braces; see CDN).
  3. Enqueue a durable deletion job (e.g. a Kafka topic or deletion queue — see Message Queues) that enumerates every derived object — derivable keys or a manifest of renditions makes this reliable — and deletes them idempotently with retries.
  4. Versioned buckets: a plain DELETE only adds a delete marker; old versions remain. Delete specific version IDs or rely on a short NoncurrentVersionExpiration rule.
  5. Physical reclamation: in Haystack-style stores, compaction actually removes the bytes later; in erasure-coded warm storage, rewriting stripes is expensive, so f4 uses per-BLOB encryption keys and deletes the key ("crypto-shredding") — the remaining ciphertext is unreadable noise.
  6. Backups age out on a fixed retention schedule, or are also crypto-shredded by deleting per-user keys.
  7. Verify: deletion frameworks (Meta has published about its DELF framework) track every data type linked to a user so nothing is orphaned, and audit that deletion completed.
⚠️ Retention conflicts Legal holds, law-enforcement preservation requests and child-safety reporting obligations can require keeping specific data even after a user deletes it. S3 Object Lock (WORM: write once, read many) and legal-hold flags enforce this; your deletion pipeline must respect them. Stories that "disappear after 24 hours" are hidden from viewers, not necessarily destroyed — they may live on in the user's private archive (see Stories).

13. Cross-region replication

A single region can fail (power, network, natural disaster). Object stores offer cross-region replication (CRR): every new object written to a source bucket is copied asynchronously to a bucket in another region. S3 Replication Time Control offers an SLA of replicating 99.99% of objects within 15 minutes.

See Multi-Region & Disaster Recovery for RPO/RTO and failover.

14. Serving through the CDN

Object storage is optimised for durability and throughput, not for being hit by billions of phones. Users should never download directly from the bucket:

15. How Instagram uses object storage

📱 Appgets pre-signed URL
→multipart PUT
Raw upload bucketquarantine
→event via Kafka
Media workersvalidate, resize, transcode
→PUT renditions
Media storehot → warm tiers
→origin pull
CDNserves users
  1. The Upload Service authenticates the user, creates a media ID (see ID Generation), and returns a pre-signed, short-lived upload URL. The phone uploads directly (multipart and resumable for video).
  2. An object-created event lands on Kafka; Media Processing Workers validate the file, strip EXIF location data, run moderation, and write renditions under immutable, hash-prefixed keys.
  3. The post's metadata row in Cassandra stores the media ID and available renditions — never the bytes.
  4. The Feed returns signed CDN URLs; the CDN pulls from object storage on a miss.
  5. As media cools, it moves from replicated hot storage to erasure-coded warm storage; raw uploads in the quarantine bucket expire after a few days; originals may be kept for re-processing into new formats (e.g. AVIF) later.
📸 In Instagram Our architecture diagram labels this box "Object Storage (S3)", and early Instagram (2010–2012) did store photos on Amazon S3 while running on AWS, as described in the team's public "What Powers Instagram" engineering post. After moving into Facebook's data centers, Instagram media lives in Meta's in-house BLOB storage, whose public lineage is Haystack (hot photos, replicated) → f4 (warm, erasure-coded) and later systems. For design interviews, saying "S3-compatible object storage, private bucket, pre-signed uploads, lifecycle tiering, CDN in front" is exactly right; mentioning Haystack's metadata insight shows depth.

16. Trade-offs & common pitfalls

✅ Strengths

  • Virtually unlimited scale and very high durability
  • Cheapest storage per GB, with even cheaper tiers
  • Simple HTTP API; direct client uploads via pre-signed URLs
  • Perfect fit for immutable media and CDN origins
  • Fully managed (cloud) — no disks to replace

⚠️ Limitations

  • Higher latency than block/file storage (tens of ms to first byte)
  • No in-place updates, appends, renames or locking
  • No transactions across objects or with your DB
  • LIST is slow and paginated — not a query engine
  • Egress, request and retrieval fees can surprise you

Common pitfalls

17. Real-world technologies

TechnologyNotesWhen to use
Amazon S3The de-facto API standard; storage classes, lifecycle, CRR, Object Lock, strong consistencyDefault choice on AWS
Google Cloud StorageStrongly consistent; dual/multi-region buckets; Autoclass tieringGCP workloads, built-in geo-redundancy
Azure Blob StorageHot/cool/cold/archive tiers; block/append/page blobsAzure workloads
Cloudflare R2, Backblaze B2, WasabiS3-compatible, low or zero egress feesEgress-heavy workloads, often paired with a CDN
MinIOS3-compatible object server you run yourself; erasure codingOn-prem / private cloud, dev/test
Ceph (RADOS Gateway)Open-source unified block/file/object storage with CRUSH placementLarge self-hosted clusters
HDFSDistributed file system for big-data batch jobs (large files, append-only)Hadoop/Spark analytics, not media serving
Haystack / f4 (Meta, internal)Needle-packed hot store; erasure-coded warm storeReference designs for billions of small media files

18. Interview corner

Why not store photos in the database?

Databases are optimised for small, indexed, transactional rows. Multi-MB blobs pollute the buffer pool, slow replication, backups and schema changes, and cost far more per GB (fast SSD, replicas, RAM). Object storage is ~10× cheaper per GB, scales to exabytes, gives 11-nines durability, and integrates with CDNs. Store bytes in object storage and only metadata (owner, caption, media ID/keys, dimensions) in the database.

Design the photo upload path.

Client calls the Upload Service (authenticated), which validates quota/size/type, allocates a media ID and returns a pre-signed PUT (or multipart) URL for a private raw bucket, valid ~15 minutes. The client uploads directly to object storage, resumably for large videos. An object-created notification (or the client's "finalize" call) publishes a Kafka event; media workers validate, strip EXIF, generate renditions, run moderation and write processed objects to the media bucket under immutable keys, then mark the post ready. Raw uploads expire via lifecycle; incomplete multipart uploads are aborted after a day.

Explain erasure coding vs replication and when you'd use each.

Replication stores N full copies: 3× storage, survives N−1 losses, trivial reads and cheap repair. Erasure coding (Reed-Solomon k+m) splits data into k fragments plus m parity; any k fragments reconstruct it, so RS(10,4) survives 4 losses at only 1.4× storage — but repairs need reading k fragments (more network), small objects are inefficient and there's CPU cost. Use replication for hot, small, latency-critical data; erasure coding for the bulk of warm/cold bytes. Facebook's Haystack (≈3.6×) → f4 (≈2.1×) migration is the canonical example.

What problem did Haystack solve, and how?

Billions of small photos as individual files meant multiple disk seeks per read just for file-system metadata (directory, inode), and inode metadata was too large to cache in RAM. Haystack appends photos as needles into ~100 GB volume files and keeps a ~10-byte-per-photo in-memory index from photo key to (offset, size), so a read is one seek. Writes go to 3 replicas of a logical volume; deletes set a flag and compaction reclaims space; a Directory maps logical to physical volumes and a Cache serves freshly uploaded hot photos.

How would you reduce storage cost for Instagram media by 40%+?

(1) Erasure-code warm data instead of replicating (3× → 1.4–2.1×). (2) Lifecycle tiering based on age/access: hot → infrequent-access tier after ~60 days, since the CDN absorbs repeat reads. (3) Better codecs (WebP/AVIF for images, AV1/HEVC for video) cut bytes 25–50% at equal quality. (4) Generate rare renditions lazily rather than eagerly. (5) Dedupe identical uploads by content hash. (6) Expire raw uploads, incomplete multipart uploads and non-current versions. (7) Don't replicate cross-region what can be regenerated.

A user deletes their account. How do you make sure all their media is gone?

Soft-delete metadata immediately so nothing is served; issue CDN purges; enqueue a durable, idempotent deletion workflow that enumerates every media object (via the metadata index and derivable rendition keys) across all regions and versions and deletes them; for erasure-coded or backup data, rely on crypto-shredding by deleting per-user/per-object keys; let backups age out within a documented window; respect legal holds; and audit completion with a deletion framework that tracks all data types linked to the user.

S3 used to be eventually consistent. Why did that matter, and what changed?

Before December 2020, overwrites, deletes and LIST were eventually consistent: a reader might get an old version or a listing missing new keys, which broke pipelines that wrote then listed (e.g. data lakes needed external consistency layers). Since then S3 offers strong read-after-write consistency for all object PUT/DELETE and LIST operations. Downstream caches (CDN) and cross-region replicas are still eventually consistent, so immutable keys remain best practice.

19. Check your understanding

Block, file or object: (a) PostgreSQL data directory, (b) 4K Reel video segments, (c) a shared folder of config files mounted by 20 servers?

(a) Block — databases need low-latency random in-place writes. (b) Object — immutable, large volume, served via CDN. (c) File — POSIX semantics shared by many hosts.

RS(6,3): what's the storage overhead and how many fragment losses can it survive?

9/6 = 1.5× overhead; survives any 3 lost fragments (any 6 of 9 reconstruct the data). Triple replication survives only 2 losses at 3×.

You store 1 billion objects with 11 nines of annual durability. How many do you expect to lose per year?

10⁹ × 10⁻¹¹ = 0.01 objects/year — one object roughly every 100 years.

Why does "keep the inode metadata in RAM" fail for billions of photos, while Haystack's in-memory index succeeds?

A file-system inode is hundreds of bytes (536 B for XFS per the paper) with fields photos don't need; billions of them don't fit in RAM. Haystack stores only what's needed — key, flags, offset, size — about 10 bytes per photo, so the whole index fits in memory and a read needs a single disk seek.

A 15 KB thumbnail is moved to Standard-IA. Why might that increase its cost?

IA bills a minimum of 128 KB per object, so the 15 KB thumbnail is billed as 128 KB × $0.0125 ≈ more than 15 KB × $0.023 in Standard (≈ 4.6× more), plus retrieval fees per access. Small objects should stay in Standard or be packed together.

Your upload keys are p/{post_id}/1080.jpg where post IDs are time-sortable. Writes are throttled during peaks (503 Slow Down). Why, and how do you fix it?

Time-sortable IDs make all new keys share a narrow, increasing key range, so every upload hits the same index partition (hot prefix). Prefix keys with a short hash ({hash4}/p/{post_id}/…) to spread writes across many partitions.

The phone uploads a 1.5 GB video with a single PUT over a mobile network and fails at 90%. What should the design do instead?

Use multipart upload: split into e.g. 10 MB parts, upload several in parallel, retry only failed parts, and resume after interruption using the UploadId; complete when all parts are done. Add a lifecycle rule to abort abandoned uploads.

🎯 Key takeaways

Related lessons