存储numpy数组的RocksDB高速读写最优Options配置方案
存储对象基准大小计算
你当前待存储的单条numpy数组字节量为:10 * 512 * 512 * 4byte = 10MiB,属于典型的大Value KV存储场景,文档给的默认配置是针对KB级小KV优化的,直接套用会产生严重的读写放大,性能非常差。
读写速度优先的最优配置
直接上可运行的配置代码:
import rocksdb import numpy as np opts = rocksdb.Options() # 基础句柄配置 opts.create_if_missing = True opts.max_open_files = -1 # 注意:该参数单位是文件句柄数不是字节,设为-1表示不限制打开的SSTable句柄数,避免读时频繁开关文件 # 内存与刷盘配置 opts.write_buffer_size = 128 * 1024 * 1024 # 128MiB,为单条Value大小的12倍以上,避免单条记录跨Memtable opts.max_write_buffer_number = 4 # 无需设置过大,避免无意义的内存占用,4个Memtable足够支撑高并发写入 opts.target_file_size_base = 128 * 1024 * 1024 # 和写缓冲大小对齐,减少L0层文件数量,降低Compaction压力 # 后台线程配置 opts.max_background_compactions = 8 # 拉高后台Compaction线程数,避免Compaction积压阻塞前台读写 opts.max_background_flushes = 4 # 后台刷盘线程数和Memtable数量匹配 # 存储与读优化配置 opts.compression = rocksdb.CompressionType.no_compression # 关闭压缩:float32数组熵值极高,压缩率不足1.1倍,CPU开销远大于空间收益 opts.block_size = 256 * 1024 # 256KiB块大小,默认4KiB块适配小Value,大Value场景下大块可大幅降低块索引体积,减少寻址开销 opts.filter_policy = rocksdb.BloomFilter(10) # 开启10bit/key的布隆过滤器,避免随机读时遍历所有SSTable,随机读性能可提升5~10倍 # 内存富余时可添加以下配置开启8GiB块缓存,热点读直接走内存 # opts.block_cache = rocksdb.LRUCache(8 * 1024 * 1024 * 1024)
关键配置逻辑说明
- 不要沿用默认30个写缓冲的配置:大Value场景下30个128MiB的Memtable会占用近4GiB内存,完全没有必要,4个Memtable即可实现1个刷盘、2个接收前台写入、1个预留的流水线,足够覆盖绝大多数高并发写场景。
- write_buffer不要设得过大:超过256MiB后单次刷盘的IO量太大,反而会阻塞前台写入;也不要小于64MiB,不然单条10MiB的Value会频繁触发刷盘,写放大飙升。
- 不要开任何压缩:不管是LZ4还是ZSTD,对原始float32数组的压缩效果都极差,压缩解压的CPU开销会直接把读写吞吐量打下来,纯负优化。
- block_size不要超过512KiB:过大的块会导致块缓存命中率下降,256KiB是大Value场景下的经验最优值。
额外性能优化技巧
- 序列化/反序列化不要用pickle,直接调用数组原生方法:存的时候用
value = arr.tobytes(),取的时候用arr = np.frombuffer(value, dtype=np.float32).reshape(10,512,512),速度比pickle快10倍以上,没有额外字节开销。 - 批量写入必须用
WriteBatch,攒10100条记录一次性提交,比单条`put`快35倍;如果能接受进程崩溃时丢失最近1~2秒的写入,可以给写入配置加disable_wal=True,写性能还能再提升1倍左右。 - 批量读取尽量用迭代器顺序扫描,不要循环单条
get,顺序读的性能是随机单条读的10倍以上。
内容的提问来源于stack exchange,提问作者Foivos
相关产品推荐
相关产品推荐

