存储设计

TDengine的数据存储主要包含元数据的存储写入数据的存储。以下章节详细介绍了TDengine各种数据的存储结构。

元数据的存储

TDengine中的元数据信息包括TDengine中的数据库,表,超级表等信息。元数据信息默认存放在 /var/lib/taos/mgmt/ 文件夹下。该文件夹的目录结构如下所示:

  1. /var/lib/taos/
  2. +--mgmt/
  3. +--db.db
  4. +--meters.db
  5. +--user.db
  6. +--vgroups.db

元数据在文件中按顺序排列。文件中的每条记录代表TDengine中的一个元数据机构(数据库、表等)。元数据文件只进行追加操作,即便是元数据的删除,也只是在数据文件中追加一条删除的记录。

写入数据的存储

TDengine中写入的数据在硬盘上是按时间维度进行分片的。同一个vnode中的表在同一时间范围内的数据都存放在同一文件组中,如下图中的v0f1804*文件。这一数据分片方式可以大大简化数据在时间维度的查询,提高查询速度。在默认配置下,硬盘上的每个文件存放10天数据。用户可根据需要调整数据库的 daysPerFile 配置项进行配置。 数据在文件中是按块存储的。每个数据块只包含一张表的数据,且数据是按照时间主键递增排列的。数据在数据块中按列存储,这样使得同类型的数据存放在一起,可以大大提高压缩的比例,节省存储空间。TDengine对不同类型的数据采用了不同的压缩算法进行压缩,以达到最优的压缩结果。TDengine使用的压缩算法包括simple8B、delta-of-delta、RLE以及LZ4等。

TDengine的数据文件默认存放在 /var/lib/taos/data/ 下。而 /var/lib/taos/tsdb/ 文件夹下存放了vnode的信息、vnode中表的信息以及数据文件的链接等。其完整目录结构如下所示:

  1. /var/lib/taos/
  2. +--tsdb/
  3. | +--vnode0
  4. | +--meterObj.v0
  5. | +--db/
  6. | +--v0f1804.head->/var/lib/taos/data/vnode0/v0f1804.head1
  7. | +--v0f1804.data->/var/lib/taos/data/vnode0/v0f1804.data
  8. | +--v0f1804.last->/var/lib/taos/data/vnode0/v0f1804.last1
  9. | +--v0f1805.head->/var/lib/taos/data/vnode0/v0f1805.head1
  10. | +--v0f1805.data->/var/lib/taos/data/vnode0/v0f1805.data
  11. | +--v0f1805.last->/var/lib/taos/data/vnode0/v0f1805.last1
  12. | :
  13. +--data/
  14. +--vnode0/
  15. +--v0f1804.head1
  16. +--v0f1804.data
  17. +--v0f1804.last1
  18. +--v0f1805.head1
  19. +--v0f1805.data
  20. +--v0f1805.last1
  21. :

meterObj文件

每个vnode中只存在一个 meterObj 文件。该文件中存储了vnode的基本信息(创建时间,配置信息,vnode的统计信息等)以及该vnode中表的信息。其结构如下所示:

  1. <文件开始>
  2. [文件头]
  3. [表记录1偏移量和长度]
  4. [表记录2偏移量和长度]
  5. ...
  6. [表记录N偏移量和长度]
  7. [表记录1]
  8. [表记录2]
  9. ...
  10. [表记录N]
  11. [表记录]
  12. <文件结尾>

其中,文件头大小为512字节,主要存放vnode的基本信息。每条表记录代表属于该vnode中的一张表在硬盘上的表示。

head文件

head文件中存放了其对应的data文件中数据块的索引信息。该文件组织形式如下:

  1. <文件开始>
  2. [文件头]
  3. [表1偏移量]
  4. [表2偏移量]
  5. ...
  6. [表N偏移量]
  7. [表1数据索引]
  8. [表2数据索引]
  9. ...
  10. [表N数据索引]
  11. <文件结尾>

文件开头的偏移量列表表示对应表的数据索引块的开始位置在文件中的偏移量。每张表的数据索引信息在head文件中都是连续存放的。这也使得TDengine在读取单表数据时,可以将该表所有的数据块索引一次性读入内存,大大提高读取速度。表的数据索引块组织如下:

  1. [索引块信息]
  2. [数据块1索引]
  3. [数据块2索引]
  4. ...
  5. [数据块N索引]

其中,索引块信息中记录了数据块的个数等描述信息。每个数据块索引对应一个在data文件或last文件中的一个单独的数据块。索引信息中记录了数据块存放的文件、数据块起始位置的偏移量、数据块中数据时间主键的范围等。索引块中的数据块索引是按照时间范围顺序排放的,这也就是说,索引块M对应的数据块中的数据时间范围都大于索引块M-1的。这种预先排序的存储方式使得在TDengine在进行按照时间戳进行查询时可以使用折半查找算法,大大提高查询速度。

data文件

data文件中存放了真实的数据块。该文件只进行追加操作。其文件组织形式如下:

  1. <文件开始>
  2. [文件头]
  3. [数据块1]
  4. [数据块2]
  5. ...
  6. [数据块N]
  7. <文件结尾>

每个数据块只属于vnode中的一张表,且数据块中的数据按照时间主键排列。数据块中的数据按列组织排放,使得同一类型的数据排放在一起,方便压缩和读取。每个数据块的组织形式如下所示:

  1. [列1信息]
  2. [列2信息]
  3. ...
  4. [列N信息]
  5. [列1数据]
  6. [列2数据]
  7. ...
  8. [列N数据]

列信息中包含该列的类型,列的压缩算法,列数据在文件中的偏移量以及长度等。除此之外,列信息中也包含该内存块中该列数据的预计算结果,从而在过滤查询时根据预计算结果判定是否读取数据块,大大提高读取速度。

last文件

为了防止数据块的碎片化,提高查询速度和压缩率,TDengine引入了last文件。当要落盘的数据块中的数据条数低于某个阈值时,TDengine会先将该数据块写入到last文件中进行暂时存储。当有新的数据需要落盘时,last文件中的数据会被读取出来与新数据组成新的数据块写入到data文件中。last文件的组织形式与data文件类似。

TDengine数据存储小结

TDengine通过其创新的架构和存储结构设计,有效提高了计算机资源的使用率。一方面,TDengine的虚拟化使得TDengine的水平扩展及备份非常容易。另一方面,TDengine将表中数据按时间主键排序存储且其列式存储的组织形式都使TDengine在写入、查询以及压缩方面拥有非常大的优势。