Raw volumes with block storage
Open in the interactive app: practice, quiz, mock interview →In one minute
- Block storage exposes a device as a flat array of fixed-size blocks addressed by number (logical block address, LBA); the only operations are read N blocks, write N blocks, flush, and discard.
- It knows nothing about files, names or permissions. A file system or database on top supplies all of that, which is why block storage is the layer under nearly every database, VM disk and container volume.
- It comes as local disks (NVMe, SATA), shared SANs (iSCSI, Fibre Channel, NVMe over Fabrics), and cloud network volumes (Amazon EBS, Google Persistent Disk, Ceph RBD) that are replicated and attached to one machine at a time.
- Performance is three numbers, IOPS, throughput and latency, tied together by queue depth. Network volumes trade some latency for durability, snapshots and the ability to move between hosts.
- Snapshots are copy-on-write: a snapshot freezes a block map, and later writes go to new blocks. The problem shapes are "partial failure" (torn writes, lost flushes) and "trust but verify" (is the data durable when the call returns?).
How it works
The interface
A 1 TiB NVMe drive with 4 KiB logical blocks is an array of 268,435,456 blocks. The host submits commands such as "read 8 blocks at LBA 1,048,576 into this buffer", and a completion arrives later. Block 77 is just 4,096 bytes with no name. A file system (ext4, XFS) keeps its superblock, inodes, bitmaps and journal inside those blocks, and databases on top think in 8 KiB or 16 KiB pages that line up with them.
Flush (or a FUA write) makes previously acknowledged writes durable; it is what fsync ultimately triggers. Discard (TRIM, UNMAP, NVMe Deallocate) says a range holds no data, so an SSD can erase it and a thin volume can release the space.
Block, file and object
File storage (NFS, SMB, EFS) moves the file system to a server shared by many clients. Object storage (its own lesson) drops in-place updates: whole objects by key over HTTP. Block storage is the lowest and fastest of the three, usually attached to one host at a time, because two hosts mounting one ext4 file system would corrupt each other's caches and allocation maps.
Where block storage lives
Local disks give the lowest latency, roughly 80 to 100 microseconds for a 4 KiB random read on a datacenter NVMe SSD, but die with the host. SANs put disk arrays on a dedicated network and present LUNs to servers over iSCSI or Fibre Channel. Cloud volumes are SANs at fleet scale: replicated extents on storage servers that a card or hypervisor presents to the guest as a local NVMe device, which you can detach, reattach elsewhere, resize and snapshot.
Snapshots and thin provisioning
A cloud volume is a map from logical block to physical location, and a snapshot freezes that map. The first write to a block afterwards goes to a new physical block, leaving the old one to the snapshot: copy-on-write, so a snapshot costs nothing up front and grows only with changes. AWS stores EBS snapshots incrementally in S3, replicated across the Region's zones (EBS snapshots), so a daily snapshot of a 1 TiB volume that changes 20 GiB a day costs about 20 GiB per day, not 1 TiB. Thin provisioning uses the same map: a 1 TiB volume consumes physical space only for blocks ever written, and discard returns it.
Down the stack
Layer 1The contract
A write that has completed may still sit in a volatile device cache; only after a completed flush, or a write with Force Unit Access, must it survive power loss. Writes are atomic only up to the device's atomic write unit, typically one logical block (512 B or 4 KiB). A 16 KiB InnoDB page written as four 4 KiB blocks can be torn: half old, half new after a crash. There is no ordering promise between concurrently outstanding writes, so a file system that needs "journal before data" must wait for completion and flush in between. Cloud volumes add availability and durability numbers: AWS states 99.8% to 99.9% annual durability for gp3 and 99.999% for io2 Block Express (EBS volume types), and performance limits, such as gp3's baseline of 3,000 IOPS and 125 MiB/s, provisionable up to 80,000 IOPS and 2,000 MiB/s at 500 IOPS per GiB (gp3 docs). Those gp3 ceilings were 16 TiB, 16,000 IOPS and 1,000 MiB/s until September 2025 (AWS announcement), so older sizing guides that stripe several gp3 volumes for performance may no longer need to. Note the durability figure is per volume, not per byte: a 0.1% to 0.2% annual failure rate means one or two lost volumes per 1,000 a year, which is why snapshots are not optional.
Layer 2The mechanism
In Linux, a file system submits I/O as struct bio requests, which the multi-queue block layer (blk-mq) places on per-CPU software queues, optionally merges and schedules, and maps to hardware dispatch queues (blk-mq docs). NVMe allows up to 65,535 I/O queues, each holding up to about 64K outstanding commands (NVM Express FAQ), so every core can have its own queue without locks. The driver writes a 64-byte command into the submission queue, rings a doorbell register, and the device posts a 16-byte completion entry and raises an interrupt or is polled.
Network volumes add a translation layer. Ceph RBD stripes an image across RADOS objects, 4 MiB by default (rbd manual), placed on OSDs by the CRUSH algorithm and replicated three ways; the primary OSD acknowledges a write only after every replica has persisted it. Each OSD runs BlueStore, which writes straight to the raw device, keeps its block map in an embedded RocksDB with a write-ahead log, and checksums everything it stores; the older FileStore backend, which journaled into a local file system, is unsupported from the Reef release on (Ceph storage devices). Snapshots are tracked per object, so the first write to an object after a snapshot clones it. Linux device-mapper's thin provisioning (kernel docs) keeps a B-tree from virtual block to data block on a metadata device, with reference counts so snapshots can share blocks; a block whose count drops to zero returns to the pool. EBS keeps its volume configuration in a cell-based store called Physalia, described in an NSDI 2020 paper as "millions" of small databases rather than one (Brooker et al.), so that re-mirroring after a server failure does not depend on one central database.
Layer 3The machine
Every I/O on a network volume is a network round trip plus a replicated write. On AWS Nitro instances, a dedicated card presents the EBS volume to the guest as an NVMe device and speaks AWS's own transport to storage servers; AWS promises gp3 only single-digit millisecond latency, and designs io2 Block Express for an average under 500 microseconds on 16 KiB I/Os (gp3 docs), against roughly 0.1 ms for instance-store NVMe.
Latency and IOPS are linked by Little's law: IOPS = outstanding I/Os / latency. At 0.5 ms per I/O, a single-threaded synchronous writer (queue depth 1) gets at most 2,000 IOPS no matter what was provisioned; reaching 16,000 IOPS needs at least 8 I/Os in flight. Throughput limits bind with large I/Os instead: at 125 MiB/s, 256 KiB writes top out near 500 per second. A database fsync on a network volume therefore costs about a millisecond, which is why commit-heavy workloads lean on group commit.
Databases guard against torn pages themselves: Postgres logs a full page image on the first change after a checkpoint (full_page_writes, Postgres docs), and InnoDB writes pages to a doublewrite buffer first, on by default (MySQL docs). Both spend write bandwidth that a larger atomic write unit would save, and that unit now exists in places. EBS offers torn write prevention for aligned 4, 8 and 16 KiB writes on every volume attached to a Nitro instance (EC2 docs), and Linux 6.11 added the RWF_ATOMIC flag so an application can ask for an all-or-nothing write: O_DIRECT only, a power-of-two length within the limits statx reports, at a naturally aligned offset (pwritev2(2)). An end-to-end atomic 16 KiB write is what makes it safe to switch off the doublewrite buffer; without one, switching it off trades integrity for speed.
Why it's built this way
- Disks and flash read and write in fixed units (512 B sectors, 4 KiB to 16 KiB flash pages), so the interface is fixed-size blocks, not bytes.
- Different software wants different structures on top (file systems, databases, VM images), so the device offers only an address space and leaves meaning to the layer above.
- Device caches are volatile and reordering raises throughput, so durability and order are opt-in through flush and FUA, not free on every write.
- A local disk dies with its host, so cloud volumes replicate over the network and accept extra latency in exchange for durability and detach-and-reattach.
- Copying a full volume to back it up is slow and expensive, so volumes keep a block map and snapshot by freezing it, paying only for changed blocks.
Diagram
flowchart TD
App["Database: write 8 KiB page"] --> FS["File system (ext4/XFS)"]
FS --> BIO["bio to blk-mq per-CPU queue"]
BIO --> NVQ["NVMe submission queue + doorbell"]
NVQ --> Card["Virtual NVMe (Nitro card / hypervisor)"]
Card --> Map{"Block map: LBA to extent"}
Map -->|"block shared with snapshot"| New["Allocate new extent (copy-on-write)"]
Map -->|"block exclusive"| Same["Overwrite in place"]
New --> Rep["Replicate to storage servers"]
Same --> Rep
Rep --> Ack["Completion entry to guest"]Worked example
A Postgres primary on a 2 TiB gp3 volume does 6,000 commits per second at peak, each touching a few 8 KiB pages, with a 300 GB working set.
Commits first. Each commit needs a WAL fsync. At about 1 ms per flush and queue depth 1, one flushing process could commit 1,000 times per second. Group commit lets one fsync cover every transaction that arrived meanwhile, so 6,000 commits per second need only a few hundred flushes per second. The volume never sees 6,000 flush IOPS; latency is the limit, not provisioned IOPS.
Then page I/O. Checkpoints write dirty pages: if 40 GB of pages are dirtied between checkpoints every 15 minutes, that is about 45 MB/s spread over the interval, comfortably below gp3's 125 MiB/s baseline. Cache misses on a 300 GB working set with 128 GB of RAM produce perhaps 4,000 random 8 KiB reads per second, above gp3's 3,000 IOPS baseline, so provision 8,000 IOPS for headroom. Provisioning IOPS and throughput separately from size is the point of gp3; on a volume type that scales IOPS with size you would be buying unused terabytes to get the IOPS.
Snapshots: with 60 GB of changed blocks a day and 30-day retention, storage is one full copy of the written blocks plus 1.8 TB of increments. A restored volume loads lazily from S3, block by block on first read, so a freshly restored replica is much slower until it has touched its working set. Two paid options remove the guesswork: fast snapshot restore, which delivers full performance at creation, or a provisioned initialization rate of 100 to 300 MiB/s; at 300 MiB/s, 1.2 TB of written blocks takes a little over an hour (EBS docs).
In the wild
- AWS, 2011: the EBS re-mirroring storm. A mistaken network change in one US-East zone pushed primary traffic onto a low-capacity backup network, cutting many EBS nodes off from their replicas. When the network returned, every node searched for free space to re-mirror at once, exhausted the cluster's spare capacity, and about 13% of the zone's volumes got stuck; slow control-plane calls then starved the regional API. Recovery took about three days and 0.07% of volumes could not be restored to a consistent state. AWS added spare capacity, made nodes back off and reconnect to their old replicas, and fenced the control plane per zone (AWS summary).
- AWS, 2012: a stale DNS entry leaks memory on every storage server. After a data-collection server was replaced, a DNS update did not reach every internal resolver, so a data-collection agent on some EBS storage servers kept retrying the dead address and slowly leaked memory. Aggregate memory alarms stayed quiet because storage servers use memory dynamically. Starting at 10:00 PDT, volumes in one zone degraded and then stuck in large numbers, and EBS's own failover logic accelerated the slide; nearly all were back by 16:15. AWS added alarms for that leak, moved to per-process memory monitoring, and planned resource limits for low-priority processes on storage hosts (AWS summary).
Trade-offs
| Option | Strengths | Weaknesses | Choose when |
|---|---|---|---|
| Local NVMe (instance store) | Lowest latency, highest IOPS, no network cost | Lost when the host dies or stops; no snapshots | Caches, scratch, replicated stores that rebuild from peers |
| Cloud network volume (EBS, PD) | Durable, detachable, snapshots, online resize | Higher latency; IOPS and throughput caps; single AZ | Most single-node databases and VM boot disks |
| SAN (iSCSI, FC, NVMe-oF) | Shared arrays, enterprise features, central management | Specialist network and team; array is a shared failure domain | On-premises virtualisation and databases |
| Distributed block (Ceph RBD) | Scale-out, self-healing, open source | Operational complexity; tail latency under recovery | Private clouds, Kubernetes on premises |
| File storage (NFS, EFS) | Many clients share files and directories | Weaker semantics for databases, higher latency | Shared content and home directories |
Pitfalls in production
- Assuming a completed write is durable. Disabling barriers, mounting with
nobarrier, or using a device with a volatile cache and no power-loss protection loses acknowledged commits on power failure. Keep flushes on, and test with crash tools that cut power mid-write. - Provisioning IOPS but running at queue depth 1. A single synchronous writer at 1 ms latency gets 1,000 IOPS from a 16,000 IOPS volume. Measure latency and queue depth, then add parallelism or group commit before paying for more IOPS.
- Restored volumes that start cold. Snapshots restore lazily, so the first query storm after a failover reads from object storage. Pre-warm or use fast snapshot restore before promoting a restored replica.
- Multi-volume snapshots taken separately. Data and WAL volumes captured at different moments do not restore cleanly. Use crash-consistent multi-volume snapshots.
- Treating a volume as zone-proof. A network volume lives in one availability zone. Replicate the database across zones, or copy snapshots elsewhere, instead of relying on the volume to survive a zone outage.
Leadership lens
- Ask for each stateful service: what happens to its data if this host disappears now, and how many minutes until it serves again? The answer decides local NVMe versus network volumes.
- Storage cost hides in three places: provisioned IOPS, snapshot retention, and over-sized volumes bought for performance. Review all three quarterly.
- Restore drills are the real test of a snapshot policy. Measure time to a warm, serving replica, not time for the API to return.
Check yourself
A gp3 volume is provisioned for 10,000 IOPS, but a single-threaded loader sees 1,200. Why?
Show answer
At queue depth 1, IOPS is capped by latency: about 0.8 ms per I/O gives roughly 1,200 per second. More parallel I/O, not more provisioned IOPS, is the fix.
Why does deleting a week-old snapshot often free less space than its size suggests?
Show answer
Snapshots share unchanged blocks. Only blocks referenced by no other snapshot or by the live volume are freed.
Why does Postgres write full page images to the WAL after each checkpoint?
Show answer
An 8 KiB page spans two 4 KiB blocks and can be torn by a crash. The full image in the WAL lets recovery restore a whole page before replaying changes.
Sources and further study
Primary
- pwritev2(2): RWF_ATOMIC: the Linux contract for untorn writes, with its alignment and size rules.
- NVM Express: what makes NVMe efficient: queue counts and depths from the standards body.
Systems docs
- EBS: torn write prevention block sizes: which writes EBS and instance store make atomic.
- EBS: initialize volumes: why restored volumes start slow and the three ways to fix it.
- Ceph: storage devices and BlueStore: how an OSD lays data on a raw device, and FileStore's retirement.
- MySQL: doublewrite buffer: the database side of torn-page protection.
Books
- Systems Performance (2nd ed.), Brendan Gregg, Ch 9 "Disks": queueing, latency, IOPS and how to measure a block device.
- Understanding Distributed Systems (2nd ed.), Roberto Vitillo, chapter "File storage": how cloud storage layers block, file and object services.
Other curricula
- Azure Architecture Center: choose a storage service: frames block storage as managed disks for single VMs versus Elastic SAN for pooled, shared iSCSI volumes.
- donnemartin/system-design-primer: does not cover block storage; it only lists GFS and HDFS among real-world architectures.
Watch
- AWS re:Invent 2023: Behind the scenes of Amazon EBS innovation and operational excellence (AWS Events): how EBS evolved its storage servers, network transport and operations over 15 years.
- AWS re:Invent 2021: Amazon EBS, a tech deep dive (AWS Events): volume types, performance limits and how to size volumes for databases.
- Understanding the Differences Between File, Block, and Object Storage (45Drives): a practical comparison of the three storage models.
Free resources
- Amazon EBS volume types: the current IOPS, throughput, size and durability numbers for each volume type.
- Amazon EBS snapshots: how incremental snapshots share blocks and what deleting one frees.
- Millions of Tiny Databases (NSDI 2020): the Physalia paper on how EBS stores volume configuration so failures stay contained.
- Ceph block device (RBD): an open-source distributed block store with striping, snapshots and clones.
- Linux device-mapper thin provisioning: a real refcounted block map with snapshots in the kernel.
- Linux multi-queue block layer (blk-mq): how Linux maps per-CPU queues onto device hardware queues.