如何用RocksDb实现Windows桌面应用并发读写且重启不丢数据?
关于Zet Universe应用的嵌入式存储问题
应用概述
- 开发Windows桌面应用Zet Universe,支持多来源数据统一处理,通过插件获取外部数据源,内置可扩展管道运行多读写器处理数据
- 数据为JSON结构,代表不同时间实体,系统仅标记删除数据,不执行实际删除操作
- 应用启动时会获取所有键构建时空索引(Octree),并基于该索引查询当前时间对应的数据
过往存储方案尝试
近十年已尝试多种存储方案,均存在明显缺陷:
- SQL Compact:存储容量受限
- SQL Server:运行缓慢、体积笨重
- 文件系统:易遭杀毒软件拦截
- 多种KV数据库、Compound Files:未适配需求
- Redis(2016年起使用):关闭时
redis-server.exeshutdown速度过慢
当前RocksDB问题及实现细节
切换至嵌入式数据库RocksDB后,应用重启会丢失部分数据。已启用WAL、并发写入并调整并行度,问题仍未解决,相关实现细节如下:
初始化配置
由StorageContext类持有封装RocksDB操作的IStorageProvider实例,初始化时创建读写实例,配置代码:
// basic options var options = new DbOptions() .SetCreateIfMissing(true) .SetWalDir(this.StoreName) // using WAL .SetWalRecoveryMode(Recovery.AbsoluteConsistency) // setting recovery mode to Absolute Consistency .SetAllowConcurrentMemtableWrite(true) // concurrent writers .SetEnableWriteThreadAdaptiveYield(true) // required for concurrent writers .IncreaseParallelism(cpus / 2) // only half of all available threads .OptimizeLevelStyleCompaction(0); // opening db _readWriteRocksDbInstance = RocksDb.Open(options, this.StoreName);
索引构建与键查询异常
初始化后遍历所有键构建外部时空索引,查询时通过键从RocksDB获取数据。原本的StorageRecordExists方法(调用HasKey)每次执行都失败,已停用:
var result = false; var charSpan = storageKey.AsSpan(); var byteSpan = MemoryMarshal.Cast<char, byte>(charSpan); try { result =_readWriteRocksDbInstance.HasKey(byteSpan); } catch (Exception ex) { Log.Exception(ex); } return result;
写入与关闭逻辑
数据写入使用Put方法,应用关闭时先调用Flush再Dispose实例,且关闭阶段无写入操作:
数据写入方法
private bool InternalSaveStorageRecord(string recordName, string sJson) { bool result = false; try { _readWriteRocksDbInstance.Put(recordName, sJson); } catch (Exception ex) { Log.Exception(ex); } return result; }
Flush操作
private void InternalSave() { var options = new FlushOptions(); _readWriteRocksDbInstance.Flush(options); }
资源释放
// disposing this._readWriteRocksDbInstance.Dispose();
请求帮助
不确定RocksDB是否为适配需求的工具,请求解决当前数据丢失问题,或推荐合适的嵌入式存储方案。
内容的提问来源于stack exchange,提问作者Daniel Kornev
相关产品推荐
相关产品推荐

