Write-Ahead Log & LSM Trees

11 min read

Reading Progress0%
System Design Index
Start Here
Tier 1 -- Building Blocks
Tier 2 -- Core Systems
URL Shortener — System Design InterviewFree
Pastebin — System Design InterviewFree
News Feed System — System Design InterviewFree
Chat System (WhatsApp/Messenger) — System Design InterviewFree
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
System Design Index
Start Here
Tier 1 -- Building Blocks
Tier 2 -- Core Systems
URL Shortener — System Design InterviewFree
Pastebin — System Design InterviewFree
News Feed System — System Design InterviewFree
Chat System (WhatsApp/Messenger) — System Design InterviewFree
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative

Write-Ahead Log & LSM Trees

Tier 1 — Building Block


1. What Is It?

Write-Ahead Log (): A is a sequential, append-only file that records every database write before applying it to the main data structure. "Write-ahead" means the log entry is durably written to disk before the operation is considered committed. On crash recovery, the database replays the WAL to restore any writes that were logged but not yet applied to the main files — guaranteeing (the D in ACID) without requiring every write to sync the entire database file.

(Log-Structured Merge-Tree): An is a write-optimized data structure that takes the WAL concept further — all writes are only appended to sequential files; reads are served from a merge of multiple sorted files. LSM trees convert random-write workloads (which are slow on disk) into sequential-write workloads (which are fast), achieving write 10–100× higher than B-trees for write-heavy workloads.

The core problem both solve: spinning disks (HDDs) are ~1000× slower for random writes than sequential writes. Even SSDs are 10–20× slower for random writes vs. sequential writes at sustained . Sequential, append-only writes are the fastest possible I/O pattern.


QUICK CHECK

A backend service handles a write-heavy workload where thousands of records are inserted per second. The engineering team is debating whether to use a B-tree-based storage engine or an LSM tree-based storage engine. What is the primary reason an LSM tree would offer significantly higher write throughput in this scenario?

Choose one answer

2. How It Works

Write-Ahead Log (WAL) Mechanics

On crash:

Recovery:
1. Load last consistent checkpoint (data file state)
2. Replay WAL from checkpoint LSN (log sequence number) onward
3. All logged writes are re-applied → database is consistent

is used by:

  • PostgreSQL: files in pg_wal/. Also used for streaming (replicas are WAL consumers).
  • MySQL InnoDB: Redo log (similar to WAL) + binary log (for ).
  • : The log is a WAL — every message is an append to a sequential file.
  • Raft/Paxos: Distributed protocols persist a WAL before committing entries.

B-Tree: The Write Problem

Traditional databases use B-trees. A B-tree is a balanced tree stored on disk; each node is a fixed-size page (a 4–16KB block of data — the smallest unit the disk reads or writes). An update to a row in the middle of the B-tree requires:

  1. Read the page from disk (random read)
  2. Modify the row in memory
  3. Write the page back to disk (random write to an arbitrary location)

Random writes to arbitrary disk locations are slow. At high write , the B-tree checkpoint (writing dirty pages to disk) becomes the bottleneck.

LSM Tree: The Write Solution

LSM trees replace the random-write B-tree update pattern with a pipeline of sequential writes:

SSTable (Sorted String Table): An immutable, sorted file on disk. Keys are sorted; values follow. A sparse index (every N-th key) enables binary search. Once written, never modified.

MemTable: An in-memory sorted data structure (red-black tree or skip list). All writes go here first. When it reaches ~64MB, it is flushed to disk as a new Level 0 SSTable.

: Background process that merges SSTables from lower levels into fewer, larger SSTables at higher levels. This is a k-way merge sort of sorted files — purely sequential reads and writes. :

  1. Removes deleted keys (tombstones — special markers written when a key is deleted, since you can't remove data from an immutable SSTable directly)
  2. Resolves duplicate keys (keeps the latest version)
  3. Merges small files into large files for efficient reads

Bloom Filter: A probabilistic data structure that answers "is key X in this SSTable?" with zero false negatives and a small false positive rate (~1%). Before reading any SSTable, check its Bloom filter — if it says "no," skip the file. This avoids reading files that don't contain the key, making reads much faster.

vs. :

B-TreeLSM Tree
Write pathRandom write to specific pageSequential append to MemTable, then SSTable
Write amplificationLow (each byte written once per checkpoint)High (compaction rewrites data multiple times: level 0 → 1 → 2 → ...)
Read pathOne B-tree lookup — O(log N)Check MemTable + multiple SSTables (mitigated by Bloom filters)
Read amplificationLow (1 pass)Higher (multiple SSTable checks, mitigated by Bloom filters)
Space amplificationLowHigher (space used by old versions during compaction)

QUICK CHECK

A high-throughput write-heavy backend service is experiencing bottlenecks when persisting data to disk. An engineer proposes switching from a B-tree-based storage engine to an LSM tree. Which trade-off should the engineer expect after making this change?

Choose one answer

3. Variants & Comparisons

Compaction Strategies

StrategyHow It WorksProsConsBest For
Size-Tiered (Cassandra default)Group SSTables of similar size; compact when you have N same-size filesHigher write throughput; less frequent compactionHigher space amplification (old + new files co-exist during compaction)Write-heavy; append-only workloads
Leveled (LevelDB, RocksDB default)Each level has a size limit; files at each level are non-overlapping; compact when level overflowsLower read amplification; lower space amplificationMore write amplification (more compaction work per byte)Read-heavy; random access patterns
FIFO (Redis streams)Oldest files deleted first to stay under space budgetZero write amplification; simpleNot suitable for random reads; data expiresTime-series / event log with TTL

Technologies Using LSM Trees

SystemCompactionNotes
RocksDB (Meta/Facebook)Leveled (default)Embedded key-value store. Used inside MySQL (MyRocks), MongoDB, CockroachDB, TiKV. Facebook uses it for their social graph. ~100K-500K writes/sec per instance.
Apache CassandraSize-Tiered or LeveledWide-column store built on LSM. Tuned for write-heavy workloads. Production deployments handle millions of writes/sec across the cluster.
LevelDB / RocksDB (Google → Meta)LeveledLevelDB is the original; RocksDB is Meta's fork with many production improvements (bloom filters per level, compression, WAL tuning).
Apache HBaseSize-Tiered (HFile)Wide-column store on Hadoop. Used by Facebook Messenger (original), Pinterest, Twitter.
Bigtable (Google)LeveledGoogle's proprietary LSM-based wide-column store; foundation for HBase design.

QUICK CHECK

Your team is building a product catalog service that handles far more reads than writes, and storage efficiency is a priority. Which LSM-tree compaction strategy would be the best fit, and why?

Choose one answer

4. When to Use It (and When NOT To)

Use LSM-Based Stores When:

  • Write is the primary constraint: LSM converts random writes to sequential — often 10–100× faster write than B-tree databases for sustained workloads.
  • Time-series / event log data: Append-only insert patterns are perfectly suited for LSM.
  • High cardinality key-value data: IoT sensor readings, user events, log records — each insert is a new key, rarely updated.
  • Large datasets with limited SSD budget: LSM's sequential I/O pattern is more efficient on SSD than random B-tree page writes.

Decision triggers:

  • "If write QPS is the bottleneck and data is append-mostly → use Cassandra or RocksDB"
  • "If you're storing time-series events (metrics, IoT, logs) → (Cassandra, InfluxDB TSM engine)"
  • "If you read the same keys repeatedly → B-tree (PostgreSQL/MySQL) is better due to lower "

Do NOT Use LSM When:

  • Read-heavy with random key access: LSM (multiple SSTable lookups) is worse than a B-tree's O(log N) single-pass lookup.
  • Strong ACID transactions with complex queries: B-tree databases (PostgreSQL) have decades of SQL optimization, JOIN support, and MVCC. LSM stores typically lack this.
  • Frequent updates to the same key: Each update adds a new version to the LSM; must eventually merge them. Many updates to the same key amplify work. B-trees do in-place updates more efficiently.

Anti-patterns:

  • Neglecting compaction: If compaction falls behind write throughput, read performance degrades severely (more SSTables to check per read). Monitor compaction throughput and pending bytes.
  • Ignoring tombstone accumulation: Deletes in LSM write a tombstone marker, not an actual deletion. Until compaction runs, tombstones accumulate — queries must scan past them. Heavy delete workloads can severely degrade performance.
  • No Bloom filters: Reading LSM without Bloom filters requires checking every SSTable for a miss. Always configure Bloom filters for read-heavy LSM workloads.

QUICK CHECK

A backend team is building a system that tracks real-time user activity events (page views, clicks, session starts) for millions of users. Each event is a new record with a unique timestamp-based key, and the system receives roughly 50,000 writes per second with far fewer reads. Which storage engine choice and reasoning is most appropriate?

Choose one answer

5. Real-World Usage

Facebook/Meta (RocksDB everywhere): Meta open-sourced RocksDB in 2013 as a fork of LevelDB optimized for SSD and high-concurrency workloads. Today RocksDB is used as the storage engine for: ZippyDB (Meta's distributed key-value store), MyRocks (MySQL with RocksDB storage engine — 2× compression vs. InnoDB for Meta's production MySQL), Logdevice (Meta's log storage system), and the TiKV key-value store inside TiDB. Meta runs millions of RocksDB instances globally.

Apache Cassandra (Facebook, Netflix, Uber): Cassandra's write path is a pure LSM implementation: CommitLog ( for ) → MemTable (in-memory) → SSTable (flushed to disk). Netflix uses Cassandra for viewing history (write-heavy: every view event is a write), storing trillions of events. Cassandra handles millions of writes/sec per cluster by virtue of LSM's sequential write pattern. Netflix stores 1+ trillion events in Cassandra clusters.

PostgreSQL for : PostgreSQL's WAL is not just for crash recovery — it's the foundation for streaming . Replicas are WAL consumers: the primary ships WAL segments to replicas in real time. This is why adding a PostgreSQL replica is easy (just point it at the primary's WAL stream) and why replicas are byte-identical to the primary. The WAL is the single source of truth for all state changes.


QUICK CHECK

A team is setting up a read replica for their PostgreSQL database. A junior engineer asks why adding a replica is relatively straightforward compared to other databases. What is the core reason PostgreSQL replication is easy to set up?

Choose one answer

6. Interview Cheat Sheet

Key sentences to demonstrate depth:

  1. " provides crash recovery by writing intent before action — on crash, replay the from the last checkpoint. It also enables : replicas are just WAL consumers receiving the same change stream."
  2. "LSM trees trade for — all writes are sequential appends, converting the random-write problem into a sequential-write problem, achieving 10–100× higher write than B-trees under sustained write load."
  3. "The MemTable → Level 0 SSTable → pipeline is the key mechanism: writes go to memory (fast), overflow to immutable sorted files, and background merges files — all sequential I/O."
  4. "Bloom filters are critical for LSM read performance — a small probabilistic structure that says 'this key is definitely NOT in this file' with zero false negatives, eliminating unnecessary SSTable reads."
  5. "Cassandra's LSM trade-off: it's an AP system built for write . Every Cassandra table design question starts with the query pattern, because LSM reads are efficient only if you hit the right partition — scatter-gather across partitions is expensive."

Common follow-up questions:

QuestionConcise Answer
"What is write amplification in LSM trees?"A single user write gets written multiple times: once to WAL, once to MemTable, once flushed to L0, then potentially rewritten by compaction as it moves from L0 → L1 → L2. Each compaction level rewrites the data. In leveled compaction, write amplification factor is typically 10–30×.
"What is read amplification in LSM trees?"For a key that doesn't exist, you must check MemTable + every SSTable at every level until you're sure it's not there. Bloom filters reduce but don't eliminate this. Read amplification can be 10+ without Bloom filters.
"How does Cassandra ensure durability?"Write goes to CommitLog (WAL, durable fsync) before MemTable. On crash, CommitLog is replayed. This is the same WAL pattern as PostgreSQL/MySQL.
"What's a tombstone in LSM and why is it a problem?"A delete operation writes a marker (tombstone) rather than removing data. The actual key removal happens during compaction. Until compaction, reads must scan past tombstones, degrading performance. Heavy deletes without regular compaction cause "tombstone accumulation" — queries that return small result sets but scan enormous tombstone sets.
"LSM vs. B-tree: which would you use for a rate limiter counter store?"B-tree (Redis or PostgreSQL): rate limiters have high update frequency to the same keys (INCR). LSM's compaction must merge many versions of the same key. B-trees do in-place updates more efficiently for this access pattern.

Connections to other building blocks:

  • (Read Replicas): WAL is the transport mechanism for PostgreSQL and MySQL streaming replication. Replicas replay the WAL from the primary.
  • Message Queues (): 's log storage is essentially a WAL — every message is appended sequentially. Kafka partitions are immutable append-only log segments, analogous to SSTables.
  • Cassandra / Wide-Column Store: Cassandra's entire write path is LSM. Understanding LSM is prerequisite to understanding Cassandra's performance characteristics (write-optimized, on non-partition-key queries).
  • : Cassandra distributes partitions across nodes using ; each node stores its partition's locally.
  • : RocksDB is typically embedded in each shard of a distributed database (CockroachDB, TiKV). Each shard is a self-contained .
Glossary History

Click dotted jargon to save explanations here.

Glossary History

Click dotted jargon to save explanations here.