01

Indexes in Messaging Systems

To quickly retrieve a message from disk, we need a mapping of message identifiers to their start positions in the log file.

This concept mirrors how databases use indices to speed up data retrieval.

02

The Book Index Analogy

Think of an index in a book: topics are listed alphabetically, with references to the pages where they appear.

Without an index, finding a topic requires scanning the entire book.

Databases use the same principle to locate data efficiently.

03

Database Index Behavior

Suppose a table contains employee last names.

Without an index, the database must scan every row to find a specific last name.

As the table grows, sequential scanning becomes slower.

With an index on the last name column, the database can directly jump to the correct data location.

This drastically reduces search time compared to full table scans.

04

Index Implementation Options

For a messaging system, a hash table could store message identifiers as keys.

The value would be the segment name and message position.

Alternatively, a hash table could be created per segment file.

Each hash table uses the message identifier as a key and the message position as a value.

05

Per-Segment Index Advantages

The per-segment hash table approach offers better memory control.

It avoids storing one large hash table in memory.

Instead, only small hash tables are loaded when needed.

Segments are deleted over time, allowing corresponding indices to be removed.

06

Challenge: Hash Table Selection

The main issue is identifying which hash table contains a given message identifier.

One solution: iterate through all hash tables in order of recency.

First, check the most recent segment.

If the message identifier is not found, check the second most recent segment.

Continue this process sequentially.

Because messages are frequently deleted upon consumption, the number of segments remains small.

07

Range-Based Index for Efficiency

Introduce a secondary index that lists message identifiers per segment.

This works well when message identifiers are sequential.

For each segment, store the first and last message identifier it holds.

08

Message Retrieval Algorithm

  1. Perform a binary search on the range index to locate the segment containing the target message.
  2. Use the segment’s index to find the message position within that segment.
  3. Retrieve the message bytes from the log file.
09

Real-World Implementation

This approach is used by Apache Kafka to store and retrieve messages.

It demonstrates practical application of indexing in distributed systems.

10

Core Design Constraint

We previously established that data must be stored on disk to prevent loss.

Memory cannot be relied upon for persistence.

The indexing system must therefore ensure durability and recoverability.

The per-segment index design supports both efficiency and resilience.

It enables fast retrieval while maintaining data integrity across restarts.

The range index reduces the number of segments to check during retrieval.

This design choice balances performance and memory usage.

It directly addresses the need for scalable, reliable message access.

The structure supports both high-throughput reads and long-term data retention.

The system remains efficient even as message volumes grow.

The indexing strategy is foundational to the system’s performance.

It enables rapid access without sacrificing storage or durability.

11

Index Vulnerability in Memory

Storing indexes in memory does not introduce new risks of data loss. The system remains resilient because indexes are not standalone data stores.

12

Index Reconstruction from Original Data

Indexes can always be rebuilt from the original dataset. This means that even if the index is lost or corrupted, the full data set provides a source for reconstruction.

13

Index Reconstruction from Log Files

In addition to original data, indexes can be recreated from log files. These logs record all data changes over time, enabling accurate index rebuilds without relying on memory.

14

Mitigating Slow Index Recreation

If the process of rebuilding an index is expected to be slow or complex, performance can be improved by storing index components on disk.

15

Disk-Based Index Storage

Systems typically store full indexes or their parts on disk. This allows for faster access during recovery and reduces the time needed to reconstruct indexes after failure.

16

System Practice

The approach of storing index parts on disk is standard in real-world systems. It balances performance and data safety by avoiding reliance solely on volatile memory.

This design ensures that index loss does not compromise overall data integrity, because both original data and logs serve as recovery sources.

Questions

  • Does the per-segment index approach require iterating over all segment indexes to find a message identifier?
  • How can we efficiently identify which segment contains a given message ID without scanning all segments?
  • What is the role of the range index in the message retrieval process?
  • Could the memory-based index be a source of data loss, and if so, how is that mitigated?
  • Why might a single global hash table be less efficient than per-segment hash tables?
  • Is it possible to store index data on disk, and if so, what are the implications?
  • How does the retrieval algorithm use binary search to locate a message?
  • What happens when messages are deleted and segments are removed?

Key takeaways

  • An index maps message identifiers to positions in log files, similar to how databases use indices for fast lookups.
  • A per-segment index reduces memory usage by avoiding a single large hash table.
  • Segments are deleted over time, and their indexes can be removed alongside them.
  • A range index stores first and last message IDs per segment, enabling binary search to locate the correct segment.
  • Message retrieval uses binary search to find the segment, then a lookup in that segment’s index to get the message position.
  • Indexes can be recreated from log files, reducing vulnerability to data loss.
  • Index data can be stored on disk to avoid complete memory dependency.
  • The system design mirrors Apache Kafka’s actual implementation, showing real-world applicability.
  • The reliance on memory-based indexes is not a fatal flaw due to the ability to rebuild them from original data.