The Runtime Theory
Cloud & Infrastructure

Object Storage vs. Block Storage

S3 versus EBS: key-value HTTP APIs versus raw device semantics, strong read-after-write consistency, and the real math behind 99.999999999% durability.

The Runtime Theory Team4 min read#s3#ebs#storage#durability#consistency
On this page

"Object storage" and "block storage" sound like product categories; they are actually two different contracts with the machine. Block storage hands you a raw device with sector semantics — the kernel, or you, manage the filesystem on top. Object storage hands you a key-value HTTP API with request semantics — the provider manages the filesystem, the replication, and the durability math, and you exchange a request for a result. The differences in consistency, latency, and cost all fall out of that contract difference.

What each one is, mechanically

text
Block storage (EBS, NVMe, iSCSI):
  your contract: read/write sectors at offsets on a device
  the machine: a replicated disk you attach to exactly one instance at a time
  the price: per-GB-month + per-IOPS, billed continuously whether used or not
  the caveat: you own the filesystem, the fsck, the snapshot strategy
 
Object storage (S3, GCS, R2):
  your contract: PUT/GET/DELETE objects by key, over HTTP(S)
  the machine: a distributed key-value store, fronted by a global API
  the price: per-GB-month + per-request, billed only for what you use
  the caveat: it's an API with network latency; it is not a disk

The EBS volume is a network disk. A gp3 volume delivers a baseline of 3,000 IOPS and 125 MB/s per TB with sub-millisecond latency within its availability zone, and it is synchronously replicated to a second AZ-internal replica before the write completes — that replication is why EBS can promise 99.8–99.9% availability per volume. But an EBS volume attaches to one instance. Its durability is a property of the provider's replication; its availability is a property of the AZ.

S3 is not a disk at all. A PUT is an HTTP request to a control plane that places the object across a minimum of three AZs and returns 200 when the provider's internal replication has accepted it. There is no "mount," no filesystem, no file descriptor — there is a request, and a response.

The durability math, actually

S3's headline number is 99.999999999% (11 nines) durability. Here is what that means in expectation:

text
annual failure rate = 1 - 0.99999999999 = 1 × 10^-11
 
objects stored:      10,000,000
expected loss/year = 10^7 × 10^-11 = 0.0001 objects

Ten million objects, and the expected loss is one ten-thousandth of an object per year — statistically, one object every 10,000 years. That number exists because replication is done correctly: each object is redundantly stored across multiple AZs, each copy checksummed end-to-end, and a background repair process continuously re-replicates anything that degrades. Durability is not a storage property; it is a repair-velocity property — the math only holds if corrupted or lost replicas are repaired faster than the mean time between independent failures.

The caveat nobody reads: durability ≠ availability, and availability is not the same as your access path. If the API region is impaired, your 11-nines objects are still there — you just can't reach them through the degraded path. And versioning is what turns "durability" into "protection against your own mistakes": without it, a DELETE or a botched overwrite is permanent by design.

Consistency: what you actually get

For years, the standard advice was "S3 is eventually consistent — design for it." Then in December 2020 S3 shipped strong read-after-write consistency for all regions:

text
PUT /bucket/object  ->  200 OK
GET /bucket/object  ->  immediately returns the written value
GET /bucket          ->  list includes the object immediately

Every read, every list, every overwrite now sees the latest write. That killed an entire category of "S3 races" people designed around. But strong consistency is not transactionality: S3 offers no multi-object atomicity. Two objects updated together (a config file and its checksum) can be read in a torn intermediate state — one new, one old — because each PUT is its own distributed transaction. If your application needs "all or nothing," you need a manifest object that is written last and treated as the commit point.

EBS is the inverse: the device gives you strict ordering and read-after-write within its replication domain, but the provider adds no consistency machinery of its own — consistency is whatever your filesystem and your application do with the device.

The performance envelope

bash
# object storage: the API is the bottleneck, and you must respect it
curl -X PUT --data-binary @backup.tar \
  "https://bucket.s3.amazonaws.com/backup-2026-08-18.tar" \
  -H "x-amz-storage-class: STANDARD"
 
# block storage: you are talking to a disk, via the kernel
mkfs.ext4 /dev/xvdf
mount /dev/xvdf /data
dd if=/dev/zero of=/data/bench bs=1M count=1024 oflag=direct

Latency is the tell. A well-behaved S3 GET is 10–50 ms (plus network RTT); a byte-range GET pulls a 5 MB window from a multi-GB object in a single request, which is why S3 can serve as the backing store for video streaming. A gp3 volume serves random 4 KB reads in sub-millisecond. Anything that is random-access, latency sensitive, or requires a filesystem (databases, caches, scratch space) belongs on block storage. Anything that is written once and read many times, immutable by nature, or too big to mount (archives, media, backups, logs) belongs in object storage.

When each one wins

Block storage wins when you need a filesystem's semantics — POSIX locking, rename atomicity, mmap — or latency measured in microseconds. The cost model punishes you for paying for capacity when what you need is IOPS, and EBS's real tax is operational: snapshots, resizing, and the filesystem work are all yours.

Object storage wins when the workload is scale-out reads, immutable artifacts, or backup — and when you can design your access pattern around the API. The cost model is the mirror image: cheap GB-months, per-request fees, and egress charges that make "download everything to iterate" the most expensive design decision you can make.

The runtime view

  • Block storage is a replicated device with filesystem semantics; object storage is a replicated key-value HTTP API. The contract difference is the whole story.
  • Durability is a repair-velocity property: 11 nines only holds while the provider re-replicates faster than replicas fail.
  • S3 is strongly consistent per-object since 2020, but has no multi-object transactions — torn reads across related objects are still on you.
  • Latency, IOPS, and access pattern decide the split: sub-millisecond random I/O is a disk; write-once-read-many is an object.