An SSD accepts 4 KB writes to any LBA, forever, like a very fast disk. The physics underneath permits none of that: NAND flash cannot overwrite a written page — it must be erased first — and erasure only happens in blocks of hundreds of pages, each surviving a finite number of erase cycles. Between the interface and the physics sits a full embedded computer (multi-core controller, DRAM, firmware) running the flash translation layer, and every strange SSD behavior — the performance cliff when full, the need for TRIM, drives dying by warranty math — is FTL bookkeeping showing through.
The Constraint Set
read: per page (~4-16 KB) fast (~50-100 µs)
write: per page, blank only slower (~200+ µs... and see below)
erase: per BLOCK (~256+ pages) slow (~ms), and each block endures
only ~1-3k cycles (TLC/QLC era)Overwrite-in-place under these rules would mean: read the whole block, erase it (milliseconds), write it all back — and burn one of your few thousand cycles per 4 KB update. No.
The FTL’s Answer: Never Overwrite, Always Remap
The FTL keeps a mapping table (LBA → physical page, gigabytes of DRAM on big drives) and turns every write into an append: incoming data goes to a fresh page in a currently-open block, the map is updated, and the old page is merely marked stale. Sound familiar? Your SSD is an LSM-ish log-structured store, and like every such design it owes a garbage-collection debt: eventually the drive must reclaim stale pages by picking victim blocks, copying their still-live pages elsewhere, and erasing. Those internal copies are writes you didn’t issue — write amplification (WA): host writes 1 GB, NAND absorbs 2–4 GB, endurance and performance both divide by that factor.
WA is workload-shaped, and the shape rules are worth memorizing: sequential writes fill blocks that die together (WA→1); small random writes across a full drive scatter live/stale pages evenly so every victim block is half-alive (WA→high); and free space is the GC’s working room — which is the real explanation of the famous cliff. A drive at 50% full finds nearly-dead victim blocks easily; at 95%, every collection copies mostly-live data to reclaim slivers. Steady- state random-write throughput can drop 3–10× between an empty and a full drive — enterprise drives ship 10–28% hidden over-provisioning precisely to floor this, and you can add more by simply leaving a partition short.
This is also why TRIM matters: without it, the FTL doesn’t know
deleted-file pages are dead (the filesystem just edited its own
metadata) and dutifully GC-copies garbage. fstrim.timer weekly is
the Linux default for a reason. And wear leveling is the FTL’s third
job: rotating erase load across blocks (including moving cold data
off healthy blocks so they can take heat), tracked publicly in SMART —
smartctl -a shows percentage-used/wear-level counters, and endurance
is sold as TBW/DWPD numbers that are just (cycles × capacity ÷ WA)
arithmetic.
The Performance Personality
Two more internals explain the benchmarks that confuse people.
SLC caching: TLC/QLC cells are slow to program, so consumer drives
write incoming data in fast 1-bit-per-cell mode into a dynamic cache
region, folding it to dense storage later — hence the pattern where a
drive writes at 5 GB/s for 30 seconds and then drops to 500 MB/s
(cache exhausted, now folding while ingesting). Sustained-write
workloads should be benchmarked past the cache. Parallelism is the
whole speed story: a big SSD is 8–16 channels × multiple dies, and
peak IOPS exist only at high queue depth (QD1 4K random read latency
~60–80 µs is physics; the million-IOPS spec sheet number is QD32+
across many jobs — fio with iodepth=1 vs 32 shows both truths).
Meanwhile NVMe removed the software bottleneck (64k queues, MSI-X per
queue, no SATA AHCI single-queue chokepoint), which is why the
protocol switch mattered as much as the flash.
The through-line for systems people: databases and filesystems built their own log-structured layers on top (WAL, LSM trees, F2FS), so a modern write path is often logs stacked on logs, each with its own GC — and the tuning literature (align writes, batch small writes, leave headroom, TRIM) is the same advice at every layer because it’s the same design underneath.
Takeaways
- Flash forbids overwrite and erases by block; the FTL converts your writes into an internal append-log with mapping + GC + wear leveling.
- Write amplification is the tax: sequential ≈1, small-random-when-full worst; endurance and steady-state speed both divide by it.
- Free space is GC headroom — the full-drive cliff is real; over- provision (or under-partition) and run fstrim.
- SLC caches make burst ≠ sustained; parallelism makes QD1 ≠ spec-sheet IOPS — benchmark the case you actually run.
- Your storage stack is logs-on-logs; the same batching/headroom advice applies at every layer because it’s the same architecture.