RocksDB 是 Facebook(Meta)开源的、用 C++ 写的高性能嵌入式键值存储引擎。它像一个"超级加速版的文件柜"——你往里塞键值对,它能以极快的速度读写,并且把数据安全地落到磁盘上。

1. RocksDB 是什么?(三分钟建立直觉)

1.1 通俗类比

想象你有一本随身笔记本(内存)和一个大书柜(磁盘):

  • 普通方案:每次记东西都直接翻开书柜找位置写,慢且累;
  • RocksDB 方案:先飞快地写在随身笔记本上(内存),等笔记本写满了,再一次性整理誊抄到书柜里(磁盘),并且给书柜编好索引,下次要找直接翻目录。

这个"先写内存、再批量落盘"的思路,就是 RocksDB 的核心 —— LSM-Tree(Log-Structured Merge-Tree,日志结构合并树)。它把"随机写"变成"顺序写",而顺序写磁盘比随机写快几个数量级(机械硬盘可达 100 倍差距,SSD 也有数倍差距),这就是它高性能的秘密。

1.2 官方定义

RocksDB 是一个 嵌入式(Embedded)键值存储引擎

  • 键值存储:数据形态是 key -> value,类似一个超大的 std::map,但数据可以超过内存、持久化在磁盘;
  • 嵌入式:它不是一个独立运行的服务器进程(不像 MySQL/Redis 需要启动服务),而是作为库链接进你的程序,#include <rocksdb/db.h> 就能用。你的程序就是它的"宿主";
  • C++ 编写:核心 API 为 C++,同时也提供 Java(RocksJava)和 C 绑定。

1.3 血缘关系

RocksDB 是 Google LevelDB 的"增强版"分支(2012 年从 LevelDB fork 而来),针对服务器场景做了大量优化:多线程 Compaction、Column Family、WAL 定制、多种压缩算法、更丰富的性能指标等。Meta 内部用它支撑着海量存储,并持续贡献回开源社区。

Google LevelDB(2008)──fork──▶ RocksDB(2012,Meta)
                                     │
      ┌──────────────────────────────┼──────────────────────────────┐
      ▼                              ▼                              ▼
  RocksJava                     TiKV / CockroachDB           MyRocks(MySQL 存储引擎)
  (Java 绑定)              (分布式 KV/数据库底层)       (Facebook 内部 MySQL 方案)

2. 为什么选它:六大使用优点

2.1 写入性能极强(写放大可控 + 顺序写)

LSM-Tree 架构让所有写入先落在内存 MemTable,再以顺序写方式刷盘,随机写场景下吞吐量远高于传统 B+ 树存储(如 MySQL InnoDB)。官方基准测试中,单机写入吞吐可达每秒数十万到上百万次操作(取决于硬件与配置)。

2.2 灵活的内存控制

通过 BlockCache(读缓存)、WriteBuffer(写缓冲)、Compression(压缩)等参数,你可以精确控制"用多少内存换多少性能"。小到几十 MB、大到上百 GB 都能适配。

2.3 丰富的功能特性

  • Column Family(列族):一个 DB 内部分多个独立命名空间,互不干扰,适合"按业务隔离数据";
  • 事务与 WriteBatch:支持 ACID 事务(悲观/乐观)、批量原子写入;
  • 快照(Snapshot):读取一致性视图;
  • 迭代器(Iterator):高效范围扫描(前缀扫描、Seek 定位);
  • 多种压缩算法:Snappy、Zlib、LZ4、ZSTD 等,可分层配置;
  • 自定义合并算子(Merge Operator):像"计数器累加""字符串追加"这类操作可以后台增量合并,不用读改写。

2.4 生产级可靠性

WAL(Write-Ahead Log,预写日志)保证崩溃恢复不丢已确认写入;数据校验和(Checksum)检测损坏;支持 BackupEngine 在线备份;还有完善的 GetProperty 运行指标,方便监控。

2.5 高度可定制("乐高式"扩展)

存储介质(普通磁盘/SSD/持久化内存)、比较器(Comparator)、合并算子、缓存策略、压缩算法几乎都可以替换。RocksDB 社区常被称为"存储引擎的瑞士军刀"。

2.6 大厂背书 + 活跃社区

Meta、字节跳动、美团、网易、Uber 等公司在生产环境大规模使用;GitHub 星标 28k+,持续迭代,文档和资料丰富,遇到问题容易找到解决方案。


3. 它被用在哪里:典型使用场景

场景说明代表案例
大数据流式计算存储中间状态(State),如窗口计数、去重、聚合结果Apache Flink 的 RocksDB State Backend
分布式数据库底层作为单机存储引擎,上层做分布式协议TiKV(TiDB 的存储层)、CockroachDB
MySQL 存储引擎替代 InnoDB,专为"写入密集 + 压缩率高"的负载优化MyRocks(Facebook)
消息/队列中间件持久化消息、消费位点Kafka 类系统的本地缓存、RocketMQ 部分场景
缓存/边缘存储本地大容量缓存、CDN 边缘 KV各类 CDN 节点本地缓存
时序/日志数据高吞吐写入的日志、监控指标、埋点数据监控系统、APM 平台
嵌入式应用桌面/移动端需要本地高性能 KV 存储游戏存档、离线地图、浏览器缓存
数据仓库/OLAP 辅助存储元数据、索引辅助结构各类大数据组件

⚠️ 不适合的场景:① 需要完整 SQL 查询能力(它不是关系型数据库);② 需要跨进程/跨机器共享一个实例(嵌入式库,单进程访问;跨机器需搭配分布式层);③ 数据量极小且需要极简管理时(SQLite 可能更省事)。


4. 核心概念白话版:MemTable / SSTable / WAL / Compaction

4.1 数据流动总览

写路径:  Put(k, v) ──▶ WAL(先写日志,防丢)──▶ MemTable(内存表)
                                                    │ 满了/到达阈值
                                                    ▼
                                             刷盘成 SSTable(有序文件)
                                                    │ 后台积累
                                                    ▼
                                          Compaction(合并压缩,多文件变少)

读路径:  Get(k) ──▶ MemTable(最新)──▶ 各级 SSTable(按层级查)

4.2 逐个名词解释

名词白话类比作用
MemTable随身笔记本内存中的有序结构(默认跳表 SkipList),写入先到这里,读也先查这里
WAL(预写日志)记账底稿每次写入先顺序追加到磁盘日志,崩溃后可据此恢复 MemTable,防丢数据
SSTable誊抄好的账本磁盘上的有序数据文件,不可变(Immutable),分多个层级存放
Compaction(合并压缩)定期整理书柜后台线程把多层小文件合并成大文件、删除被覆盖/删除的旧数据、按需压缩
Block Cache常用书页的复印件读缓存,缓存最近读过的数据块,避免反复读磁盘
Bloom Filter(布隆过滤器)快速排除目录判断"这个 key 肯定不在某文件里",省去无效磁盘 IO
Column Family书柜里的分区隔板一个 DB 内的独立命名空间,数据物理上可分别管理
LSM-Tree整体管理哲学上述一切背后的组织思想:内存缓冲 + 顺序写 + 后台合并

4.3 为什么它读会比写慢一点?

因为读取可能需要在多个层级(MemTable → L0 → L1 → …)逐层查找。RocksDB 通过 Bloom Filter、Block Cache、以及"先查最新层"的顺序来缓解,读多写少的场景请优先加大 Block Cache 并压缩层级(见第 7 节)。


5. 环境准备:三种安装方式(Windows/macOS/Linux)

RocksDB 支持多种接入方式,推荐按你的平台选择:

方式 A:vcpkg(Windows / macOS / Linux 通用,推荐新手)

# 1. 安装 vcpkg(若已安装请跳过)
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat          # Windows;macOS/Linux 用 ./bootstrap-vcpkg.sh

# 2. 集成到全局(之后 CMake 能自动找到包)
.\vcpkg integrate install

# 3. 安装 rocksdb(选择 x64 静态库,约需几分钟编译)
.\vcpkg install rocksdb:x64-windows-static

方式 B:Linux 发行版包管理器(Ubuntu 最快)

# Ubuntu/Debian(版本可能较旧,适合快速体验)
sudo apt update && sudo apt install -y librocksdb-dev

# 或从源码编译最新版
git clone https://github.com/facebook/rocksdb.git
cd rocksdb
make static_lib -j$(nproc)     # 产出 librocksdb.a,耗时较长

方式 C:macOS Homebrew

brew install rocksdb

⚠️ 易错点 1:源码编译 RocksDB 很吃编译时间(C++ 模板 + 多种压缩库),新手别裸编译,优先用 vcpkg / 包管理器。 ⚠️ 易错点 2:Windows 下如果报"找不到 snappy/zstd 头文件",多半是 vcpkg 安装的是动态库而链接时选了静态库(或反之),保持 x64-windows-static 与 CMake 配置一致即可。

5.1 最小 CMake 工程模板

cmake_minimum_required(VERSION 3.16)
project(rocksdb_demo CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 用 vcpkg 时只需这一句,即可自动找到 rocksdb
find_package(rocksdb REQUIRED)

add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE rocksdb::rocksdb)

6. 上手实战:可运行的 C++ 代码

6.1 示例 1:打开数据库、读写、删除(Hello World)

// main.cpp —— RocksDB 最小可用示例
#include <rocksdb/db.h>
#include <iostream>
#include <cassert>
#include <string>

int main() {
    // 1. 打开数据库(不存在会自动创建)
    rocksdb::DB* db = nullptr;
    rocksdb::Options options;
    options.create_if_missing = true;   // 数据库不存在时自动创建
    options.IncreaseParallelism(4);     // 后台线程数设为 4(默认 CPU 核数)

    rocksdb::Status status = rocksdb::DB::Open(options, "./my_rocksdb", &db);
    if (!status.ok()) {
        std::cerr << "打开数据库失败: " << status.ToString() << std::endl;
        return 1;
    }

    // 2. 写入一个键值对(Status 是 RocksDB 的错误返回对象)
    status = db->Put(rocksdb::WriteOptions(), "name", "rocksdb");
    assert(status.ok());  // 生产代码请改用 status.ok() 判断,不要 assert

    // 3. 读取
    std::string value;
    status = db->Get(rocksdb::ReadOptions(), "name", &value);
    if (status.ok()) {
        std::cout << "读取成功: name = " << value << std::endl;  // 输出 rocksdb
    } else if (status.IsNotFound()) {
        std::cout << "key 不存在" << std::endl;
    }

    // 4. 删除
    status = db->Delete(rocksdb::WriteOptions(), "name");
    assert(status.ok());

    // 5. 关闭数据库(必须调用,否则数据可能未完全落盘)
    delete db;
    return 0;
}

编译运行:

# 使用 vcpkg + CMake 时:
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build build -j
./build/demo
# 预期输出:读取成功: name = rocksdb

⚠️ 易错点 3:用完一定要 delete db!RocksDB 析构时会做收尾落盘与资源释放,忘记释放轻则丢数据,重则崩溃。 ⚠️ 易错点 4:Get 的返回有三种语义:ok() 命中 / IsNotFound() 未命中 / 其他错误。不要用"value 是否为空"判断是否存在——存空字符串也是合法的。

6.2 示例 2:批量写入(WriteBatch)与原子性

业务里经常要"一次写 100 个 key"。逐个 Put 会有 100 次 WAL 刷盘,很慢。WriteBatch(批量写) 把它们打包成一次原子提交:

#include <rocksdb/db.h>
#include <iostream>

int main() {
    rocksdb::DB* db = nullptr;
    rocksdb::Options options;
    options.create_if_missing = true;
    rocksdb::DB::Open(options, "./batch_db", &db);

    // 构造批量写:多条操作打包,要么全部成功、要么全部失败(原子性)
    rocksdb::WriteBatch batch;
    for (int i = 0; i < 100; ++i) {
        // key 与 value 都支持任意二进制,这里用字符串演示
        batch.Put("user:" + std::to_string(i), "active");
    }
    // 顺手在批量里删一个旧 key
    batch.Delete("user:0");

    rocksdb::WriteOptions wopts;
    wopts.sync = false;  // 不强制每次刷盘(性能更高;程序崩溃由 WAL 保证,机器断电可能有极小窗口丢失)
    rocksdb::Status status = db->Write(wopts, &batch);
    if (!status.ok()) {
        std::cerr << "批量写入失败: " << status.ToString() << std::endl;
    } else {
        std::cout << "批量写入 100 条成功(其中 1 条删除)" << std::endl;
    }

    delete db;
    return 0;
}

💡 小知识:WriteOptions.sync = false 时,写入只进操作系统页缓存,性能极佳;sync = true 时每次 fsync 到磁盘,最安全但慢。默认 false,对"允许丢失极小窗口数据"的缓存类场景很合适。

6.3 示例 3:范围扫描(Iterator,前缀查询)

键值存储的优势之一是有序遍历。RocksDB 默认按键的字典序(可自定义 Comparator)排序:

#include <rocksdb/db.h>
#include <iostream>

int main() {
    rocksdb::DB* db = nullptr;
    rocksdb::Options options;
    options.create_if_missing = true;
    rocksdb::DB::Open(options, "./iter_db", &db);

    // 先塞入一批按前缀组织的数据(模拟"用户张三的订单")
    rocksdb::WriteBatch batch;
    batch.Put("order:1001", "book");
    batch.Put("order:1002", "phone");
    batch.Put("order:2001", "laptop");
    batch.Put("product:1", "pen");
    db->Write(rocksdb::WriteOptions(), &batch);

    // 用迭代器扫描所有 "order:" 开头的 key
    rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
    for (it->Seek("order:"); it->Valid() && it->key().ToString().rfind("order:", 0) == 0; it->Next()) {
        // Seek 定位到第一个 >= "order:" 的位置,然后逐条 Next 遍历
        std::cout << it->key().ToString() << " -> " << it->value().ToString() << std::endl;
    }
    if (!it->status().ok()) {
        std::cerr << "迭代出错: " << it->status().ToString() << std::endl;
    }
    delete it;  // 迭代器也要记得释放

    delete db;
    return 0;
}

预期输出:

order:1001 -> book
order:1002 -> phone
order:2001 -> laptop

⚠️ 易错点 5:遍历时一定要判断 it->Valid(),且要检查 it->status()。迭代器遍历中若遇到 IO 错误,Valid() 会变为 false,但错误信息只在 status() 里,不检查就会"静默少数据"。

6.4 示例 4:Column Family(列族)隔离数据

列族相当于数据库里的"表"。不同列族的数据在物理上分开管理,可以独立设置压缩、缓存等参数:

#include <rocksdb/db.h>
#include <iostream>

int main() {
    rocksdb::DB* db = nullptr;
    rocksdb::Options options;
    options.create_if_missing = true;
    options.create_missing_column_families = true;  // 允许自动创建列族

    // 打开时列出已存在的列族;新库默认只有 "default"
    std::vector<std::string> existing;
    rocksdb::DB::ListColumnFamilies(options, "./cf_db", &existing);
    std::cout << "已有列族: ";
    for (auto& name : existing) std::cout << name << " ";
    std::cout << std::endl;

    // 打开时指定列族描述符
    std::vector<rocksdb::ColumnFamilyDescriptor> descriptors;
    descriptors.emplace_back("default", rocksdb::ColumnFamilyOptions());
    descriptors.emplace_back("users", rocksdb::ColumnFamilyOptions());  // 用户数据
    descriptors.emplace_back("logs", rocksdb::ColumnFamilyOptions());   // 日志数据

    std::vector<rocksdb::ColumnFamilyHandle*> handles;
    rocksdb::Status s = rocksdb::DB::Open(options, "./cf_db", descriptors, &handles, &db);
    if (!s.ok()) { std::cerr << "打开失败: " << s.ToString() << std::endl; return 1; }

    // 写入不同列族(handles 顺序与 descriptors 一致)
    db->Put(rocksdb::WriteOptions(), handles[1], "alice", "profile_data");
    db->Put(rocksdb::WriteOptions(), handles[2], "2026-08-10", "visit_log");

    // 分别读取
    std::string v1, v2;
    db->Get(rocksdb::ReadOptions(), handles[1], "alice", &v1);
    db->Get(rocksdb::ReadOptions(), handles[2], "2026-08-10", &v2);
    std::cout << "users 列族: " << v1 << std::endl;  // profile_data
    std::cout << "logs 列族: " << v2 << std::endl;   // visit_log

    // 关闭前必须释放列族句柄
    for (auto* h : handles) delete h;
    delete db;
    return 0;
}

6.5 示例 5:性能指标读取(监控自己的引擎)

#include <rocksdb/db.h>
#include <iostream>

int main() {
    rocksdb::DB* db = nullptr;
    rocksdb::Options options;
    options.create_if_missing = true;
    rocksdb::DB::Open(options, "./stat_db", &db);

    // 模拟一些读写
    for (int i = 0; i < 1000; ++i) {
        db->Put(rocksdb::WriteOptions(), "k" + std::to_string(i), "v");
    }

    // 读取引擎内部统计(字符串形式返回)
    std::string stats;
    db->GetProperty("rocksdb.stats", &stats);
    std::cout << stats << std::endl;

    // 读取当前磁盘数据总量(字节)
    std::string size;
    db->GetProperty("rocksdb.total-sst-files-size", &size);
    std::cout << "SST 文件总大小: " << size << " 字节" << std::endl;

    delete db;
    return 0;
}

rocksdb.stats 会输出非常详细的内部指标(各级别文件数、压缩次数、命中率等),生产环境可以用它做监控告警。


7. 进阶调优:性能参数与读写优化

7.1 常用参数速查表

参数默认值作用调优建议
write_buffer_size64MB单个 MemTable 大小写密集可调大(128MB~256MB),减少刷盘频率
max_write_buffer_number2内存中最多保留几个 MemTable调大到 4~6 可吸收写入尖峰,但吃内存
target_file_size_base64MB目标 SST 文件大小增大可减少文件数量,加快部分场景扫描
max_background_jobs2后台刷盘+压缩线程数写入密集调大到 8~16(配合 IncreaseParallelism)
block_cache8MB读缓存大小读多场景调大,如 256MB~数 GB
bloom_locality / bloom_bits_per_key10 bits布隆过滤器精度读多场景保持默认或提高,用空间换 IO
compressionSnappy数据压缩算法追求压缩率用 ZSTD;追求速度用 LZ4
level_compaction_dynamic_level_bytesfalse动态层级容量写放大敏感场景建议开启
bytes_per_sync0周期性 sync设为 1MB 左右可降低断电丢数据窗口

7.2 读写场景调优套路

写入密集型(日志、时序、埋点)

options.write_buffer_size = 128 * 1024 * 1024;   // 更大的写缓冲
options.max_write_buffer_number = 6;             // 吸收写入尖峰
options.max_background_jobs = 8;                 // 更多后台刷盘线程
options.compression = rocksdb::kLZ4Compression;  // 高速压缩

读取密集型(缓存、查询服务)

options.block_cache = rocksdb::NewLRUCache(512 * 1024 * 1024); // 512MB 读缓存
options.optimize_filters_for_hits = true;  // 读多场景优化过滤器

⚠️ 易错点 6改参数前先做基准测试。RocksDB 参数之间相互耦合(例如 MemTable 调大必然吃更多内存),不要照抄网上的"万能配置",用官方 db_bench 工具或你自己的压测脚本对比验证。

7.3 官方基准工具 db_bench

# 源码编译后自带 db_bench
./db_bench --benchmarks=fillrandom,readrandom --num=1000000 \
           --threads=16 --value_size=1024 --key_size=16
# fillrandom:随机写 100 万条;readrandom:随机读,打印每秒操作数与延迟

8. 对比表格:RocksDB vs LevelDB vs SQLite vs Redis

维度RocksDBLevelDBSQLiteRedis
类型嵌入式 KV 存储引擎嵌入式 KV 存储引擎嵌入式关系型数据库独立内存数据库服务器
数据模型键值(有序)键值(有序)关系表 + SQL多种数据结构(String/Hash/List 等)
数据持久化磁盘(LSM-Tree)磁盘(LSM-Tree)磁盘(B+ 树)内存为主(可选 AOF/RDB 持久化)
写入性能★★★★★(顺序写)★★★★★★★★★★★★(内存)
读性能★★★★(需多层查找)★★★★★★★★★★★★(内存)
内存占用控制精细可调较简单较简单受数据量制约
多线程支持(多线程压缩/并发写)不支持多线程有限单线程事件循环
Column Family✅ 支持✅(表)✅(DB 隔离)
事务✅ ACID(悲观/乐观)有限✅ ACID✅ 有限事务
部署形态库链接进程序库链接进程序库链接进程序独立进程 + 网络协议
适合场景大数据量、写密集、嵌入式高吞吐简单轻量 KV需要 SQL 的中小型本地数据高速缓存、实时数据、分布式共享
维护活跃度高(Meta 持续维护)低(基本停更)

一句话选型

  • 要 SQL、要事务、本地单文件管理 → SQLite
  • 要毫秒级缓存、跨机器访问、数据结构丰富 → Redis
  • 数据量大、写入密集、要嵌入 C++ 程序 → RocksDB
  • 只是"图个轻量、够用就行"的简单 KV → LevelDB(但更推荐 RocksDB,兼容 API 且功能更强)。

9. FAQ 速查表

问题快速答案
RocksDB 是数据库吗?不是关系型数据库,是嵌入式键值存储引擎,需要你自己组织上层逻辑(或搭配 TiKV 等分布式层)
多个进程能同时打开同一个 RocksDB 吗?默认不支持(单进程独占);跨进程需自己加锁或用单写多读模式
数据存在哪里?打开时指定的目录下,由 .log(WAL)、.sst(数据)、CURRENT/MANIFEST(元数据)等文件组成
如何备份?官方推荐 rocksdb::BackupEngine,支持在线增量备份
Get 返回 IsNotFound() 就是 key 不存在吗?对;但注意区分"未命中"和"出错",用 Status 语义判断而非 value 是否为空
支持超大 value 吗?支持,但超大 value(>1MB 级)会拖慢读写,建议拆块或改用 BlobDB
读多写少怎么调?加大 block_cache、开 Bloom Filter、适当调大 target_file_size_base
写多读少怎么调?加大 write_buffer_size、max_write_buffer_number、max_background_jobs
会丢数据吗?默认 WriteOptions.sync=false 时,进程崩溃不丢(有 WAL),机器断电可能丢失最后几毫秒未 fsync 的数据;要求严格就设 sync=true
有图形界面管理工具吗?社区有第三方 GUI 工具;命令行可用 ldb / sst_dump 工具检查数据
和 LevelDB 代码兼容吗?API 基本兼容(RocksDB 扩展了更多参数),多数代码改 include 即可迁移
编译太慢怎么办?用 vcpkg/包管理器;或编译时关闭不需要的压缩库(make static_lib DISABLE_*)

10. 总结

RocksDB 用一个朴素但深刻的思想 —— "先写内存,批量顺序落盘,后台合并"(LSM-Tree)—— 换来了极致的写入性能和灵活的内存控制,成为当今大数据与存储领域的"基础设施级"开源组件。无论你是:

  • 想给 C++ 程序加一个高性能本地 KV 存储;
  • 在学习数据库/存储引擎底层原理;
  • 还是准备在生产系统里用它承接高吞吐写入,

从今天的 5 个示例出发(打开/读写/批量写/迭代器/列族),配合 db_bench 做压测调优,你就能快速上手并驾驭它。

下一步建议:① 跑通示例后,用 db_bench 对比不同参数下的吞吐;② 阅读官方 Wiki 的《Tuning Guide》;③ 尝试用 BackupEngine 实现自动备份,为生产环境做准备。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐