Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

对齐时间序列内存存储结构开发总结

Table of Contents

一、问题背景



某用户有这样的测试场景,模拟100万设备,每个设备包含27列测点,共2700万个测点,每个测点每秒采集1条数据,每个设备27个测点数据采集的时间戳完全相同。

...

同样,原有非对齐序列,需要对各个序列按时间单独排序。排序也仅需要对唯一的时间列进行排序,排序的工作量可降低至1/27。


二、方案设计


针对上述背景,优化的主要思路为对多个时间戳相同的时间序列只存储一个时间戳列。为此分别设计了如下几种方案。


方案1: 行式存储(Object)


  1. 将一行对齐的时间序列(Vector)作为一个measurement,写入memtable时一行Aligned Timeseries为一个时间戳加一个TsPrimitiveType类的数组。
  2. 内存控制模块在写入前根据Vector每个子项的数据类型检查内存增量,进行内存统计
  3. PrimitiveArrayManager增加Vector类的数组统计,类似目前TEXT类型的管理,只统计统计 TsPrimitiveType数组 的引用
  4. 新增VectorTVList,结构为一个long型时间戳数组和一个Object类型数组

...

  1. 写入Memtable时将放入VectorTVList中,VectorTVList在扩容时向PrimitiveArrayManager申请。
  2. VectorTVList的其他接口参考BinaryTVList;
  3. Flush时,按时间戳进行排序,再按行遍历时间戳和每个value,将这一行数据传给TsFile的ChunkWriter进行encoding。


方案2: 列式存储(Primitive Array)


  1. 将对齐时间序列的内存结构作为一组PrimitiveArray的合集(时间列、索引列和多个值列);
  2. 内存控制模块在写入前根据Vector每个子项的数据类型检查是否需要向PrimitiveArrayManager申请新增Array,进行内存统计;
  3. 新增VectorTVList,结构为一个long型时间Array和多个其他类型Array,同时每列维护bitmap用来记录空值, 和一个int 类型数组记录各个值列的rowIndex。bitmap默认为空指针,当客户端传入空值(insertRecord)或者传入代表空值的bitmap(insertTablet)时再创建出来;
  4. 写入Memtable时,将insertPlan里的值放入VectorTVList中,VectorTVList在扩容时需向PrimitiveArrayManager申请需要的Array类型;
  5. VectorTVList排序时只需要排时间列和rowIndex列;
  6. Flush时,按时间戳进行排序时间戳列和rowIndex列,之后的遍历方式为先找到一个时间戳,和对应的rowIndex,再根据rowIndex和bitMap找到各个值列对应的真实值和是否为null,将这一行数据传给TsFile的ChunkWriter进行encoding。

...

  1. Flush时,按时间戳进行排序时间戳列和rowIndex列,之后的遍历方式为先找到一个时间戳,和对应的rowIndex,再根据rowIndex和bitMap找到各个值列对应的真实值和是否为null,将这一行数据传给TsFile的ChunkWriter进行encoding。 

方案3: 行式存储(bytes版)


  1. 将一行Vector作为一个measurement,写入memtable时,一行Vector为一个时间戳和多个值序列化成的一个byte数组,同时使用bitmap记录每一行的空值情况。
  2. 内存控制模块在写入前根据Vector每个子项的数据类型检查内存增量,进行内存统计
  3. 新增VectorTVList,结构为一个long型时间戳数组和一个bytes数组,每行维护一个bitmap记录空值
  4. PrimitiveArrayManager增加Vector类的数组统计,类似目前TEXT类型管理,只统计 byte数组的引用;
  5. 写入Memtable后放入VectorTVList中,VectorTVList在扩容时向PrimitiveArrayManager申请;
  6. VectorTVList的其他接口参考BinaryTVList
  7. Flush时,按时间戳进行排序,再按行遍历时间戳并将对应的bytes值反序列化成具体的值,将这一行数据传给TsFile的ChunkWriter进行encoding。


三、方案评估


方案1行式存储优点 :


  1. 对null友好,无需维护bitmap记录空值
  2. 排序逻辑与现有其他类型完全相同,排序时会实际更新值列

...

  1. 需要编码解码来读取数据,效率低下
  2. 不能复用ArrayPool管理内存
  3. 对空值不友好
  4. 对TEXT类型的数据不友好,需要找到bytes 中对应的offset和length来读取


四、实验验证

 

1.目标

比较行式和列式存储在排序和遍历功能上的时间开销,以及存储的性能开销

...

结论:方案二列式存储与方案三行式存储(bytes版)在排序和查询过程的耗时基本相同。但在写入过程中,方案三行式存储为方案二耗时的4倍。因此,方案二的性能更符合要求。


五、最终结论


经综合比较,由于方案一内存浪费过大,方案三写入耗时较高、性能较差,最终选择方案二列式存储方案作为Vector数据类型内存存储结构。

...