RocksDB WAL文件实际内容少但磁盘占用高的原因及优化方法
RocksDB WAL文件磁盘占用异常:原因分析与解决方案
问题现象
某RocksDB实例总磁盘占用约75M,其中WAL文件000006.log被du命令统计为占用71M,但ls -lh显示该文件实际仅40字节;手动复制该文件后,du显示新文件的磁盘占用降至4K。
一、异常原因
这是文件系统磁盘块未回收导致的,核心逻辑如下:
ls -lh显示的是文件的逻辑大小(即当前文件的有效数据长度),这里的40字节表示文件当前只有40字节的实际内容。du统计的是文件实际占用的物理磁盘块数,显示71M说明该文件曾经被分配过71M的磁盘空间——可能是之前写入过大量数据,或者RocksDB预分配了空间,之后文件被截断到40字节,但文件系统没有立即释放多余的磁盘块。- 手动复制文件时,只会复制文件中实际有数据的部分,新文件仅占用对应大小的磁盘块(4K为文件系统默认块大小),原文件的闲置磁盘块需要等到文件被删除、覆盖写入,或文件系统执行空间回收后才会被释放。
二、降低WAL文件磁盘占用的方案
1. 调整RocksDB配置
- 限制WAL总大小:设置
Options.max_total_wal_size,当WAL文件总大小超过该阈值时,RocksDB会自动删除旧的WAL文件。 - 控制单个WAL大小:通过
Options.max_wal_size设置单个WAL文件的最大容量,避免单个文件过大。 - 按需关闭WAL:如果业务可以容忍少量数据丢失(如测试环境),在
WriteOptions中设置disableWAL = true,写入操作将不生成WAL文件。 - 启用自动清理:确保
Options.wal_dir配置正确,RocksDB会自动清理不再需要的归档WAL文件。
2. 手动回收磁盘空间
- 对异常WAL文件执行备份-删除-还原操作:先复制文件到临时位置,删除原文件,再将备份文件复制回去,文件系统会自动回收闲置磁盘块。
- 使用
fallocate命令(支持XFS/EXT4等文件系统):执行fallocate -d 000006.log,直接释放文件中的空洞区域对应的磁盘块。
3. 确保RocksDB正常关闭
程序退出时必须调用db->Close()和delete db,让RocksDB完成WAL文件的清理、截断等收尾工作,避免异常关闭导致的磁盘空间残留。
4. 选择合适的文件系统
优先使用XFS、EXT4这类对文件空间回收效率更高的文件系统,减少磁盘块残留的概率。
相关命令输出
du -h * 输出
4.0K 000004.sst 71M 000006.log 4.0K CURRENT 4.0K IDENTITY 0 LOCK 128K LOG 128K LOG.old.1669987718576391 4.0M MANIFEST-000005 8.0K OPTIONS-000005 8.0K OPTIONS-000008
ls -lh 输出
-rw-r--r--. 1 polaris polaris 966 Dec 2 18:58 000004.sst -rw-r--r--. 1 polaris polaris 40 Dec 2 18:58 000006.log -rw-r--r--. 1 polaris polaris 16 Dec 2 18:58 CURRENT -rw-r--r--. 1 polaris polaris 37 Dec 2 18:57 IDENTITY -rw-r--r--. 1 polaris polaris 0 Dec 2 18:57 LOCK -rw-rw-r--. 1 polaris polaris 16K Dec 2 18:58 LOG -rw-rw-r--. 1 polaris polaris 15K Dec 2 18:57 LOG.old.1669987718576391 -rw-r--r--. 1 polaris polaris 166 Dec 2 18:58 MANIFEST-000005 -rw-r--r--. 1 polaris polaris 4.5K Dec 2 18:57 OPTIONS-000005 -rw-r--r--. 1 polaris polaris 4.5K Dec 2 18:58 OPTIONS-000008
测试代码
#include <cassert> #include <string> #include <rocksdb/db.h> #include <iostream> using namespace std; int main(int argc, char** argv) { rocksdb::DB* db; rocksdb::Options options; options.create_if_missing = true; rocksdb::Status status = rocksdb::DB::Open(options, "/dev/shm/testdb", &db); assert(status.ok()); // Insert value status = db->Put(rocksdb::WriteOptions(), "Test key", "Test value"); assert(status.ok()); // Read back value std::string value; status = db->Get(rocksdb::ReadOptions(), "Test key", &value); std::cout << value << '\n'; assert(status.ok()); assert(!status.IsNotFound()); // Read key which does not exist status = db->Get(rocksdb::ReadOptions(), "This key does not exist", &value); assert(status.IsNotFound()); }
内容的提问来源于stack exchange,提问作者Arindam Ghosh
相关产品推荐
相关产品推荐

