RocksDB故障排查 #

一、故障排查概述 #

1.1 排查思路 #

text
故障排查流程:
├── 收集信息 - 错误日志、监控数据
├── 分析现象 - 确定问题类型
├── 定位原因 - 找到根本原因
├── 解决问题 - 实施解决方案
└── 验证效果 - 确认问题解决

1.2 常见问题分类 #

类别 问题
启动问题 打开失败、恢复失败
写入问题 写入慢、写入停止
读取问题 读取慢、读取错误
空间问题 空间增长、空间不足
性能问题 性能下降、抖动

二、启动问题 #

2.1 数据库打开失败 #

问题现象:

text
Error: IO error: While lock file: /path/to/db/LOCK: Resource temporarily unavailable

原因分析:

  • 另一个进程已打开数据库
  • 上次异常退出,锁文件未清理

解决方案:

bash
# 检查是否有进程占用
lsof /path/to/db/LOCK

# 确认无进程后删除锁文件
rm /path/to/db/LOCK

# 重新打开数据库

2.2 WAL恢复失败 #

问题现象:

text
Error: Corruption: Corrupted WAL file

原因分析:

  • WAL文件损坏
  • 系统崩溃导致WAL不完整

解决方案:

cpp
// 设置恢复模式
rocksdb::Options options;
options.wal_recovery_mode = rocksdb::WALRecoveryMode::kPointInTimeRecovery;

// 或跳过损坏记录
options.wal_recovery_mode = rocksdb::WALRecoveryMode::kSkipAnyCorruptedRecords;

2.3 MANIFEST损坏 #

问题现象:

text
Error: Corruption: MANIFEST corrupted

解决方案:

bash
# 1. 备份当前数据
cp -r /path/to/db /path/to/db_backup

# 2. 尝试使用ldb修复
ldb repair /path/to/db

# 3. 如果修复失败,从备份恢复

三、写入问题 #

3.1 写入速度慢 #

问题现象:

  • 写入延迟高
  • 写入吞吐下降

诊断步骤:

cpp
// 检查MemTable状态
uint64_t num_memtables;
db->GetIntProperty("rocksdb.num-immutable-mem-table", &num_memtables);

// 检查L0文件数
uint64_t l0_files;
db->GetIntProperty("rocksdb.num-files-at-level0", &l0_files);

// 检查待Compaction
uint64_t pending_compaction;
db->GetIntProperty("rocksdb.estimate-pending-compaction-bytes", &pending_compaction);

解决方案:

cpp
// 1. 增加MemTable大小
options.write_buffer_size = 128 * 1024 * 1024;

// 2. 增加后台线程
options.max_background_jobs = 16;

// 3. 调整Compaction触发阈值
options.level0_file_num_compaction_trigger = 8;

// 4. 使用批量写入
rocksdb::WriteBatch batch;
batch.Put(key1, value1);
batch.Put(key2, value2);
db->Write(WriteOptions(), &batch);

3.2 写入停止 #

问题现象:

text
Error: IO error: Write stopped

原因分析:

  • L0文件数超过限制
  • MemTable数量超过限制

诊断步骤:

bash
# 检查L0文件数
ldb dump --db=/path/to/db --count_only

# 检查配置
# level0_stop_writes_trigger

解决方案:

cpp
// 1. 手动触发Compaction
db->CompactRange(CompactRangeOptions(), nullptr, nullptr);

// 2. 调整停止写入阈值
options.level0_stop_writes_trigger = 50;

// 3. 增加后台Compaction线程
options.max_background_compactions = 8;

3.3 写入延迟抖动 #

问题现象:

  • 写入延迟偶尔飙升
  • 周期性性能下降

原因分析:

  • Compaction导致IO争用
  • Flush阻塞写入

解决方案:

cpp
// 1. 限制Compaction速率
options.rate_limiter.reset(
    rocksdb::NewGenericRateLimiter(100 * 1024 * 1024)  // 100MB/s
);

// 2. 增加后台线程
options.max_background_flushes = 4;
options.max_background_compactions = 8;

// 3. 调整MemTable配置
options.max_write_buffer_number = 6;
options.min_write_buffer_number_to_merge = 2;

四、读取问题 #

4.1 读取速度慢 #

问题现象:

  • 读取延迟高
  • 读取吞吐下降

诊断步骤:

cpp
// 检查缓存命中率
auto stats = db->GetOptions().statistics;
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);

// 检查L0文件数
uint64_t l0_files;
db->GetIntProperty("rocksdb.num-files-at-level0", &l0_files);

解决方案:

cpp
// 1. 增加Block Cache
rocksdb::BlockBasedTableOptions table_options;
table_options.block_cache = rocksdb::NewLRUCache(4 * 1024 * 1024 * 1024);

// 2. 启用布隆过滤器
table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));

// 3. 减少L0文件
options.level0_file_num_compaction_trigger = 4;

4.2 读取错误 #

问题现象:

text
Error: Corruption: block checksum mismatch

原因分析:

  • 数据块损坏
  • 磁盘错误

解决方案:

bash
# 1. 检查SST文件完整性
sst_dump --file=/path/to/file.sst --command=verify

# 2. 如果确认损坏,删除损坏文件
# 注意:会导致数据丢失
rm /path/to/corrupted_file.sst

# 3. 从备份恢复
ldb restore --db=/path/to/db --backup_dir=/path/to/backup

五、空间问题 #

5.1 空间持续增长 #

问题现象:

  • 磁盘空间持续增长
  • 数据量与预期不符

诊断步骤:

bash
# 检查各层文件大小
for i in {0..6}; do
    echo "Level $i:"
    ls -lh /path/to/db/*_$i.sst 2>/dev/null | awk '{sum+=$5} END {print sum}'
done

# 检查快照数量
ldb dump --db=/path/to/db --count_only

解决方案:

cpp
// 1. 手动触发Compaction
db->CompactRange(CompactRangeOptions(), nullptr, nullptr);

// 2. 释放快照
db->ReleaseSnapshot(snapshot);

// 3. 启用压缩
options.compression = rocksdb::CompressionType::kZSTD;

5.2 空间不足 #

问题现象:

text
Error: IO error: No space left on device

解决方案:

bash
# 1. 紧急清理空间
rm /path/to/db/*.log.old  # 删除旧日志

# 2. 触发Compaction
ldb compact --db=/path/to/db

# 3. 如果无法恢复,迁移数据
# 停止写入,复制到更大磁盘

六、性能问题 #

6.1 性能逐渐下降 #

问题现象:

  • 性能随时间下降
  • 延迟逐渐增加

诊断步骤:

cpp
// 监控关键指标
void DiagnosePerformance(rocksdb::DB* db) {
    uint64_t value;
    
    // L0文件数
    db->GetIntProperty("rocksdb.num-files-at-level0", &value);
    std::cout << "L0 files: " << value << std::endl;
    
    // 待Compaction
    db->GetIntProperty("rocksdb.estimate-pending-compaction-bytes", &value);
    std::cout << "Pending compaction: " << value / 1024 / 1024 << " MB" << std::endl;
    
    // MemTable数量
    db->GetIntProperty("rocksdb.num-immutable-mem-table", &value);
    std::cout << "Immutable MemTables: " << value << std::endl;
}

解决方案:

cpp
// 1. 定期Compaction
db->CompactRange(CompactRangeOptions(), nullptr, nullptr);

// 2. 调整配置
options.max_background_jobs = 16;
options.level0_file_num_compaction_trigger = 4;

// 3. 监控并预警

6.2 内存占用过高 #

问题现象:

  • 内存使用超出预期
  • 可能导致OOM

诊断步骤:

cpp
void DiagnoseMemory(rocksdb::DB* db) {
    uint64_t value;
    
    db->GetIntProperty("rocksdb.cur-size-all-mem-tables", &value);
    std::cout << "MemTable: " << value / 1024 / 1024 << " MB" << std::endl;
    
    db->GetIntProperty("rocksdb.block-cache-usage", &value);
    std::cout << "Block Cache: " << value / 1024 / 1024 << " MB" << std::endl;
    
    db->GetIntProperty("rocksdb.estimate-table-readers-mem", &value);
    std::cout << "Table Readers: " << value / 1024 / 1024 << " MB" << std::endl;
}

解决方案:

cpp
// 1. 减小MemTable
options.write_buffer_size = 32 * 1024 * 1024;
options.max_write_buffer_number = 2;

// 2. 减小Block Cache
table_options.block_cache = rocksdb::NewLRUCache(256 * 1024 * 1024);

// 3. 使用高压缩比
options.compression = rocksdb::CompressionType::kZSTD;

七、故障排查工具 #

7.1 日志分析 #

bash
# 查看RocksDB日志
tail -f /path/to/db/LOG

# 搜索错误
grep -i error /path/to/db/LOG
grep -i corruption /path/to/db/LOG
grep -i "write stall" /path/to/db/LOG

7.2 状态检查脚本 #

bash
#!/bin/bash
# diagnose_rocksdb.sh

DB_PATH=$1

echo "=== RocksDB Diagnosis ==="

# 检查文件数量
echo "File counts:"
echo "  SST files: $(ls $DB_PATH/*.sst 2>/dev/null | wc -l)"
echo "  WAL files: $(ls $DB_PATH/*.log 2>/dev/null | wc -l)"

# 检查磁盘使用
echo ""
echo "Disk usage:"
du -sh $DB_PATH

# 检查最近日志
echo ""
echo "Recent errors:"
grep -i error $DB_PATH/LOG 2>/dev/null | tail -10

echo ""
echo "=== Diagnosis Complete ==="

八、预防措施 #

8.1 监控告警 #

指标 阈值 告警级别
L0文件数 > 20 警告
L0文件数 > 30 严重
MemTable数量 > 6 警告
待Compaction > 10GB 警告
磁盘使用率 > 80% 警告

8.2 定期维护 #

bash
# 每日检查
0 0 * * * /path/to/health_check.sh /path/to/db

# 每周Compaction
0 2 * * 0 ldb compact --db=/path/to/db

# 每月备份
0 3 1 * * ldb backup --db=/path/to/db --backup_dir=/path/to/backup

九、最佳实践 #

9.1 故障预防 #

  1. 定期备份:设置自动备份
  2. 监控告警:配置关键指标告警
  3. 容量规划:预留足够空间
  4. 配置优化:根据场景优化配置
  5. 定期维护:执行定期维护任务

9.2 故障处理 #

  1. 保持冷静:不要盲目操作
  2. 收集信息:记录错误信息
  3. 分析原因:找到根本原因
  4. 制定方案:评估影响后实施
  5. 总结经验:记录处理过程

十、总结 #

10.1 常见问题速查 #

问题 可能原因 解决方案
打开失败 锁文件、WAL损坏 删除锁、设置恢复模式
写入慢 Compaction滞后 增加线程、调整配置
读取慢 缓存未命中 增加缓存、启用过滤器
空间增长 Compaction不足 手动Compaction
内存高 配置过大 减小缓存和MemTable

10.2 关键要点 #

  1. 监控先行:建立完善的监控体系
  2. 定期维护:执行定期维护任务
  3. 快速响应:及时处理告警
  4. 记录经验:积累处理经验
  5. 预防为主:做好预防措施

下一步,让我们学习最佳实践!

最后更新:2026-03-27