RocksDB最佳实践 #

一、设计原则 #

1.1 核心原则 #

text
RocksDB设计原则:
├── 了解场景 - 明确读写模式
├── 合理配置 - 根据场景配置
├── 监控先行 - 建立监控体系
├── 测试验证 - 充分测试后上线
└── 持续优化 - 基于监控持续改进

1.2 场景分类 #

场景 特点 重点优化
写密集 高写入吞吐 MemTable、Compaction
读密集 高读取QPS Block Cache、过滤器
混合 读写均衡 均衡配置
时序 顺序写入 FIFO Compaction

二、配置最佳实践 #

2.1 通用配置模板 #

cpp
#include <rocksdb/options.h>
#include <rocksdb/table.h>
#include <rocksdb/cache.h>

rocksdb::Options GetProductionOptions() {
    rocksdb::Options options;
    
    // 基础配置
    options.create_if_missing = true;
    options.create_missing_column_families = true;
    
    // MemTable配置
    options.write_buffer_size = 64 * 1024 * 1024;  // 64MB
    options.max_write_buffer_number = 4;
    options.min_write_buffer_number_to_merge = 2;
    
    // Compaction配置
    options.max_background_jobs = 8;
    options.max_background_compactions = 4;
    options.max_background_flushes = 2;
    
    // 层级配置
    options.max_bytes_for_level_base = 256 * 1024 * 1024;
    options.level0_file_num_compaction_trigger = 4;
    options.level0_slowdown_writes_trigger = 20;
    options.level0_stop_writes_trigger = 36;
    
    // 压缩配置
    options.compression = rocksdb::CompressionType::kLZ4Compression;
    
    // Block Cache
    rocksdb::BlockBasedTableOptions table_options;
    table_options.block_cache = rocksdb::NewLRUCache(
        1024 * 1024 * 1024  // 1GB
    );
    table_options.filter_policy.reset(
        rocksdb::NewBloomFilterPolicy(10)
    );
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    // 统计
    options.statistics = rocksdb::CreateDBStatistics();
    
    return options;
}

2.2 场景化配置 #

高吞吐写入:

cpp
rocksdb::Options GetHighWriteThroughputOptions() {
    rocksdb::Options options;
    
    options.write_buffer_size = 128 * 1024 * 1024;
    options.max_write_buffer_number = 8;
    options.max_background_jobs = 16;
    options.level0_file_num_compaction_trigger = 8;
    options.compression = rocksdb::CompressionType::kLZ4Compression;
    
    return options;
}

低延迟读取:

cpp
rocksdb::Options GetLowReadLatencyOptions() {
    rocksdb::Options options;
    
    options.write_buffer_size = 32 * 1024 * 1024;
    options.max_write_buffer_number = 3;
    options.level0_file_num_compaction_trigger = 2;
    
    rocksdb::BlockBasedTableOptions table_options;
    table_options.block_cache = rocksdb::NewLRUCache(4 * 1024 * 1024 * 1024);
    table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
    table_options.pin_l0_filter_and_index_blocks_in_cache = true;
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    return options;
}

三、写入最佳实践 #

3.1 批量写入 #

cpp
// 推荐:使用WriteBatch
void BatchWrite(rocksdb::DB* db, 
                const std::vector<std::pair<std::string, std::string>>& data) {
    rocksdb::WriteBatch batch;
    
    for (const auto& [key, value] : data) {
        batch.Put(key, value);
    }
    
    rocksdb::WriteOptions options;
    options.sync = false;  // 根据可靠性需求
    
    db->Write(options, &batch);
}

// 不推荐:单次写入
void SingleWrite(rocksdb::DB* db, 
                 const std::vector<std::pair<std::string, std::string>>& data) {
    for (const auto& [key, value] : data) {
        db->Put(rocksdb::WriteOptions(), key, value);  // 性能差
    }
}

3.2 WAL配置 #

cpp
// 关键数据:同步写入
rocksdb::WriteOptions GetSyncOptions() {
    rocksdb::WriteOptions options;
    options.sync = true;
    return options;
}

// 非关键数据:异步写入
rocksdb::WriteOptions GetAsyncOptions() {
    rocksdb::WriteOptions options;
    options.sync = false;
    return options;
}

// 批量导入:禁用WAL
rocksdb::WriteOptions GetBulkLoadOptions() {
    rocksdb::WriteOptions options;
    options.disableWAL = true;
    options.sync = false;
    return options;
}

3.3 键设计 #

cpp
// 推荐:有序键设计
std::string MakeUserKey(int user_id) {
    // 使用固定长度,保持有序
    char key[20];
    sprintf(key, "user:%010d", user_id);
    return std::string(key);
}

// 推荐:前缀设计
std::string MakePrefixedKey(const std::string& prefix, int id) {
    return prefix + ":" + std::to_string(id);
}

// 不推荐:随机键
std::string MakeRandomKey() {
    return std::to_string(rand());  // 导致随机IO
}

四、读取最佳实践 #

4.1 缓存利用 #

cpp
// 推荐:利用缓存
rocksdb::ReadOptions GetCachedReadOptions() {
    rocksdb::ReadOptions options;
    options.fill_cache = true;  // 填充缓存
    return options;
}

// 大范围扫描:不填充缓存
rocksdb::ReadOptions GetScanReadOptions() {
    rocksdb::ReadOptions options;
    options.fill_cache = false;  // 避免污染缓存
    options.readahead_size = 2 * 1024 * 1024;  // 大预读
    return options;
}

4.2 迭代器使用 #

cpp
// 推荐:设置边界
void RangeScan(rocksdb::DB* db, 
               const std::string& start, 
               const std::string& end) {
    
    rocksdb::ReadOptions options;
    options.iterate_upper_bound = &end;  // 设置上界
    
    rocksdb::Iterator* it = db->NewIterator(options);
    
    for (it->Seek(start); it->Valid(); it->Next()) {
        // 处理数据
    }
    
    delete it;  // 及时释放
}

// 不推荐:无边界扫描
void UnboundedScan(rocksdb::DB* db) {
    rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
    
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        // 效率低
    }
    
    delete it;
}

4.3 快照使用 #

cpp
// 推荐:使用RAII管理快照
class ScopedSnapshot {
public:
    explicit ScopedSnapshot(rocksdb::DB* db) 
        : db_(db), snapshot_(db->GetSnapshot()) {}
    
    ~ScopedSnapshot() {
        if (snapshot_) {
            db_->ReleaseSnapshot(snapshot_);
        }
    }
    
    const rocksdb::Snapshot* Get() const { return snapshot_; }
    
private:
    rocksdb::DB* db_;
    const rocksdb::Snapshot* snapshot_;
};

// 使用
void ConsistentRead(rocksdb::DB* db) {
    ScopedSnapshot snap(db);
    
    rocksdb::ReadOptions options;
    options.snapshot = snap.Get();
    
    // 一致性读取
    std::string value;
    db->Get(options, "key", &value);
}

五、运维最佳实践 #

5.1 监控配置 #

cpp
// 启用统计
options.statistics = rocksdb::CreateDBStatistics();
options.statistics->set_stats_level(rocksdb::StatsLevel::kAll);

// 启用日志
options.info_log_level = rocksdb::InfoLogLevel::INFO_LEVEL;
options.log_file_time_to_roll = 24 * 60 * 60;  // 每天轮转
options.keep_log_file_num = 7;  // 保留7天

5.2 定期维护 #

cpp
// 定期Compaction
void ScheduleCompaction(rocksdb::DB* db, int interval_hours) {
    while (true) {
        std::this_thread::sleep_for(std::chrono::hours(interval_hours));
        
        rocksdb::CompactRangeOptions options;
        options.exclusive_manual_compaction = false;
        
        db->CompactRange(options, nullptr, nullptr);
    }
}

// 定期备份
void ScheduleBackup(rocksdb::DB* db, 
                    const std::string& backup_dir,
                    int interval_hours) {
    while (true) {
        std::this_thread::sleep_for(std::chrono::hours(interval_hours));
        
        rocksdb::BackupEngine* backup_engine;
        rocksdb::BackupEngine::Open(rocksdb::Env::Default(),
            rocksdb::BackupEngineOptions(backup_dir), &backup_engine);
        
        backup_engine->CreateNewBackup(db);
        backup_engine->PurgeOldBackups(7);  // 保留7个备份
        
        delete backup_engine;
    }
}

5.3 健康检查 #

cpp
struct HealthStatus {
    bool healthy;
    std::vector<std::string> issues;
};

HealthStatus CheckHealth(rocksdb::DB* db) {
    HealthStatus status;
    status.healthy = true;
    
    uint64_t value;
    
    // 检查L0文件数
    db->GetIntProperty("rocksdb.num-files-at-level0", &value);
    if (value > 30) {
        status.healthy = false;
        status.issues.push_back("L0 files too many: " + std::to_string(value));
    }
    
    // 检查MemTable数量
    db->GetIntProperty("rocksdb.num-immutable-mem-table", &value);
    if (value > 6) {
        status.healthy = false;
        status.issues.push_back("Immutable MemTables too many: " + std::to_string(value));
    }
    
    // 检查待Compaction
    db->GetIntProperty("rocksdb.estimate-pending-compaction-bytes", &value);
    if (value > 10 * 1024 * 1024 * 1024) {
        status.healthy = false;
        status.issues.push_back("Pending compaction too large");
    }
    
    return status;
}

六、性能优化清单 #

6.1 写入优化 #

优化项 方法
批量写入 使用WriteBatch
WAL优化 sync=false或disableWAL
MemTable 增大write_buffer_size
后台线程 增加max_background_jobs
Compaction 调整触发阈值

6.2 读取优化 #

优化项 方法
Block Cache 增大缓存容量
布隆过滤器 启用并设置合适参数
索引优化 选择合适的索引类型
预读 设置readahead_size
迭代器 设置边界,及时释放

6.3 空间优化 #

优化项 方法
压缩 启用压缩,分层配置
Compaction 定期执行
快照清理 及时释放快照
删除数据 使用DeleteRange

七、常见陷阱 #

7.1 配置陷阱 #

cpp
// 陷阱1:MemTable过小
options.write_buffer_size = 4 * 1024 * 1024;  // 太小,频繁Flush

// 陷阱2:Block Cache过小
table_options.block_cache = rocksdb::NewLRUCache(64 * 1024 * 1024);  // 太小

// 陷阱3:后台线程不足
options.max_background_jobs = 1;  // 太少

// 陷阱4:L0触发阈值过低
options.level0_file_num_compaction_trigger = 1;  // 过于频繁

7.2 使用陷阱 #

cpp
// 陷阱1:不及时释放迭代器
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
// 使用后忘记delete it

// 陷阱2:长时间持有快照
const rocksdb::Snapshot* snapshot = db->GetSnapshot();
// 长时间不释放,影响Compaction

// 陷阱3:单次写入
for (int i = 0; i < 10000; i++) {
    db->Put(rocksdb::WriteOptions(), key, value);  // 性能差
}

// 陷阱4:无边界扫描
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
    // 无边界,效率低
}

八、生产检查清单 #

8.1 上线前检查 #

  • [ ] 配置已根据场景优化
  • [ ] 监控已配置
  • [ ] 告警已设置
  • [ ] 备份策略已实施
  • [ ] 性能测试已完成
  • [ ] 故障恢复流程已测试

8.2 运行中检查 #

  • [ ] 监控指标正常
  • [ ] 无告警触发
  • [ ] 空间使用合理
  • [ ] 性能稳定
  • [ ] 备份正常执行

8.3 定期维护 #

  • [ ] 每日健康检查
  • [ ] 每周性能分析
  • [ ] 每月容量评估
  • [ ] 每季度配置审查

九、总结 #

9.1 核心最佳实践 #

  1. 了解场景:明确读写模式
  2. 合理配置:根据场景配置参数
  3. 批量操作:使用WriteBatch减少IO
  4. 监控告警:建立完善的监控体系
  5. 定期维护:执行定期维护任务

9.2 关键要点 #

方面 要点
配置 根据场景选择合适配置
写入 批量写入、合理WAL配置
读取 利用缓存、设置边界
运维 监控告警、定期维护
优化 持续监控、持续优化

RocksDB文档系列完成!恭喜你完成了从入门到专家的学习之旅!

最后更新:2026-03-27