背景
TsFileResource 会随着数据写入不断生成,当 TsFileResource 中的时间索引粒度较细,单个 TsFileResource 可能包含数十万设备的时间索引条目,大小可到几十M,在有限内存管理海量设备时,将 TsFileResource 全部驻留内存有 OOM 风险。
此外,在系统重启时,所有的TsFileResource都需要load到内存中一遍。
因此,TsFileResource 不能全部驻留在内存中,需要设计以下内容:
结构设计:
- TsFileResource 和 TsFile 的对应关系?(1对1,1对多)
- TsFileResource 的时间索引粒度?
缓存机制设计:
- 将哪些 TsFileResource 放在内存里?
- 内存中的 TsFileResource 何时踢出?
- 查询时如何将未缓存在内存的 TsFileResource 加载进内存?
目标场景
方案1 & 方案2
总体目标
- 引入一个全局的TsFileResourceManager,管理TsFileResource,将最近的 TsFileResource 缓存在内存,踢出老文件
当前TsFileResource的层级关系
存储组 → 虚拟存储组 → 分区号 → List<TsFileResource> 统一管理 TsFileResource
方案1
每关闭一个 TsFileResource 时,计算其内存,内存达到设置的阈值后,将最不活跃的分区的整个 List<TsFileResource> 清空
当需要一个分区的文件时,到磁盘上 listFiles,将该分区加载进来
方案2
主要思想:假设使用 FILE_TIME_INDEX 没有内存问题。根据内存动态切换 FILE_TIME_INDEX 和 DEVICE_TIME_INDEX。
TsFileManagement 中按照 存储组 → 虚拟存储组 → 分区号 → List<TsFileResource> 管理 TsFileResource。
将 TsFileResource 抽为接口,两个实现类,ClosedTsFileResource,UnclosedTsFileResource
引入 TsFileResourceManager,根据 List<TsFileResource> 统一管理 TsFileResource 引用。
每关闭一个 TsFileResource 时,将其内存统计入 TsFileResourceManager 里。
缓存策略中:
踢出一个 TsFileResource 的操作为:将 TsFileResource 中的 TimeIndex 改为 FILE_TIME_INDEX。
方案3
保持现有的 TIME_INDEX 不变,每个存储组保留固定个 TsFileResource,当总内存超过阈值,就将 TsFileResource 合并。可以应用多种合并策略。
例:
File1
root.sg.d1.s1, 1, 10
root.sg.d1.s2, 1, 10
File2
root.sg.d2.s1, 1, 10
root.sg.d1.s2, 11, 20
合并后:
File1, File2
root.sg.d1.s1, 1, 10
root.sg.d2.s1, 1, 10
root.sg.d1.s2, 1, 20