RocksDB缓存策略 #

一、缓存概述 #

1.1 RocksDB缓存层次 #

text
RocksDB缓存层次:

读取请求
    │
    ▼
┌─────────────────┐
│   MemTable      │ ← 内存写入缓冲
└────────┬────────┘
         │ 未命中
         ▼
┌─────────────────┐
│  Block Cache    │ ← LRU缓存
└────────┬────────┘
         │ 未命中
         ▼
┌─────────────────┐
│  OS Page Cache  │ ← 操作系统缓存
└────────┬────────┘
         │ 未命中
         ▼
┌─────────────────┐
│     磁盘        │
└─────────────────┘

1.2 缓存类型 #

缓存类型 位置 作用
MemTable 内存 写入缓冲,最新数据
Block Cache 内存 热数据块缓存
Compressed Cache 内存 压缩块缓存
OS Page Cache 内核 文件系统缓存

二、Block Cache #

2.1 创建Block Cache #

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

// 创建LRU缓存
std::shared_ptr<rocksdb::Cache> CreateBlockCache(size_t capacity) {
    return rocksdb::NewLRUCache(
        capacity,       // 缓存容量
        8,              // 分片数
        false,          // 是否使用高优先级
        0.0             // 高优先级比例
    );
}

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

rocksdb::Options options;
options.table_factory.reset(
    rocksdb::NewBlockBasedTableFactory(table_options)
);

2.2 LRU缓存参数 #

cpp
#include <rocksdb/cache.h>

std::shared_ptr<rocksdb::Cache> CreateOptimizedCache() {
    return rocksdb::NewLRUCache(
        2 * 1024 * 1024 * 1024,  // 容量:2GB
        16,                       // 分片数:16(减少锁竞争)
        true,                     // 使用高优先级队列
        0.5                       // 高优先级比例:50%
    );
}

// 分片数建议:
// - 小缓存:4-8
// - 中等缓存:8-16
// - 大缓存:16-32

2.3 缓存优先级 #

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

rocksdb::BlockBasedTableOptions GetPriorityCacheOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // 创建带优先级的缓存
    options.block_cache = rocksdb::NewLRUCache(
        1024 * 1024 * 1024,
        8,
        true,    // 启用高优先级
        0.3      // 30%高优先级空间
    );
    
    // Pin重要块
    options.pin_l0_filter_and_index_blocks_in_cache = true;
    options.pin_top_level_index_and_filter = true;
    
    return options;
}

三、压缩块缓存 #

3.1 配置压缩块缓存 #

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

rocksdb::BlockBasedTableOptions GetCompressedCacheOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // 主缓存(解压后数据)
    options.block_cache = rocksdb::NewLRUCache(
        2 * 1024 * 1024 * 1024  // 2GB
    );
    
    // 压缩块缓存(压缩数据)
    options.block_cache_compressed = rocksdb::NewLRUCache(
        512 * 1024 * 1024  // 512MB
    );
    
    return options;
}

3.2 压缩缓存作用 #

text
压缩块缓存工作流程:

读取请求
    │
    ▼
检查Block Cache(解压数据)
    │ 未命中
    ▼
检查Compressed Cache(压缩数据)
    │ 命中
    ▼
解压数据
    │
    ▼
放入Block Cache
    │
    ▼
返回数据

优点:
- 节省内存空间
- 减少磁盘读取
- 适合压缩比高的场景

四、缓存策略 #

4.1 缓存填充策略 #

cpp
#include <rocksdb/options.h>

// 读取时填充缓存
rocksdb::ReadOptions GetFillCacheOptions() {
    rocksdb::ReadOptions options;
    options.fill_cache = true;  // 默认值
    return options;
}

// 大范围扫描不填充缓存
rocksdb::ReadOptions GetNoFillCacheOptions() {
    rocksdb::ReadOptions options;
    options.fill_cache = false;  // 避免污染缓存
    return options;
}

4.2 缓存预读 #

cpp
#include <rocksdb/options.h>

rocksdb::ReadOptions GetReadaheadOptions() {
    rocksdb::ReadOptions options;
    
    // 设置预读大小
    options.readahead_size = 256 * 1024;  // 256KB
    
    // 自动预读
    options.auto_readahead_size = true;
    
    return options;
}

4.3 缓存Pin策略 #

cpp
#include <rocksdb/table.h>

rocksdb::BlockBasedTableOptions GetPinOptions() {
    rocksdb::BlockBasedTableOptions options;
    
    // Pin L0的Filter和Index
    options.pin_l0_filter_and_index_blocks_in_cache = true;
    
    // Pin顶层Index和Filter
    options.pin_top_level_index_and_filter = true;
    
    return options;
}

五、缓存优化 #

5.1 读密集场景 #

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

rocksdb::Options GetReadOptimizedOptions() {
    rocksdb::Options options;
    
    rocksdb::BlockBasedTableOptions table_options;
    
    // 大容量缓存
    table_options.block_cache = rocksdb::NewLRUCache(
        4 * 1024 * 1024 * 1024,  // 4GB
        16
    );
    
    // 压缩缓存
    table_options.block_cache_compressed = rocksdb::NewLRUCache(
        1 * 1024 * 1024 * 1024  // 1GB
    );
    
    // Pin重要块
    table_options.pin_l0_filter_and_index_blocks_in_cache = true;
    
    // 布隆过滤器
    table_options.filter_policy.reset(
        rocksdb::NewBloomFilterPolicy(10)
    );
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    return options;
}

5.2 写密集场景 #

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

rocksdb::Options GetWriteOptimizedOptions() {
    rocksdb::Options options;
    
    // 大MemTable
    options.write_buffer_size = 128 * 1024 * 1024;
    options.max_write_buffer_number = 8;
    
    // 中等Block Cache
    rocksdb::BlockBasedTableOptions table_options;
    table_options.block_cache = rocksdb::NewLRUCache(
        1 * 1024 * 1024 * 1024  // 1GB
    );
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    return options;
}

5.3 内存受限场景 #

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

rocksdb::Options GetMemoryConstrainedOptions() {
    rocksdb::Options options;
    
    rocksdb::BlockBasedTableOptions table_options;
    
    // 小缓存
    table_options.block_cache = rocksdb::NewLRUCache(
        256 * 1024 * 1024  // 256MB
    );
    
    // 不使用压缩缓存
    table_options.block_cache_compressed = nullptr;
    
    // 高压缩比
    options.compression = rocksdb::CompressionType::kZSTD;
    
    options.table_factory.reset(
        rocksdb::NewBlockBasedTableFactory(table_options)
    );
    
    return options;
}

六、缓存监控 #

6.1 缓存统计 #

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

void PrintCacheStats(rocksdb::DB* db) {
    // 获取缓存使用量
    uint64_t usage;
    db->GetIntProperty("rocksdb.block-cache-usage", &usage);
    std::cout << "Block cache usage: " << usage / 1024 / 1024 << " MB" << std::endl;
    
    // Pin使用量
    db->GetIntProperty("rocksdb.block-cache-pinned-usage", &usage);
    std::cout << "Pinned usage: " << usage / 1024 / 1024 << " MB" << std::endl;
    
    // 缓存容量
    auto cache = db->GetOptions().table_factory->GetOptions<rocksdb::BlockBasedTableOptions>()->block_cache;
    std::cout << "Cache capacity: " << cache->GetCapacity() / 1024 / 1024 << " MB" << std::endl;
}

6.2 缓存命中率 #

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

void PrintCacheHitRate(rocksdb::DB* db) {
    auto stats = db->GetOptions().statistics;
    
    uint64_t hits = stats->getTickerCount(rocksdb::BLOCK_CACHE_HIT);
    uint64_t misses = stats->getTickerCount(rocksdb::BLOCK_CACHE_MISS);
    uint64_t total = hits + misses;
    
    if (total > 0) {
        double hit_rate = (double)hits / total * 100;
        std::cout << "Block cache hit rate: " << hit_rate << "%" << std::endl;
        std::cout << "Hits: " << hits << ", Misses: " << misses << std::endl;
    }
    
    // 数据块命中
    hits = stats->getTickerCount(rocksdb::BLOCK_CACHE_DATA_HIT);
    misses = stats->getTickerCount(rocksdb::BLOCK_CACHE_DATA_MISS);
    std::cout << "Data block hit rate: " << (double)hits / (hits + misses) * 100 << "%" << std::endl;
    
    // 索引块命中
    hits = stats->getTickerCount(rocksdb::BLOCK_CACHE_INDEX_HIT);
    misses = stats->getTickerCount(rocksdb::BLOCK_CACHE_INDEX_MISS);
    std::cout << "Index block hit rate: " << (double)hits / (hits + misses) * 100 << "%" << std::endl;
    
    // 过滤器块命中
    hits = stats->getTickerCount(rocksdb::BLOCK_CACHE_FILTER_HIT);
    misses = stats->getTickerCount(rocksdb::BLOCK_CACHE_FILTER_MISS);
    std::cout << "Filter block hit rate: " << (double)hits / (hits + misses) * 100 << "%" << std::endl;
}

七、缓存最佳实践 #

7.1 缓存大小建议 #

场景 Block Cache 压缩缓存 说明
读密集 50-60%内存 10-20% 大缓存
写密集 20-30%内存 5-10% 中等缓存
平衡 40-50%内存 10-15% 均衡配置
内存受限 30-40%内存 不使用 小缓存

7.2 缓存优化建议 #

  1. 合理设置大小:根据可用内存和场景
  2. 监控命中率:关注缓存效果
  3. 避免污染:大扫描不填充缓存
  4. Pin重要块:索引和过滤器
  5. 使用压缩缓存:节省内存空间

八、总结 #

8.1 缓存配置速查 #

配置 参数 说明
缓存容量 NewLRUCache(capacity) 设置缓存大小
分片数 NewLRUCache(capacity, shards) 减少锁竞争
压缩缓存 block_cache_compressed 缓存压缩数据
Pin策略 pin_l0_filter_and_index Pin重要块
填充策略 fill_cache 是否填充缓存

8.2 关键要点 #

  1. 分层缓存:MemTable → Block Cache → 磁盘
  2. LRU策略:自动淘汰冷数据
  3. 优先级:保护重要数据
  4. 监控优化:持续关注命中率
  5. 场景配置:根据场景调整

下一步,让我们学习写入优化!

最后更新:2026-03-27