System designby Learnastra

Concept lesson · Foundations

Storage engines and data models

By Anup Rai

Start here

Definition

A data model defines how an application represents and addresses records. A storage engine implements how those records and indexes are organized in memory and on disk, updated, and recovered after failure.

Why it matters: The same logical write can create very different disk, memory, and background-maintenance work depending on the engine.

The visual modelB+ tree and LSM tree write paths

B+ trees update indexed pages. LSM engines append and merge immutable sorted runs; read and write amplification trade off.

B+ tree and LSM tree write pathsB+ trees update indexed pages. LSM engines append and merge immutable sorted runs; read and write amplification trade off. A B+ tree routes through separator keys to a leaf page. WAL requires recovery records before dirty data pages reach durable storage; this example also flushes the commit record before acknowledging a durable transaction. An LSM write records a WAL entry and updates a memtable, which later flushes to a sorted run. Reads merge visible versions from memory and runs. Compaction rewrites runs and removes obsolete entries when safe. Keep a tombstone until older data cannot resurrect, accounting for replicas and retained snapshots as well as local files.Update message 42 from v1 to v2B+ TREEWAL before page flushmessage 42 = v2separators 20 / 50< 2021,35,42,4950+LSM TREEWAL + memtable: message 42 = v2new sorted run: message 42 = v2older sorted run: message 42 = v1compaction keeps visible v2WAL supports recovery; page/run layout affects access cost. Compaction consumes I/O.
Read the diagram step by step
  1. A B+ tree routes through separator keys to a leaf page. WAL requires recovery records before dirty data pages reach durable storage; this example also flushes the commit record before acknowledging a durable transaction.
  2. An LSM write records a WAL entry and updates a memtable, which later flushes to a sorted run.
  3. Reads merge visible versions from memory and runs. Compaction rewrites runs and removes obsolete entries when safe.
  4. Keep a tombstone until older data cannot resurrect, accounting for replicas and retained snapshots as well as local files.

Worked example

Message 42 changes from “Train at five” to “Train at six.” A B-tree updates relevant pages; an LSM can retain the old file and place version 2 in a memory table and later a new sorted file.

Key takeaways

You will learn to

  • Separate an application’s logical data model from the engine’s physical layout.
  • Trace B-tree and LSM reads, writes, recovery, and deletion using actual keys.
  • Explain read, write, and space amplification before choosing an engine.

Practice in this chapter

8 interview questions with model answers and follow-ups.

Go to interview practice

Useful foundations: Database indexes: B-trees, composite keys and query access · Databases, data models, and ACID transactions

Workload and timing examples are interview assumptions.

01Data model versus storage engine

Choose the logical key independently of the storage engine. A message record can be (room_id, sequence, author_id, body, version). Fetching the latest fifty messages in one room favors an ordered key beginning with room and sequence. For example, a request updates message 42 in room R7 from “Train at five” to “Train at six” and deletes message 8, whose old value is “Hello.”

One machine can store this correctly. It becomes slow when the active data no longer fits memory or disk work exceeds capacity. Before adding shards, understand which physical work each logical write creates. A write-heavy service can saturate its storage while the incoming request count appears modest.

02B-trees and B+ trees: ordered page lookup

A B-tree keeps keys ordered in a branching tree of pages. A page is a block that the engine reads or writes as a unit. Internal pages guide a search toward a child; leaf pages contain index entries, with the exact record layout depending on the engine. A B+ tree keeps record-bearing entries in leaves and supports walking adjacent leaves for ranges.

Concept in focusB-plus tree: routing pages and linked leaves

This schematic B+ tree stores record entries at the leaves. Internal separator keys guide the search; all leaves are the same distance from the root.

B-plus tree: routing pages and linked leavesThis schematic B+ tree stores record entries at the leaves. Internal separator keys guide the search; all leaves are the same distance from the root. The root separator 40 chooses one child page. At the internal page containing 60, key 50 selects the child below 60. The leaf containing 40 and 50 holds the matching key and record reference. All leaves have equal depth. Linked leaves support ranges in this B+ tree example.LOOKUP KEY 50Every rounded box is one page.40ROOT: separator20INTERNAL page60INTERNAL page5 | 12LEAF: key + ref20 | 30LEAF: key + ref40 | 50LEAF: key + ref60 | 75LEAF: key + refless than 4050 >= 4050 < 60Linked leaves support an ordered range scan.Balanced: every root-to-leaf path has two edges (three pages). Greenmarks the lookup path; blue horizontal arrows link leaves.

Remember: Seek through the hierarchy; scan across leaves.

Read the diagram
  1. The root separator 40 chooses one child page.
  2. At the internal page containing 60, key 50 selects the child below 60.
  3. The leaf containing 40 and 50 holds the matching key and record reference.
  4. All leaves have equal depth. Linked leaves support ranges in this B+ tree example.

Imagine the root’s separators for R7 are message 20 and message 50. Looking up 42 follows the middle child to a leaf containing 21, 35, 42 and 49. If that index entry points to a separately stored row, fetching the message body is additional work. A latest-fifty query can seek near the end of R7’s range and walk backward through ordered entries.

Changing 42 updates the relevant data and index structures rather than scanning every message. A full leaf may split, requiring parent changes. Cached upper pages reduce physical reads, but cache misses, page splits, transaction versions, and recovery logging still matter. “Logarithmic lookup” describes growth; it does not specify a fixed number of disk operations for every product.

03Write-ahead logging: recovery and acknowledgment

A write-ahead log, or WAL, makes the recovery records for a change durable before the corresponding changed data pages are written to durable storage. That is the write-ahead ordering rule: the log reaches durable storage first. After a crash, the engine can reconstruct committed state from durable records and its persisted files. The exact protocol varies; a log is a recovery mechanism, not automatically an application event stream.

Concept in focusWhy a committed write can survive an old data page

Read the top row before the crash, then the bottom row during recovery. This example assumes synchronous local durability.

Why a committed write can survive an old data pageRead the top row before the crash, then the bottom row during recovery. This example assumes synchronous local durability. Recover x = 9 from the persisted log when the data page still says x = 8. The WAL record becomes durable before the commit reply. A crash occurs before the changed page is flushed. Recovery replays the durable log to reconstruct the required state.Commit x = 9; crash before the data page is flushedWAL: x = 9Commit replyCrash1. log persisted2. success3. page still x = 8Disk page: x = 8Replay WALPage: x = 9Recovery can redo the change because its log record survived.Synchronous local commit shown; replica waits depend on policy.

Remember: Log first; recovery can redo a page update later.

Read the diagram
  1. Recover x = 9 from the persisted log when the data page still says x = 8.
  2. The WAL record becomes durable before the commit reply.
  3. A crash occurs before the changed page is flushed.
  4. Recovery replays the durable log to reconstruct the required state.
Try from memoryWhat makes x = 9 recoverable when the page still contains 8?

The recovery record is durable before success. Recovery can redo the committed change from WAL.

Assume the database acknowledges an edit only after its required recovery and commit records are durable under the configured local storage policy. At time 0 it logs message 42 version 2. At time 1 it acknowledges the edit. If the process crashes before the ordinary data page is flushed, recovery can replay the relevant durable information. If the service instead acknowledges only an in-memory buffer, the same crash may lose the edit.

State which failures each storage stage can survive:

Acknowledged bytes have reached Failure they can survive under the stated assumptions Remaining risk
Only a process buffer No guarantee after that process dies Buffered records may vanish
Operating-system cache A process crash if the OS and its buffered bytes survive Reboot or power loss can lose unsynchronized data
Synchronized recovery log on durable media Process or machine restart with that media intact Device loss or a storage stack that violates synchronization
Required remote durable replicas too The failures covered by the replica placement and commit protocol Correlated loss beyond that failure model

Synchronization asks the storage stack to persist the necessary bytes; it does not make one local device indestructible. Group commit lets several transactions share one synchronization operation. This can improve throughput, but a transaction may wait for the group before receiving its acknowledgment.

Worked example diagramAn LSM update first lives in the recovery log and memory table. Flushing and compaction reorganize it without changing the logical message value.
Storage engines and data models: architecture diagram1. Update message 42 to 2. Durable WAL record: log under chosen policy; 2. Durable WAL record to 3. Memory table: 42 v2: apply; 3. Memory table: 42 v2 to 4. Flush sorted file: flush; 4. Flush sorted file to 6. Compaction retains needed versions: merge; 5. Older file: 42 v1 to 6. Compaction retains needed versions: compare versions1 → 2: log under chosen policy2 → 3: apply3 → 4: flush4 → 6: merge5 → 6: compare versions01Update message 4202Durable WAL record03Memory table: 42 v204Flush sorted file05Older file: 42 v106Compaction retainsneeded versions
  1. 1 → 2log under chosen policyUpdate message 42 → Durable WAL record
  2. 2 → 3applyDurable WAL record → Memory table: 42 v2
  3. 3 → 4flushMemory table: 42 v2 → Flush sorted file
  4. 4 → 6mergeFlush sorted file → Compaction retains needed versions
  5. 5 → 6compare versionsOlder file: 42 v1 → Compaction retains needed versions

04LSM trees: memory tables and immutable sorted files

A log-structured merge tree, abbreviated LSM, accumulates updates in a memory table and writes sorted immutable files as buffers fill. The WAL protects updates that have not yet become durable table files under the chosen configuration. Immutable means a later edit is stored as another version rather than rewriting that old file in place.

Concept in focusCompaction chooses among stored versions

Two sorted files contain different versions of A. This example assumes no snapshot needs the old version.

Compaction chooses among stored versionsTwo sorted files contain different versions of A. This example assumes no snapshot needs the old version. Follow the two copies of A into one merged output. New file: A = 9 and C = 3. Old file: A = 8 and B = 2. Merged output: A = 9, B = 2, C = 3. A = 8 is no longer required here.Merge versions; keep the newest value for each keyNew fileA = 9 | C = 3newerOld fileA = 8 | B = 2olderCompactA = 9 | B = 2 | C = 3A = 8 is obsolete here. A snapshot that needs it would change this decision.

Remember: Merge keys; resolve versions; retain anything still required.

Read the diagram
  1. Follow the two copies of A into one merged output.
  2. New file: A = 9 and C = 3. Old file: A = 8 and B = 2.
  3. Merged output: A = 9, B = 2, C = 3. A = 8 is no longer required here.
Try from memoryWhy does A = 8 disappear, but B = 2 remain?

A has a newer value, 9, and no required snapshot needs 8 in this example. B has no replacement, so it remains.

Location after the update and deletion Entries for R7 Meaning
Older sorted file F1 8 v1 = Hello; 42 v1 = Train at five Earlier stored values
Newer memory table 8 v2 = deletion marker; 42 v2 = Train at six Latest changes
New file F2 after flush Same newer entries, sorted by key Memory can be reclaimed when safe

A read of message 42 must select the newest visible version according to the engine’s ordering and snapshot rules. It cannot stop at v1 merely because F1 was convenient to open. A read of message 8 encounters a deletion marker, often called a tombstone, which suppresses its older value. Range reads merge ordered streams from relevant files. They are supported, but their cost depends on how many streams and obsolete versions must be considered.

05Compaction, tombstones, and amplification

Cost Plain definition Example consequence
Read amplification Extra data or storage operations needed for one logical read Several candidate files for message 42
Write amplification Physical bytes written per logical byte ingested Rewriting retained records during compaction
Space amplification Physical storage relative to live logical data Old versions and temporary compaction outputs

Assume an illustrative workload ingests 100 MB/s and the measured total local write amplification, including the log in this measurement, is 8. The device must sustain about 800 MB/s of writes, before adding other workloads or safety margin. This is arithmetic from assumed inputs, not a hardware guarantee. Compaction also consumes read bandwidth and CPU. Deferring it forever makes later reads and space usage worse.

Two common compaction policies move that cost differently. Leveled compaction limits overlap within deeper levels, usually reducing read and space amplification but rewriting overlapping data. Tiered compaction accumulates several sorted runs before merging them, often reducing write amplification while increasing read sources and temporary space. These are tendencies, not universal benchmark results: key order, skew, overwrite rate and tuning matter.

06Storage-engine comparison and row versus column layouts

Two different physical choices are being compared. B-trees and LSM trees organize key lookup and update work. Row-oriented and column-oriented layouts determine whether fields of one record or values of one field are stored together. These choices can be combined; select them from whether the workload fetches individual messages, scans room ranges, or analyzes a few fields across many messages.

Physical approach How it handles work Useful starting point Cost to measure
B-tree/B+ tree Seek through ordered pages; update affected structures Point lookups and ordered ranges Cache misses, page changes/splits, logging, and version cleanup
LSM tree Buffer updates; flush and merge immutable sorted files Sustained writes with an ordered-key design Compaction, multiple read sources, obsolete versions, and temporary space
Row-oriented layout Keep one record's fields together Fetch a message and its metadata Scans of a few columns may read unnecessary fields
Column-oriented analytical layout Group values by column Scan selected fields across many records Reconstructing or updating individual records can cost more
Concept in focusWhere are the bytes needed for SUM(total)?

Green cells are totals. The first layout groups each person’s fields; the second groups each field’s values.

Where are the bytes needed for SUM(total)?Green cells are totals. The first layout groups each person’s fields; the second groups each field’s values. Locate the same three totals in row-oriented and column-oriented storage. The example records are (1, Ada, 20), (2, Bo, 30), (3, Cy, 40). A column layout stores 20, 30 and 40 together; a row layout places each with its other fields.Same records, two physical layoutsRows: all fields of one record together1Ada202Bo303Cy40Columns: one field from many records together123AdaBoCy203040SUM(total) needs the green values: scattered fields versus one column.

Remember: Whole row: fields together. Column scan: one field together.

Read the diagram
  1. Locate the same three totals in row-oriented and column-oriented storage.
  2. The example records are (1, Ada, 20), (2, Bo, 30), (3, Cy, 40).
  3. A column layout stores 20, 30 and 40 together; a row layout places each with its other fields.
Try from memoryWhich layout groups the bytes needed for SUM(total)?

The column layout groups 20, 30 and 40. The row layout stores each total beside that record’s other fields.

For an assumed room-history workload dominated by appends and bounded room-range reads, I would evaluate an LSM-backed ordered store. The key (room, sequence) makes the common range explicit. I would benchmark it against an indexed relational design before assuming its extra operational complexity is worthwhile. The choice depends on latency targets, transactional requirements, updates, retention and operating experience.

A key-value API does not remove the need to design keys. Hashing every entire message key across shards scatters a room’s range; partitioning by room preserves locality but creates a hot partition for a huge room. Time buckets or subpartitions can bound growth at the cost of merging reads. Physical engine selection does not solve those ownership decisions.

Row-oriented storage places a record’s fields together, useful when fetching a message. Column-oriented analytical storage groups values by column, useful when scanning a few fields across many records. A wide-column database’s data model is not synonymous with a columnar analytics layout. Ask which query the layout accelerates rather than matching names.

A practical baseline is PostgreSQL with an ordered B-tree index for transactional room history. Evaluate RocksDB when the application needs an embedded ordered key-value engine and can own the surrounding service protocol; RocksDB alone is not a replicated database service. Its write options distinguish asynchronous WAL writes from synchronized writes. If an acknowledged edit must survive machine restart, verify that WAL is enabled and the required synchronization policy is applied rather than assuming the default write call provides it.

07Storage failure, recovery, and benchmarking

After a crash, check that every acknowledged change covered by the durability policy survived, including the new value of message 42 and the deletion of message 8. A deleted message disappearing from ordinary reads does not prove its bytes vanished from snapshots, old files, replicas or backups; physical erasure follows a separate retention and cleanup policy.

In an interview I would say: “The key supports room-history reads. An LSM may suit frequent appends, but edits and deletion markers leave versions that reads and compaction must resolve. I will state which failures saved messages survive, budget the extra reads, writes and disk space, and test range reads while background maintenance runs.”

Practise the interview questions

Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.

Foundation · Question 1

What is a storage engine, and how is it different from a data model?

Reveal a model answer

The data model describes records and access semantics, such as messages keyed by room and sequence. The engine organizes their bytes and indexes and performs updates and recovery. B-trees and LSM trees are engine techniques; relational tables and documents are logical models. Choosing SQL does not by itself select a B-tree or define its disk cost.

What the answer must demonstrate: Distinguish the logical interface from physical organization.

Applied · Question 2

A B-tree has separators 20 and 50; its middle leaf contains 21, 35, 42, 49. Explain lookup for key 42.

Reveal a model answer

“The root separators guide me to the relevant leaf range, where I find 42’s index entry. Depending on the layout, that entry contains the needed data or points to a separate row. Cached pages can avoid disk reads.”

What the answer must demonstrate: Distinguish logical search steps from physical I/O.

Applied · Question 3

An update is acknowledged before its changed data page reaches disk. Under what WAL policy can it survive a process crash?

Reveal a model answer

It can survive when the required recovery records, including the commit decision, were made durable before acknowledgment and recovery correctly replays them. Log-before-data ordering alone does not prove commit-before-ack durability. I must verify the configured synchronization policy and failure model.

What the answer must demonstrate: Name the acknowledgment boundary and failure model.

Foundation · Question 4

Why can an LSM contain two values for message 42?

Reveal a model answer

“The old sorted file cannot be changed. An edit first enters a newer memory table and later another file. Reads use the engine’s sequence and snapshot rules to choose the right version. Compaction removes old versions once they are no longer needed.”

What the answer must demonstrate: Explain version visibility, not just file count.

Follow-up · Question 5

An LSM contains a tombstone for key 8 and older files may contain key 8’s value. When may the tombstone be removed?

Reveal a model answer

“Only when the engine can prove older values cannot reappear for supported reads and no required snapshot needs that history. Removing the marker merely because it is old can expose an older stored copy.”

What the answer must demonstrate: Logical deletion, compaction and physical erasure differ.

Applied · Question 6

What does write amplification of 8 mean at 100 MB/s ingestion?

Reveal a model answer

“With a measurement that includes all the relevant local writes, it implies roughly 800 MB/s of device writes. I would also budget compaction reads, CPU, replication and headroom, and verify the figure under a steady workload.”

What the answer must demonstrate: Define the measurement before multiplying it.

Applied · Question 7

Why does an ordered engine not automatically give fast room history?

Reveal a model answer

“The logical key and partitioning still matter. If each full message key is independently hashed to a different shard, a room query fans out. Keeping room and sequence together gives locality but may create a hot room partition.”

What the answer must demonstrate: Connect query shape to both ordering and partitioning.

Follow-up · Question 8

How would you test the engine choice?

Reveal a model answer

“I would load representative data, sustain ingestion until compaction reaches normal behavior, and measure tail latency for latest-fifty reads, edits, deletions and recovery. An empty database’s short insert burst hides the deferred maintenance cost.”

What the answer must demonstrate: Evaluate steady-state operation, not only peak foreground throughput.

Blank-page exercise · 16 minutes

Build the answer yourself

Design storage for room R7 history: append messages, fetch the latest fifty, edit one message and delete another. Draw where two versions and a deletion marker exist before and after compaction.

  • Specify the logical record, partitioning boundary and ordered key.
  • Show which records are durably stored before the write is acknowledged and how recovery uses them after a crash.
  • Explain how a read selects the newest visible value across files.
  • Budget compaction, snapshots and recovery instead of counting only live payload bytes.

Check that each component and design decision follows from your requirements and workload.

Recall the key ideas

Answer from memory before opening each card. Explain why the choice works and what it costs. Revisit missed cards tomorrow.

Storage engines and data modelsWhat is the difference between model and engine?Recall first, then reveal

The model defines records and access semantics; the engine defines physical pages, files, logs and update behavior.

Meaning above; mechanics below

Return to lesson
Storage engines and data modelsWhy does a tombstone exist?Recall first, then reveal

It records deletion so an older value in another file does not become visible again.

A delete must outlive the old copy

Return to lesson
Storage engines and data modelsIs a buffered append free of later work?Recall first, then reveal

No. Flushing and compaction convert fast foreground writes into later I/O, CPU and space costs.

Append now, organize later

Return to lesson
Storage engines and data modelsDoes WAL imply survival of disk loss?Recall first, then reveal

No. Local recovery logging and off-machine redundancy cover different failures.

Log repairs a crash; copies cover loss

Return to lesson

Final revision

Summary and interview notes

Choose a logical key that serves the query, then choose an engine and durability policy that can maintain it within the workload budget. B-trees and LSM trees move work differently; neither removes the need to account for versions, background maintenance, recovery and partitioning.

Remember these points

  • Logical SQL/document/key-value models are distinct from physical B-tree, LSM, row and column layouts.
  • Persist recovery information in the log before the corresponding data pages reach disk. To promise crash recovery, also persist the required commit information before reporting success.
  • An LSM read chooses the visible version using values and deletion markers in memory and relevant sorted files.
  • Compaction exchanges foreground speed for later reads, rewrites and temporary space; benchmark steady state.
  • A tombstone may be dropped only when old values cannot reappear for supported reads and retained snapshots.

Interview tips

Important qualifications

  • RocksDB is an embedded engine; replication, failover and application transaction ownership need a surrounding system.
  • Logical deletion is not proof of physical erasure from old files, snapshots or backups.

Technical references

  • RocksDB OverviewVerified implementation reference for memory tables, sorted files, point reads, and range traversal.
  • PostgreSQL: Write-Ahead LoggingOfficial explanation of log-before-data ordering, acknowledgment, and crash recovery; the lesson separately identifies LSM-specific memory-table flushing.
  • RocksDB: CompactionVerified reference for sorted-run organization and amplification tradeoffs.
  • PostgreSQL: B-Tree IndexesOfficial reference for ordered B-tree indexing. The tiny page and throughput examples are illustrative, not engine benchmarks.
  • RocksDB: Basic OperationsChecked synchronous/non-synchronous writes, OS-buffer boundary and disableWAL behavior; durability remains configuration dependent.

Practice marks stay in this browser.