Skip to lesson
‹

Courses / System Design Interview / Chapter 17

Module 2 · Building Blocks · Chapter 17 of 39

Blob Stores

18 sections · ~31 min✓ Fact-checked

Builds on Databases: Replication, Partitioning and Choosing a Store, Designing a Key-Value Store, Content Delivery Networks and Message Queues. Next up: Distributed Search.

Part 1 · What a Blob Store Is For

Files are not rows

It is past midnight after a wedding in Jaipur, and two hundred guests open the same photo backup app to save what they shot. A cousin's 2 GB video of the baraat reaches 93% when her phone switches towers, and the upload starts again from zero. In the app's data centre, one of the two file servers holding every family's photos reports a dead disk array, and the team spends the night restoring a week-old backup. A restart from zero, one machine holding everything, a lost week: each is a problem a blob store is built to solve.

A blob (binary large object) is a file stored as an opaque run of bytes: a photo, a video, a backup. A blob store, also called an object store, keeps billions of them, from a few KB to many GB each, and returns any one by name. This chapter follows the backup app as it grows from those two file servers to 10 billion files.

Keeping files in the database is the obvious first idea, and a poor one. Databases are built for small rows that are queried and updated in place; a 4 MB photo in a row slows backups and replication and pushes useful rows out of memory, for bytes nobody queries. So the usual split is simple: the file goes in the blob store, and a small row in the database points to it.

Here is how the three options compare.

Database rowFiles on one server's diskBlob store
Best size per itemBytes to a few KBAnyKB to many GB
ScaleLimited by the databaseOne machine's disksBillions of objects, petabytes
Survives a dead serverWith replicasNoYes, copies on several machines
Cost per GBHighLow, but you run everythingLow
Best size per item

Database rowBytes to a few KB

Files on one server's diskAny

Blob storeKB to many GB

Scale

Database rowLimited by the database

Files on one server's diskOne machine's disks

Blob storeBillions of objects, petabytes

Survives a dead server

Database rowWith replicas

Files on one server's diskNo

Blob storeYes, copies on several machines

Cost per GB

Database rowHigh

Files on one server's diskLow, but you run everything

Blob storeLow

The blob store is the only column that survives a dead machine and still grows to petabytes, which is exactly what the backup app lacked that night.

Buckets, keys and metadata

From outside, the data model is deliberately small. A bucket is a named container, often one per app and environment, with its own access rules. Inside it, each object is identified by a key, a string such as u/42/2026/10/IMG_2041.jpg for user 42's photo.

The slashes look like folders, but the namespace is flat: the key is just a string, and listing all keys that start with u/42/2026/10/ gives a folder-like view of one month. Each object also carries metadata: system fields such as size, content type, creation time and a checksum, plus your own fields such as the phone it came from.

http
PUT /backup-prod/u/42/2026/10/IMG_2041.jpg
Content-Type: image/jpeg
Content-Length: 3412880

GET /backup-prod/u/42/2026/10/baraat.mp4
Range: bytes=0-1048575

HEAD /backup-prod/u/42/2026/10/IMG_2041.jpg
GET /backup-prod?prefix=u/42/2026/10/&limit=100
DELETE /backup-prod/u/42/2026/10/IMG_2041.jpg

Put, get (whole or a byte range), metadata only, list by prefix, delete. That is nearly the whole API.

Objects are usually immutable: you replace a whole object rather than editing bytes in the middle, which makes caching and replication much simpler, because a copy can never be half old and half new. A byte-range read still lets a video player fetch only the minute it needs.

Design keys for spread, not only for people

Some stores split the key space into sorted ranges, so if every key starts with today's date, all of today's uploads land on one partition. A short hash at the front of the key, such as 7f/u/42/2026/10/IMG_2041.jpg, spreads the load.

Names you will hear

Amazon S3, Google Cloud Storage and Azure Blob Storage are the big clouds' managed stores; use the one where your servers run, since moving data between clouds costs egress. MinIO is an S3-compatible store you run yourself, when data must stay on premises. HDFS holds huge files read in bulk by analytics jobs, not photos served to phones.

Part 2 · Inside the Store

Metadata service and data nodes

Behind that API, a blob store has two very different jobs, so it uses two kinds of servers. The metadata service knows, for every object, which chunks it is made of and which data nodes hold each chunk. The data nodes store chunks on their local disks and do little else.

API front end

Checks who you are

Streams bytes in and out

Stateless, many copies

Metadata service

Key → chunks → nodes

Small, hot, must be consistent

A replicated, partitioned database

Data nodes

Store chunks on disk

Report health and free space

Thousands of them, all alike

Metadata is small but read on every request, so it lives in a replicated, partitioned database (the databases chapter) with strong consistency. Each partition's leader is chosen through consensus (the coordination chapter), so two servers never both decide where a key's chunks go. The bytes are huge but simple, so they sit on cheap disks.

The backup app shows the difference in size. Say it reaches 1 crore users with about 1,000 files each: 10 billion objects. Assume an average of 1 MB, since every photo also has small thumbnail objects beside it.

MetadataData
Per objectAbout 500 bytesAbout 1 MB on average
For 10 billion objectsAbout 5 TBAbout 10 PB
NeedsFast, consistent lookupsCheap disks and lots of bandwidth

Metadata is about 2,000 times smaller than the data it describes, small enough for a database cluster, while the bytes need thousands of disks. Data nodes send a heartbeat to the metadata service every few seconds with their health and free space. That is how the metadata service knows where new chunks can go, and how it notices when a node stops answering.

Chunks and multipart upload

The cousin's 2 GB baraat video is where the design meets a real phone network. Sent as one piece, it is fragile: a tower switch at 93% means starting again, and one data node must hold the whole file. So large files are split into chunks of a fixed size, from a few MB to around 128 MB. In chunks, a file can be uploaded in parallel, retried a piece at a time and spread over many nodes.

The client side of this is called multipart upload, and it runs in five steps.

Multipart upload
  1. 1Startthe client asks to begin and gets an upload id
  2. 2Upload partseach part carries its number; parts go in parallel and in any order, and each reply includes a checksum
  3. 3Retry what failedonly the failed parts are sent again
  4. 4Completethe client sends the list of parts, and the object appears all at once
  5. 5Or abortthe client cancels, or a cleanup rule removes uploads left unfinished for a few days

In numbers: the 2 GB video in 16 MB parts is 128 parts. Over home Wi-Fi uploading about 5 MB/s, it takes about 7 minutes, and a dropped connection costs at most one 16 MB part, about 3 seconds of work. The app saves the upload id and the finished part numbers on the phone, so it can resume even after being closed.

Part size is a trade-off. Small parts waste less on a retry but mean more requests and more metadata per object. Managed stores also cap the number of parts, commonly at 10,000 per upload, so a client picks bigger parts for bigger files. Once the parts arrive, each chunk must be stored safely, which raises the next question: what happens to the video when a data node dies?

Watch: an upload survives a dead node

Here is the whole life of a smaller file, a 48 MB clip from the same wedding: three chunks, three copies of each on four data nodes, then a disk failure the day after.

Predict before you watch: data node 2 holds a copy of all three chunks, then its disk fails. Can the video still be played, and what brings each chunk back to three copies?
  • Yes. Every chunk still has two copies on other nodes.
  • Missed heartbeats tell the metadata service, which has surviving nodes copy each lost chunk to a node that lacks it.
Animated sceneA chunked upload, a dead node, and repair0:30

Watch for the node labels: a 48 MB video goes up as three 16 MB chunks

Read it as steps

The labels on the data nodes show which chunks each one holds.

The bytes never passed through the metadata service, only decisions did, and the video appeared only at "complete", so readers never see half a file. Losing a node cost no data because every chunk had copies on other machines. Repair ran from two survivors at once instead of waiting for one replacement disk, and that difference decides durability at scale.

Writing when a node is down or slow

The scene's writes met healthy nodes. Real writes meet dead or slow ones, and must decide quickly while the phone waits.

  • A node is down. The metadata service has seen its heartbeats stop and does not pick it. If a node dies mid-write, the API asks for a replacement and writes the chunk there, so the chunk still has three copies before the client hears OK.
  • A node is slow. The write waits for every copy, so one disk taking 2 seconds slows every upload it touches. Give each copy a timeout of a few times the normal p99, then write to a replacement.
  • Confirming at two copies. Some stores reply after two copies and let repair make the third. Uploads get faster at the tail, but for a few minutes that chunk survives only one more loss, so do it only with fast repair.
  • Erasure-coded writes follow the same rules per piece: the 9 pieces of a 6 + 3 chunk (explained on the next page) go to 9 different nodes, and a piece whose node fails is written elsewhere.

A half-finished write is never visible: a chunk that reached two nodes before the API crashed was never added to the metadata, so no reader finds it, and garbage collection removes the strays later. Three full copies are the simple answer to durability; the next page asks whether they are the cheapest one.

Replication or erasure coding

Core deep dive

Durability is the one promise a blob store cannot break: how many copies, placed where, and how fast they are repaired. This page and the next two carry it.

With 10,000 disks failing at roughly 1 to 2% a year, you lose one every two to four days. Durability, the chance that an object survives a year, comes from redundant data on different machines.

Replication keeps full copies, usually 3, on different disks and racks. It is simple, reads are fast, and repairing a lost copy means copying one chunk. The price is 3× the storage.

Erasure coding works like a parity sum: from k data pieces it computes m extra parity pieces, so that any k of the k + m pieces can rebuild the chunk. Reed-Solomon coding is the classic method. With 6 + 3, a chunk becomes 9 pieces on 9 nodes, uses 9 ÷ 6 = 1.5× the storage and survives any 3 lost pieces. The price is work: encoding costs CPU, reading a whole chunk means fetching pieces from 6 nodes, and rebuilding one lost piece means reading 6 others over the network.

Side by side, for 1 PB of data:

SchemeRaw disk for 1 PBLosses survivedRepairing one pieceGood for
3 replicas3 PB2Copy one chunkHot data, small objects
Erasure coding 6 + 31.5 PB3Read 6 pieces to rebuild 1Warm and cold data
Erasure coding 10 + 41.4 PB4Read 10 pieces to rebuild 1Large, rarely read archives
3 replicas

Raw disk for 1 PB3 PB

Losses survived2

Repairing one pieceCopy one chunk

Good forHot data, small objects

Erasure coding 6 + 3

Raw disk for 1 PB1.5 PB

Losses survived3

Repairing one pieceRead 6 pieces to rebuild 1

Good forWarm and cold data

Erasure coding 10 + 4

Raw disk for 1 PB1.4 PB

Losses survived4

Repairing one pieceRead 10 pieces to rebuild 1

Good forLarge, rarely read archives

Erasure coding halves the disk and survives more losses; it pays in network and CPU on every repair and degraded read. Many stores use both: the backup app's new uploads stay replicated while they are viewed and shared, and files untouched for 30 days are re-encoded to 6 + 3.

Catching silent corruption

Disks occasionally return wrong bytes without an error. Every chunk carries a checksum, verified on each read and by a background scrub; a chunk that fails is treated as lost and repaired.

Placement and repair

Copies only help if they do not die together, and only while they are rebuilt faster than disks fail. A failure domain is a set of things that fail together: a disk, a machine, a rack sharing one power feed and one switch, a building. Three copies in one rack disappear together when that rack loses power, so placement puts each copy in a different rack.

Erasure coding needs the same care per piece. If a 6 + 3 chunk keeps 3 pieces in each of 3 racks, losing one rack uses up all its spare pieces, and one more disk failure during that hour loses the chunk. With one piece in each of 9 racks, a whole rack plus any two disks can fail. So a coded cluster needs at least 9 racks to get the full benefit.

Repair is a race. An object is lost only if every copy, or 4 of its 9 pieces, fails before repair finishes, so durability depends on repair speed as much as on the number of copies. Take a 20 TB disk that is 80% full: 16 TB of chunks to rebuild.

  • Onto one replacement disk, writing about 200 MB/s: 80,000 seconds, most of a day exposed.
  • Spread over 80 nodes, each re-copying 200 GB at 100 MB/s: about half an hour.
  • With 6 + 3 coding, each lost piece is rebuilt by reading 6 others: about 96 TB of network reads. Over 40 nodes at 100 MB/s each, that is about 7 hours, unless repair gets more bandwidth.

Two rules keep repair from causing its own outage. Wait 10 to 15 minutes before declaring a node dead, because most silent nodes are rebooting, and rebuilding 16 TB for a node that returns wastes the network. And repair the chunks with the fewest copies left first, throttled so user reads keep their bandwidth. A chunk down to its last copy skips the wait entirely.

How many machines

The redundancy scheme now turns into hardware. Take the backup app's 10 billion objects, about 10 PB of data, and assume nodes of 24 disks of 20 TB each. The scheme changes the answer by a factor of two.

3 replicasErasure coding 6 + 3
Data stored10 PB10 PB
Raw disk needed30 PB15 PB
Usable per node: 24 × 20 TB, filled to 80%≈ 384 TB≈ 384 TB
Data nodes≈ 80≈ 40
Disks, failing at 1–2% a year≈ 1,900: one every 10–20 days≈ 960: one every 20–40 days

Halving the disk halves the machines, but the smaller cluster has less spare bandwidth for its heavier repairs. Fill disks only to about 80%, because repair needs free space to rebuild into. The 40-node answer also has a placement catch from the previous page: those nodes must spread over at least 9 racks, about 4 or 5 nodes each.

Money follows the same shape. Managed object storage costs roughly $0.02 per GB-month (check current prices), so 10 PB is about $200,000 a month. Either way, for files many people download, internet egress at about $0.05–0.10 per GB often costs more than storing them, which matters once the app lets families share albums.

Part 3 · Deletes, Downloads and Uploads

Deletes and garbage collection

A delete has two halves. Removing the key from the metadata is quick, and from that moment the object is gone from reads and listings. Freeing the chunks on the data nodes happens later, in the background, because deleting across many nodes is slow and can fail halfway.

What happens after DELETE
  1. 1Metadata marks the object deletedreads and listings stop seeing it at once
  2. 2A grace period passesa few days in which the delete can still be undone
  3. 3The garbage collector scansit compares the chunks on each data node with the chunks the metadata still refers to
  4. 4Orphan chunks are freeddata nodes delete them and reclaim the space

Deleted objects are not the only source of orphan chunks, chunks that nothing refers to. Abandoned multipart uploads leave parts behind, and a write that failed after reaching some nodes leaves stray copies. All are collected the same way. The backup app adds its own layer on top: deleted photos sit in a trash for 30 days, and only then does the app send DELETE to the store.

Never delete the chunks first

If you free the chunks and then the metadata update fails, the metadata points at data that no longer exists, and readers get errors. Remove the reference first; an orphan chunk only wastes space until the next collection.

Lifecycle rules automate the rest: move objects older than 30 days to a colder tier, delete old versions after 90 days, abort incomplete uploads after 7.

Serving files: signed URLs and a CDN

Next, how bytes reach phones. Do not stream files through app servers: a 2 GB download ties up bandwidth and a connection for minutes, and the app adds nothing. Let clients talk to the blob store directly, but only for files they are allowed to see.

A signed URL (often called a pre-signed URL) makes that safe. After checking that the user may access a file, your app server builds a URL containing the path, an expiry time and a signature: a keyed hash of those fields, made with a secret only your servers and the store know. The store recomputes it and serves the file only if it matches and the time has not passed, so nobody can change the path or expiry. Anyone holding the link can use it, so keep expiries to minutes.

http
POST /api/uploads                     (the app server checks login, quota and file type)
200 {"upload_url": "https://blobs.example.in/backup-prod/u/42/9f1c.jpg?expires=1792134000&sig=4b9e..."}

PUT https://blobs.example.in/backup-prod/u/42/9f1c.jpg?expires=1792134000&sig=4b9e...
Content-Type: image/jpeg
200 OK                                (the bytes went straight to the blob store)

The app server only signs; the bytes go straight between the phone and the store, for uploads and downloads alike.

When a family shares the wedding album with 500 relatives, the same photos are read thousands of times. Put a CDN in front of the bucket (the CDN chapter): the bucket becomes the CDN's origin, and edges near users serve repeat reads. Give files versioned names, such as a content hash in the key, so they can be cached for a year and never need invalidating; an edited photo simply gets a new name.

Stores can also publish an event when an object is created. On a queue (the message queue chapter), they let workers make thumbnails without the uploader waiting, and they answer a question this page skipped: how the app learns that an upload really happened.

From pending to ready: tracking uploads

A signed upload URL leaves your database in the dark. The phone may never upload, may send a different file, or may crash halfway. Treat each upload as a small state machine, with the database row as its record.

One photo upload
  1. 1Pendingthe app server inserts a row (photo 9f1c, owner 42, status pending) and signs a URL
  2. 2Uploadthe phone sends the bytes straight to the store before the URL expires, say in 15 minutes
  3. 3Object createdthe store publishes an event to a queue once the object is complete
  4. 4Readya worker checks the real size and type, makes thumbnails, then sets the status to ready
  5. 5Sweepa daily job deletes rows still pending after 24 hours, and any object they point to

Sign the limits into the URL itself: the exact key, the content type, a maximum size such as 50 MB, and the expiry. Where the store checks them, a 2 GB file or an executable is turned away at the door, because changing any of them breaks the signature. The worker still checks the real bytes.

Events arrive at least once and sometimes late, so the worker's last step is conditional: set ready only where the status is still pending. A duplicate event then changes nothing, and thumbnails are written to fixed keys, so redoing them is harmless. The album shows only ready rows. The app may call POST /uploads/9f1c/complete to mark it ready sooner, but the server must first confirm with a HEAD request that the object exists with the right size: never take the client's word that an upload finished.

Part 4 · Failures at Scale

What goes wrong at scale

Durability is not the only thing that breaks as the backup app grows.

ProblemSymptomFix
Hot objectA viral video's chunks hammered on a few nodesServe through a CDN; add extra copies of hot chunks
Huge bucketsListing 100 million keys is slowPartition metadata by bucket and key; paginate listings
Tiny filesPer-object overhead dwarfs the dataPack many small objects into one larger chunk with an index
Hot key rangeAll new uploads hit one metadata partitionHash prefixes in keys; split busy ranges
Orphans and leftoversStorage grows faster than live dataGarbage collection; lifecycle rules for uploads
Repair stormA dead rack starts petabytes of copyingWait before repairing; fewest copies first; throttle

Almost every fix moves load away from one hot spot, whether a node, a partition or the network. The table leaves out one property you must decide and state: consistency, what a reader sees right after a write.

With a single metadata record per key, read-after-write for a new object is straightforward: once the PUT succeeds, every GET sees it, because the commit and the read go to the same partition leader. Two uploads to the same key resolve the same way: each commits a complete chunk list, the later commit wins whole, and the loser's chunks become orphans for the collector. Listings are often served from a separate index and can lag by a moment; document that.

Losing a whole region

Copies across racks and buildings survive a dead disk, a dead machine and a dead rack. They do not survive losing a whole region to a flood, a fire or a long power cut. For data you cannot lose, keep a cross-region copy in a second region hundreds of kilometres away.

The copy is made asynchronously: each new object is written in its home region, then queued and copied over, usually within minutes. Copying before replying would add a cross-region round trip, 30 ms or more, to every part of every upload. The price is a window of recent uploads that a regional disaster could take with it; that window is your recovery point objective (RPO), the most recent data you accept losing.

Four rules shape the second region:

  • Each region is a complete store, with its own metadata, so the copy can serve reads alone if the home region goes dark.
  • Copy what matters. Original photos and videos, yes; thumbnails, no, since workers can rebuild them. Keep the copy in a colder, cheaper tier.
  • Respect data rules. Data that must stay in India, as payment data must, needs a second region that is also in India.
  • A copy is not a backup. Deletes copy across too, so turn on versioning, and lock backups against deletion for a set period, such as 30 days.

Part 5 · Interview kit

The 45-minute answer

For "design a blob store", spend the 40 minutes of design time like this.

MinutesWhat you say and drawKey number or decision
0–5Requirements: put, ranged get, delete, list by prefix; KB to TB objects; durability first; read-after-write.A durability target such as 11 nines a year; objects never change in place
5–8Estimates that decide something: objects, bytes, metadata size, machines.10 B objects ≈ 10 PB; metadata ≈ 5 TB; ≈ 80 nodes at 3×, 40 at 6 + 3
8–13API (PUT, GET, HEAD, DELETE, LIST, multipart) and metadata: key → size, checksum, chunk list → nodes.Chunks of 16–128 MB; an object appears only on complete
13–22Stateless API, consistent partitioned metadata, data nodes with heartbeats, signed URLs, a CDN, events.Bytes never pass through metadata or app servers
22–37Deep dive: durability (placement, writes with a dead node, repair) or metadata at scale (partitions, hot prefixes, listings).Rebuild a lost disk in under an hour across many nodes
37–40Wrap-up: rack and region loss, monitoring (repair backlog, chunks with one copy left, orphan bytes), cost.Async cross-region copy; egress often beats storage

Pick durability if they ask how you never lose a file: placement, writes with a dead node, repair speed. Pick metadata if they stress billions of objects or fast listings: partitions by bucket and key, hash prefixes, strong consistency per key.

Say
"Metadata and bytes are separate: about 5 TB of metadata in a strongly consistent, partitioned database, and 10 PB of chunks on about 80 data nodes."
Say
"New objects keep 3 copies in 3 racks; after 30 days they move to 6 + 3 coding, which halves the disk but makes each repair read 6 pieces."
Say
"Repair is spread across the cluster, so a dead disk's 16 TB is rebuilt in about half an hour instead of most of a day."
Avoid
Three copies in one rack: they share power and a switch, so they fail together.
Avoid
Streaming uploads and downloads through your app servers instead of using signed URLs.

Follow-ups and variants

A senior interviewer then probes what is easy to draw and hard to run:

The same core also appears under other names:

Wrap-up

TermMeaning
ObjectA file stored as opaque bytes under a key in a bucket
Metadata serviceMaps each key to its chunks and the nodes holding them
Erasure codingk data pieces plus m parity pieces; any k rebuild the chunk
Failure domainThings that fail together: a disk, a node, a rack, a region
Signed URLA short-lived link whose signature allows one action on one key
Orphan chunkA chunk no metadata refers to, freed by garbage collection

Next, the Distributed Search chapter shows how to find the right item among millions when a user types just a few words.

Part 6 · Check yourself

Quick check

Q1Why does a delete remove the metadata first and free the chunks later?

Think it through, then check.

Q2The backup app's storage bill grows 30% faster than the bytes its database says users uploaded. What are the likely causes?

Think it through, then check.

Q3Shared albums push the app to 200 TB stored and 2 PB downloaded a month. At $0.02 per GB-month to store and $0.05–0.10 per GB of egress, which bill is bigger, and what follows?

Think it through, then check.

Q4A rack holding 8 of your 80 data nodes loses power. Should repair start at once, and what happens meanwhile?

Think it through, then check.

Q5The CDN chapter cached files at the edge with long TTLs. A user crops a wedding photo and saves it under the same key, and relatives still see the old one for hours. Why, and what is the fix?

Think it through, then check.

Next chapter · 18 of 39Distributed Search~31 min · 1 animated scene