...
- 一个insertPlan写入完成后,检查该TSP的 workingMemtable 的 shouldFlush 字段,如果为 true,再检查是否TsFile大小超过阈值,如果超过,flush memtable后将文件封口。
- TsFile关闭完成后,清空该TSPInfo,重置对应的 SGInfo 状态,并向SystemInfo报告重置后SGInfo
- 如果此时SystemInfo 为reject状态 且 `SystemInfo中统计的总内存 < 总写入内存 * reject_proportion`,将SystemInfo 置于正常状态
- 如果`SystemInfo 总内存 >= 总写入内存 * 50%`,触发即时flush
MTree内存控制:
注册时间序列时,如果总时间序列个数*300 estimate_series_size > 总内存*0.1,此时拒绝注册,抛出异常。write_read_schema_free_memory_proportion:schema,此时拒绝注册,抛出异常。
细节:关于Array Pool中分类型的数组如何管理?
...
TsFile封口时,更新ChunkMetadata和Resource的内存统计并上报给System
Historical Resource 设计
采用二级索引的方式来降低TsFileResource常驻内存的数量,进而控制内存使用。
rootFile: 记录是<device, [starttime, endTime, IndexFile]>,是TsFileResource的根索引,常驻内存
IndexFile:记录是<device, [starttime, endTime, TsFileRecource]>, 是TsFileResource的中间索引,固定大小,按需load进内存
TsFileResource:记录是<device, starttime, endTime>, 是TsFile的索引,按需load进内存
写入
TsFile关闭时,unsealed_resource刷入磁盘;维护IndexFile,将涉及的各device的tsfile resource都进行记录。
如果IndexFile文件大于阈值(1GB)了,就进行关闭持久化到磁盘上,并开启一个新的IndexFile用于记录下一批TsFileResource中间索引。IndexFile关闭时,往rootFile里继续写一批记录,将涉及的各device的 index file都进行记录。
细节:rootFile也过大怎么办?
解法:多级索引(缺点,一次查询过多次访问磁盘);或者在rootFile中忽略一些device(缺点是这些设备的查询需要逐个去扫描indexFile)
...
估算下一个rootFile可以索引多少个TsFileResource。
假设:
1个storage group,每个设备100个测点,每个storage group 51200个设备, 也就是5.12e6个测点
内存128GB
Tsfile 512MB
IndexFile是1GB
每条ResourceIndex 100B,一个IndexFile是1GB,可以记录1GB/100B=10240000条记录,也就是200个TsFileResource。
每个rootFile在一个IndexFile关闭时会记录一下,也是51200*100B=5.12MB
也就是200个TsFileResource会产1GB的IndexFile和5.12MB的rootFile
100T的磁盘空间,有100T/512MB=100000个TsFile,需要100000/200 * 1GB = 500GB IndexFile,100000/200*5.12MB= 2.56GB内存
假设一个storage group A个设备,一个设备D个测点, 总共就是A * D个测点
假设每次TsFile刷写会造成所有设备的索引更新,就会产生A * 100B 的IndexFile记录
一个IndexFile假设是 C GB, 那一个IndexFile能支持 C * 1000,000,000 / A * 100 = C * 10,000,000/A 个TsFile的刷写
IndexFile关闭时,也会在RootFile里记录下A * 100B的rootFile记录
也就是C * 10,000,000/A 个TsFile的刷写,会有C GB的IndexFile产生, 还有A * 100B的rootFile记录
假设整个数据库有S个 Storage group,那么常驻内存的就是 S * (rootfile + C GB)
A 平均一个storage group 设备数
D 平均一个设备测点数
C IndexFile文件大小,单位是GB
512MB TsFile大小
rootFile = C * 10,000,000/A * 100B
IndexFile= C GB
磁盘空间= C * 10,000,000/A * 512MB
测点=A * D
该估算有个问题就是对于TsFileName长度可以进行优化,可以只消耗Tsfile个数的TsFilename长度内存占用,而不是device * [starttime, endTime] * tsFile个数来估算,因此其内存占用估算放大了很多倍。
这个优化的前提是java的string 常量池,可以保证多个string公用一个字符串常量。
因此,限制一个StorageGroup的设备数是可以做到只使用(2.56GB+1GB)/128GB~ 3%的内存索引100TB的磁盘空间。
读取流程
- 查找常驻内存的rootFile,找到对应的device的记录,根据startTime和endTime,找到对应的IndexFile。
- load IndexFile进内存,找到对应的device的记录,根据startTime和endTime,找到对应的TsFile。
- load TsFile在内存中构造TsFileResource
merge流程
TsFile会定期的跟乱序文件进行合并,因此其名字和元数据也会进行更新。
对于新生成的TsFile,也需要往IndexFile里写入记录即<device, ResourceIndexs>, 但是这个会造成有多个indexFile里某条device的记录区间有重叠的情况。
例如有IndexFile1记录的device, 10, 200, Tsfile1, merge后,新的indexFile2记录device, 10,400, tsFile2。
这两条记录都会在rootFile里进行记录,查询的时候需要读取两个IndexFile,但是IndexFile1里的TsFile1找不到了,那就不再查找。只找IndexFile2里的TsFile2.
这里会多读一次文件,为了减少这种无效的索引干扰,可以在merge 数据结束后进行一下相关IndexFile的合并操作,尽量保证一个device的一个时间区间在一个IndexFile里。
cache优化
...
文档原链接: https://shimo.im/docs/CWxXTDhvkRrHvXPx