RocksDB内存管理 #

一、内存使用概述 #

1.1 内存组成 #

text
RocksDB内存使用:

┌─────────────────────────────────────────────────┐
│                   总内存使用                      │
├─────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────┐   │
│  │           Block Cache                   │   │
│  │        (数据块缓存)                      │   │
│  └─────────────────────────────────────────┘   │
├─────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────┐   │
│  │           MemTable                      │   │
│  │        (写入缓冲)                        │   │
│  └─────────────────────────────────────────┘   │
├─────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────┐   │
│  │           Index & Filter                │   │
│  │        (索引和过滤器)                    │   │
│  └─────────────────────────────────────────┘   │
├─────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────┐   │
│  │           其他开销                       │   │
│  │        (跳表、锁等)                      │   │
│  └─────────────────────────────────────────┘   │
└─────────────────────────────────────────────────┘

1.2 内存比例建议 #

组件 建议比例 说明
Block Cache 40-50% 缓存热数据
MemTable 20-30% 写入缓冲
Index & Filter 10-20% 加速查找
其他 5-10% 系统开销

二、Block Cache #

2.1 创建Block Cache #

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

// LRU缓存
std::shared_ptr<rocksdb::Cache> CreateLRUCache(size_t size) {
    return rocksdb::NewLRUCache(
        size,           // 缓存大小
        8,              // 分片数(减少锁竞争)
        false,          // 是否使用高优先级
        0.0             // 高优先级比例
    );
}

// 使用
rocksdb::BlockBasedTableOptions table_options;
table_options.block_cache = CreateLRUCache(1024 * 1024 * 1024);  // 1GB

2.2 Block Cache配置 #

cpp
#include <rocksdb/table.h>

rocksdb::BlockBasedTableOptions GetBlockCacheOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // 主缓存
    options.block_cache = rocksdb::NewLRUCache(
        1024 * 1024 * 1024,  // 1GB
        16                    // 16分片
    );
    
    // 压缩块缓存
    options.block_cache_compressed = rocksdb::NewLRUCache(
        256 * 1024 * 1024  // 256MB
    );
    
    // Pin L0的Filter和Index
    options.pin_l0_filter_and_index_blocks_in_cache = true;
    
    // Pin顶层Index
    options.pin_top_level_index_and_filter = true;
    
    return options;
}

2.3 缓存优先级 #

cpp
#include <rocksdb/cache.h>

// 设置缓存优先级
rocksdb::BlockBasedTableOptions table_options;
table_options.block_cache = rocksdb::NewLRUCache(
    1024 * 1024 * 1024,
    8,
    true,    // 使用高优先级
    0.5      // 50%高优先级
);

// 高优先级用于:
// - 索引块
// - 过滤器块
// - 热点数据块

2.4 缓存统计 #

cpp
#include <rocksdb/cache.h>
#include <iostream>

void PrintCacheStats(const std::shared_ptr<rocksdb::Cache>& cache) {
    rocksdb::Cache::CacheStats stats;
    cache->GetStats(&stats);
    
    std::cout << "Cache usage: " << stats.cache_usage << std::endl;
    std::cout << "Pinned usage: " << stats.pinned_usage << std::endl;
    std::cout << "Hit rate: " << 
        (double)stats.hit_count / (stats.hit_count + stats.miss_count) << std::endl;
}

三、MemTable内存 #

3.1 MemTable大小配置 #

cpp
#include <rocksdb/options.h>

rocksdb::Options GetMemTableOptions() {
    rocksdb::Options options;
    
    // 单个MemTable大小
    options.write_buffer_size = 64 * 1024 * 1024;  // 64MB
    
    // 最大MemTable数量
    options.max_write_buffer_number = 4;
    
    // 最小合并数量
    options.min_write_buffer_number_to_merge = 2;
    
    // 最大内存占用 = write_buffer_size × max_write_buffer_number
    // = 64MB × 4 = 256MB
    
    return options;
}

3.2 MemTable内存计算 #

text
MemTable内存占用计算:

1. 数据存储
   - 键值对数据
   - 跳表节点

2. 索引开销
   - 跳表多层索引
   - 约10-20%额外开销

3. 总占用
   MemTable内存 ≈ 数据大小 × 1.2

示例:
write_buffer_size = 64MB
实际内存占用 ≈ 64MB × 1.2 = 76.8MB

3.3 MemTable变体内存 #

cpp
#include <rocksdb/memtablerep.h>

// 跳表(默认)- 内存效率中等
options.memtable_factory.reset(new rocksdb::SkipListFactory());

// 向量 - 内存效率低,适合小数据
options.memtable_factory.reset(new rocksdb::VectorRepFactory());

// 哈希链表 - 内存效率高
options.memtable_factory.reset(
    rocksdb::NewHashLinkListRepFactory(10000)
);

四、索引和过滤器内存 #

4.1 索引块内存 #

cpp
#include <rocksdb/table.h>

rocksdb::BlockBasedTableOptions GetIndexOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // 索引类型
    options.index_type = rocksdb::BlockBasedTableOptions::kBinarySearch;
    
    // 索引块大小
    options.index_block_restart_interval = 1;
    
    // Pin索引到缓存
    options.pin_l0_filter_and_index_blocks_in_cache = true;
    
    return options;
}

4.2 过滤器内存 #

cpp
#include <rocksdb/table.h>
#include <rocksdb/filter_policy.h>

rocksdb::BlockBasedTableOptions GetFilterOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // 布隆过滤器
    options.filter_policy.reset(
        rocksdb::NewBloomFilterPolicy(10)  // 10 bits per key
    );
    
    // 内存占用计算:
    // 每个key 10 bits
    // 100万keys = 10M bits ≈ 1.25MB
    
    // 优化内存
    options.optimize_filters_for_memory = true;
    
    return options;
}

4.3 减少索引内存 #

cpp
#include <rocksdb/table.h>

rocksdb::BlockBasedTableOptions GetReducedIndexOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // 使用分区索引
    options.index_type = rocksdb::BlockBasedTableOptions::kTwoLevelIndexSearch;
    
    // 增大索引块大小
    options.index_block_restart_interval = 16;
    
    // 使用哈希索引(适合点查询)
    options.index_type = rocksdb::BlockBasedTableOptions::kHashSearch;
    options.prefix_extractor.reset(rocksdb::NewFixedPrefixTransform(5));
    
    return options;
}

五、内存限制 #

5.1 设置内存限制 #

cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>

void SetMemoryLimit(rocksdb::DB* db, size_t limit) {
    // 设置Block Cache大小限制
    auto cache = db->GetOptions().table_factory->GetOptions<rocksdb::BlockBasedTableOptions>()->block_cache;
    cache->SetCapacity(limit);
}

// 监控内存使用
void MonitorMemoryUsage(rocksdb::DB* db) {
    uint64_t memtable_usage;
    db->GetIntProperty("rocksdb.cur-size-all-mem-tables", &memtable_usage);
    
    uint64_t block_cache_usage;
    db->GetIntProperty("rocksdb.block-cache-usage", &block_cache_usage);
    
    std::cout << "MemTable: " << memtable_usage / 1024 / 1024 << " MB" << std::endl;
    std::cout << "Block Cache: " << block_cache_usage / 1024 / 1024 << " MB" << std::endl;
}

5.2 写入限速 #

cpp
#include <rocksdb/options.h>

rocksdb::Options GetWriteLimitOptions() {
    rocksdb::Options options;
    
    // MemTable数量限制
    options.max_write_buffer_number = 4;
    
    // 写入减速触发
    options.level0_slowdown_writes_trigger = 20;
    
    // 写入停止触发
    options.level0_stop_writes_trigger = 36;
    
    return options;
}

六、内存优化策略 #

6.1 内存敏感场景 #

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

rocksdb::Options GetMemoryOptimizedOptions() {
    rocksdb::Options options;
    
    // 减小MemTable
    options.write_buffer_size = 16 * 1024 * 1024;  // 16MB
    options.max_write_buffer_number = 2;
    
    // 减小Block Cache
    rocksdb::BlockBasedTableOptions table_options;
    table_options.block_cache = rocksdb::NewLRUCache(256 * 1024 * 1024);  // 256MB
    
    // 使用高压缩比
    options.compression = rocksdb::CompressionType::kZSTD;
    
    // 减少索引内存
    table_options.index_block_restart_interval = 16;
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    return options;
}

6.2 内存充足场景 #

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

rocksdb::Options GetMemoryRichOptions() {
    rocksdb::Options options;
    
    // 大MemTable
    options.write_buffer_size = 256 * 1024 * 1024;  // 256MB
    options.max_write_buffer_number = 8;
    
    // 大Block Cache
    rocksdb::BlockBasedTableOptions table_options;
    table_options.block_cache = rocksdb::NewLRUCache(4 * 1024 * 1024 * 1024);  // 4GB
    table_options.block_cache_compressed = rocksdb::NewLRUCache(512 * 1024 * 1024);
    
    // Pin更多数据
    table_options.pin_l0_filter_and_index_blocks_in_cache = true;
    table_options.pin_top_level_index_and_filter = true;
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    return options;
}

七、内存监控 #

7.1 内存指标 #

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

void PrintMemoryStats(rocksdb::DB* db) {
    uint64_t value;
    
    // MemTable内存
    db->GetIntProperty("rocksdb.cur-size-all-mem-tables", &value);
    std::cout << "MemTable memory: " << value / 1024 / 1024 << " MB" << std::endl;
    
    // Block Cache使用
    db->GetIntProperty("rocksdb.block-cache-usage", &value);
    std::cout << "Block cache usage: " << value / 1024 / 1024 << " MB" << std::endl;
    
    // Block CachePin
    db->GetIntProperty("rocksdb.block-cache-pinned-usage", &value);
    std::cout << "Block cache pinned: " << value / 1024 / 1024 << " MB" << std::endl;
    
    // 活跃MemTable数量
    db->GetIntProperty("rocksdb.num-active-mem-table", &value);
    std::cout << "Active MemTables: " << value << std::endl;
    
    // Immutable MemTable数量
    db->GetIntProperty("rocksdb.num-immutable-mem-table", &value);
    std::cout << "Immutable MemTables: " << value << std::endl;
}

7.2 内存统计 #

cpp
#include <rocksdb/statistics.h>

void PrintMemoryStatistics(rocksdb::DB* db) {
    auto stats = db->GetOptions().statistics;
    
    // Block Cache命中
    uint64_t hits = stats->getTickerCount(rocksdb::BLOCK_CACHE_HIT);
    uint64_t misses = stats->getTickerCount(rocksdb::BLOCK_CACHE_MISS);
    
    double hit_rate = (double)hits / (hits + misses) * 100;
    std::cout << "Block cache hit rate: " << hit_rate << "%" << std::endl;
    
    // MemTable命中
    hits = stats->getTickerCount(rocksdb::MEMTABLE_HIT);
    misses = stats->getTickerCount(rocksdb::MEMTABLE_MISS);
    
    hit_rate = (double)hits / (hits + misses) * 100;
    std::cout << "MemTable hit rate: " << hit_rate << "%" << std::endl;
}

八、最佳实践 #

8.1 内存配置建议 #

场景 Block Cache MemTable 建议
读密集 50-60% 15-20% 大缓存
写密集 30-40% 30-40% 大MemTable
平衡 40-50% 25-30% 均衡配置
内存受限 30-40% 15-20% 高压缩比

8.2 内存调优步骤 #

  1. 评估可用内存:确定总内存预算
  2. 分配组件内存:按比例分配各组件
  3. 监控内存使用:观察实际使用情况
  4. 调整优化:根据监控结果调整
  5. 验证效果:确认性能提升

九、总结 #

9.1 内存组件 #

组件 作用 配置参数
Block Cache 缓存热数据 block_cache
MemTable 写入缓冲 write_buffer_size
Index 加速查找 index_block_restart_interval
Filter 快速排除 filter_policy

9.2 关键要点 #

  1. 合理分配:按场景分配内存比例
  2. 监控使用:持续监控内存指标
  3. 及时调整:根据实际情况优化
  4. 避免溢出:设置合理的限制
  5. 权衡取舍:平衡各组件内存

下一步,让我们学习缓存策略!

最后更新:2026-03-27