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 故障预防 #
- 定期备份:设置自动备份
- 监控告警:配置关键指标告警
- 容量规划:预留足够空间
- 配置优化:根据场景优化配置
- 定期维护:执行定期维护任务
9.2 故障处理 #
- 保持冷静:不要盲目操作
- 收集信息:记录错误信息
- 分析原因:找到根本原因
- 制定方案:评估影响后实施
- 总结经验:记录处理过程
十、总结 #
10.1 常见问题速查 #
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 打开失败 | 锁文件、WAL损坏 | 删除锁、设置恢复模式 |
| 写入慢 | Compaction滞后 | 增加线程、调整配置 |
| 读取慢 | 缓存未命中 | 增加缓存、启用过滤器 |
| 空间增长 | Compaction不足 | 手动Compaction |
| 内存高 | 配置过大 | 减小缓存和MemTable |
10.2 关键要点 #
- 监控先行:建立完善的监控体系
- 定期维护:执行定期维护任务
- 快速响应:及时处理告警
- 记录经验:积累处理经验
- 预防为主:做好预防措施
下一步,让我们学习最佳实践!
最后更新:2026-03-27