RocksDB & Pebble

Data Structures & Storage intermediate Building with AI 11 min read

Overview

RocksDB and Pebble are embedded key-value storage engines built on the LSM-Tree architecture. They are not standalone databases — they are libraries that other databases embed to handle low-level data persistence. RocksDB, developed at Facebook (now Meta), is written in C++ and has become the de facto standard embedded storage engine. Pebble, developed by Cockroach Labs in Go, was purpose-built to replace RocksDB in CockroachDB with improved performance and maintainability.

For AI engineers, these engines matter because they sit beneath many of the systems you interact with daily. Vector databases like Weaviate embed custom storage engines inspired by RocksDB. Distributed databases like CockroachDB (powered by Pebble) and TiKV (powered by RocksDB) store the metadata, inverted indexes, and even raw vectors that drive retrieval pipelines. Understanding these engines helps you tune performance, diagnose bottlenecks, and make informed infrastructure decisions.

The relationship between RocksDB and Pebble is evolutionary — Pebble inherits RocksDB’s file formats and core architecture while introducing optimizations specifically for high-concurrency, distributed database workloads. Choosing between them often comes down to your language ecosystem and the specific performance characteristics you need.

How It Works

RocksDB Architecture

RocksDB is a fork of Google’s LevelDB, significantly enhanced for production workloads. It implements the full LSM-Tree stack: Write-Ahead Log (WAL), memtable, SSTable flushing, and multi-level compaction. Where LevelDB was designed for simplicity, RocksDB adds features critical for real-world deployment:

Key Concept: Column Families

Column families allow multiple independent key-value spaces within a single RocksDB instance, each with its own memtable and SSTable configuration. They share a single WAL for atomic cross-family writes. This enables, for example, storing vector metadata with aggressive compaction while keeping raw embeddings in a write-optimized family.

RocksDB API Basics

RocksDB provides a straightforward key-value interface. All keys and values are arbitrary byte arrays:

// C++ RocksDB basic operations
#include "rocksdb/db.h"

rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
options.write_buffer_size = 64 * 1024 * 1024;  // 64MB memtable

rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/db", &db);

// Write
db->Put(rocksdb::WriteOptions(), "embedding_001", vector_bytes);

// Read
std::string value;
db->Get(rocksdb::ReadOptions(), "embedding_001", &value);

// Range scan
auto* it = db->NewIterator(rocksdb::ReadOptions());
for (it->Seek("embedding_"); it->Valid() && it->key().starts_with("embedding_"); it->Next()) {
    process(it->key(), it->value());
}

// Batch write (atomic)
rocksdb::WriteBatch batch;
batch.Put("key1", "val1");
batch.Put("key2", "val2");
batch.Delete("key3");
db->Write(rocksdb::WriteOptions(), &batch);

Pebble Architecture

Pebble is a from-scratch Go implementation that mirrors RocksDB’s architecture but makes targeted improvements:

Key Concept: Cgo Boundary Cost

When Go programs call C libraries (via Cgo), each call crosses a language boundary that costs ~100-200 nanoseconds of overhead. For a storage engine handling millions of operations per second, this adds up to significant latency. Pebble eliminates this by being pure Go, which also simplifies debugging, profiling, and cross-compilation.

Pebble API

// Go Pebble basic operations
import "github.com/cockroachdb/pebble"

db, err := pebble.Open("/path/to/db", &pebble.Options{
    MemTableSize:                64 * 1024 * 1024, // 64MB memtable
    L0CompactionThreshold:       4,
    L0StopWritesThreshold:       12,
})

// Write
err = db.Set([]byte("embedding_001"), vectorBytes, pebble.Sync)

// Read
value, closer, err := db.Get([]byte("embedding_001"))
defer closer.Close()

// Range scan
iter, _ := db.NewIter(&pebble.IterOptions{
    LowerBound: []byte("embedding_"),
    UpperBound: []byte("embedding_\xff"),
})
for iter.First(); iter.Valid(); iter.Next() {
    process(iter.Key(), iter.Value())
}
iter.Close()

// Batch write (atomic)
batch := db.NewBatch()
batch.Set([]byte("key1"), []byte("val1"), nil)
batch.Set([]byte("key2"), []byte("val2"), nil)
batch.Delete([]byte("key3"), nil)
batch.Commit(pebble.Sync)

File Format Compatibility

Pebble maintains bidirectional file format compatibility with RocksDB 6.2.1. This means a Pebble instance can open and read a database directory created by RocksDB, and vice versa. The shared formats include:

Performance Comparison

In CockroachDB’s benchmarks, Pebble showed measurable improvements over RocksDB:

Practical Applications

Vector Database Storage Layers

Many vector databases use RocksDB or RocksDB-inspired engines for their underlying storage. For example, Milvus uses RocksDB to store segment metadata and scalar fields alongside vector data. When you configure dataCoord.segment.maxSize in Milvus, you’re indirectly tuning the SSTable flush behavior of the underlying RocksDB instance.

Embedding Cache

Computing embeddings is expensive ($0.0001 per 1K tokens for OpenAI’s text-embedding-3-small). A common pattern is to cache computed embeddings in RocksDB keyed by a hash of the input text. On subsequent requests, the cache is checked first, avoiding redundant API calls. RocksDB’s efficient point lookups (sub-microsecond with bloom filters) make this nearly free.

Distributed AI Infrastructure

CockroachDB (Pebble) and TiKV (RocksDB) serve as the metadata and coordination layers for distributed AI systems. When you deploy a multi-node vector search cluster, the consensus layer (Raft) and distributed transaction layer rely on these engines for local state persistence. Understanding their tuning parameters helps you optimize for your workload’s read/write ratio.

Feature Stores

Online feature stores for ML inference (like Feast’s online store) use RocksDB to serve precomputed features with sub-millisecond latency. When a model needs the latest user features for real-time inference, RocksDB’s block cache and bloom filters ensure the lookup completes in microseconds rather than milliseconds.

Key Takeaways

Further Reading