TDengine 存储引擎剖析:数据文件与索引设计(一)

news2025/4/19 4:25:39

TDengine 存储引擎简介

在物联网、工业互联网等快速发展的今天,时间序列数据呈爆发式增长。这些数据具有产生频率高、依赖采集时间、测点多信息量大等特点,对数据存储和处理提出了极高要求。TDengine 作为一款高性能、分布式、支持 SQL 的时序数据库,应运而生,在众多领域得到了广泛应用。其卓越的性能很大程度上得益于精心设计的存储引擎,该存储引擎针对时序数据的特性进行了深度优化,能够高效地处理海量时间序列数据的存储与查询,为相关应用提供了强大的数据支持 。

TDengine 数据文件设计

数据文件结构剖析

TDengine 的数据文件采用了独特的四位一体的文件组结构,这种设计是其高效存储和快速查询的关键。每个文件组包含 .data、.last(在 3.0 版本中已更名为 .stt 文件 )、.head 和 .sma 这四类文件,它们各自承担着不同的职责,相互协作,共同完成数据的存储与管理。

.data 文件是核心的数据存储文件,它以列存储的方式存放实际的时序数据。这些数据被划分为多个数据块,每个数据块仅属于一张表,这使得数据的存储和读取更加高效。例如,在一个物联网场景中,众多传感器产生的数据会分别存储在各自对应的表的数据块中,这样在查询某个传感器的数据时,可以直接定位到相应的数据块,减少了数据扫描的范围。同时,每个数据块还记录着预计算中的行数数据,也就是预计算中的 count 函数计算结果,这为一些统计查询提供了便利。

.stt 文件(3.0 前为 .last 文件)主要用于保存每一张表从内存落盘到磁盘时的碎片数据,即小于 minrows 的数据。在 2.x 版本中,.last 文件存在一些局限性,比如当文件小于 32k 时,即便其中某表的碎片数据已满足行数要求可合并到 .data 文件,.last 文件也只是追加写入,不会清理这部分数据。而在 3.0 版本中,.stt 文件有了改进,属于同一个超级表的数据会存储在同一个数据块中,且数据块中的数据按照 (uid(表的唯一标识), timestamp, version)递增排列。每次落盘,数据文件组都会生成一个新的 stt 文件,用来存放本次落盘中的散碎数据。当 .stt 文件个数超过一定的阈值 (由建库参数 stt_trigger 控制),则首先将多个 .stt 文件的碎片数据合并后,再根据实际情况决定写入 .data 文件,或写入新的 .stt 文件中。这一改进有效减少了文件碎片化对性能的影响。

.head 文件存储着 .data 文件中数据块的索引信息。在查询时,系统会先加载 .head 文件中的索引信息,通过这些索引可以快速定位到 .data 文件中对应的时序数据,从而返回给用户。BRIN 索引(Block Range Index)在其中发挥了重要作用,它适用于具有天然顺序的数据集,由于不需要再做排序,资源耗费少,非常契合时序数据的查询特点。例如,当查询某个时间段内的数据时,.head 文件中的索引可以帮助系统迅速确定包含该时间段数据的数据块在 .data 文件中的位置,大大提高了查询效率。但需要注意的是,.head 文件的大小会影响查询性能,maxrows 和 minrows 以及 duration 等参数都会对其大小产生影响。比如,同样 1000 行数据,maxrows = 200 需要 5 个数据块,maxrows 为 1000 时只需要 1 块,而每个数据块都需要一条索引信息存储在 .head 文件中;duration 越大,单个数据文件存储的数据量越大,数据块越多,.head 文件也会越大。在实际应用中,曾出现过因 duration 参数设置为 1000 多天,导致数据查询性能严重下降的情况 。

.sma 文件存储着数据块中每列数据的预计算数据。预计算的目的是为了加速查询,尽可能避免从硬盘中读取原始数据。.sma 文件相当于 2.x 后期版本中的 smad 文件,而 smal 文件在 3.0 版本中被移除。通过预计算,在进行一些聚合查询时,如 sum、max、min 等操作,可以直接从 .sma 文件中获取结果,而无需读取大量的原始数据,从而提高了查询速度。

为了更直观地理解,以下是 TDengine 数据文件结构的示意图:

数据写入流程与分区策略

TDengine 的数据写入流程涉及从内存到硬盘的多个步骤,并且采用了基于建库参数 duration(days) 的数据分区策略,这对数据管理和查询有着重要影响。

当数据到达 TDengine 时,首先会被写入内存中的 Vnode Buffer。在这个阶段,数据会按照表进行组织,并在内存中以跳表(skiplist)结构进行索引,以便快速定位和处理。同时,为了保证数据的持久性和一致性,数据也会被写入预写式日志(WAL,Write-Ahead Log)中。WAL 记录了数据到达数据库的顺序,在系统出现故障时,可以通过 WAL 进行数据恢复,确保数据不丢失。

当内存中的数据量达到一定阈值或者满足特定的时间条件时,数据会触发落盘操作,从内存写入硬盘的数据文件中。在落盘过程中,数据会根据建库时设置的 duration(days) 参数进行分区。假设某库 duration 设置为 10 日,那么从 1970 年 1 月 1 日 0 时起,每隔 10 天就会划分一个数据文件组。写入的数据时间戳归属于哪个时间范围,便会写入哪个数据文件组中,即每个数据文件组中都包含了固定时间范围内的数据。例如,2024 年 1 月 1 日到 1 月 10 日的数据会被写入一个数据文件组,1 月 11 日到 1 月 20 日的数据会被写入另一个数据文件组。这种分区策略使得数据的管理更加有序,在进行数据查询和删除时,可以快速定位到相应的数据文件组,提高了操作效率。比如,当需要查询 2024 年 1 月 5 日的数据时,系统可以直接定位到包含 1 月 1 日到 1 月 10 日数据的数据文件组,而无需遍历整个数据库。

在数据写入硬盘的数据文件时,会按照 .data 文件的结构要求,将数据划分为数据块进行存储。每个数据块只属于一张表,并且会记录相关的预计算信息。同时,如果存在小于 minrows 的碎片数据,会被写入 .stt 文件中,等待后续的合并和处理。

乱序数据处理机制

在时序数据库场景下,乱序数据是指时间戳不按照递增顺序到达数据库的数据。虽然在理想情况下,数据应该按照时间顺序依次到达,但在实际应用中,由于各种原因,如设备损坏断电、网络异常、数据补录等,乱序数据的出现是不可避免的。TDengine 针对乱序数据进行了专门的处理,以保证数据存储时的顺序性和查询性能。

TDengine 将乱序数据分为两类:内存乱序数据和硬盘乱序数据。内存乱序数据是指在同一张表的范畴内,时间戳与内存数据的时间范围相交的数据。对于这类乱序数据,TDengine 会在内存中通过为每张表建立一个跳表结构做好排序。例如,创建某表后,先写入了从 1970 年到 2023 年的一小批数据(由于数据量较少不足以触发落盘),当再写入一条 1998 年时间戳的乱序数据时,跳表会对其进行排序,使得数据在内存中以 “1970 - 1998 - 2023” 的顺序有序存在。该排序操作的成本由写入操作承担,但由于内存中保留的只是极少数数据,因此对整体性能影响极小。

硬盘乱序数据是指在同一张表的范畴内,时间戳与硬盘数据的时间范围相交的数据。在硬盘数据写入时,由于 TDengine 通过建库参数 duration(days) 做数据分区,每个数据文件组包含固定时间范围内的数据。当数据落盘时,会根据其时间戳判断所属的数据文件组,并与该数据文件组中已有的数据块的时间范围进行比较,来判断数据是否乱序。例如,假设某表的数据文件组按照 10 天进行分区,当一条数据落盘时,如果其时间戳与当前数据文件组中已有数据块的时间范围没有交集,那么它就是正常数据;如果有交集,则可能是乱序数据。

在 2.0 版本中,如果落盘时的数据和已有数据块时间戳相交,乱序数据会形成一个子块追加在数据文件中,查询时需要把子块的数据读到内存中再做排序。当子块比较多的时候,会影响查询性能。而在 3.0 版本中,经过重新设计,乱序数据和原有数据将会合并重写为新的数据块,以追加的方式写入数据文件中并且重写索引,而旧的数据块则被视为碎片文件。这样一来,处理数据的成本就被转嫁给了落盘操作,对后续的查询基本没有影响。考虑到乱序数据通常是业务上的偶发场景,这种处理方式基本不会造成性能负担。即便是产生了少部分由于乱序带来的碎片数据、无效数据块,也都可以由企业版功能 compact 清除或者重组 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2337703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringBoot+Vue自学笔记】001

跟着这位老师学习的:https://www.bilibili.com/video/BV1nV4y1s7ZN?vd_sourceaf46ae3e8740f44ad87ced5536fc1a45 前后端开发技术的全栈课程: Java EE企业级框架:SpringBootMyBatisPlus Web前端核心框架:VueElement UI 公共云…

第十节:性能优化-如何排查组件不必要的重复渲染?

工具:React DevTools Profiler 方法:memo、shouldComponentUpdate深度对比 React 组件性能优化:排查与解决重复渲染问题指南 一、定位性能问题:React DevTools 高级用法 使用 React Developer Tools Profiler 精准定位问题组件&…

MATLAB项目实战(一)

题目: 某公司有6个建筑工地要开工,每个工地的位置(用平面坐标系a,b表示,距离单位:km)及水泥日用量d(t)由下表给出.目前有两个临时料场位于A(5,1),B(2,7),日储…

spring boot 文件下载

1.添加文件下载工具依赖 Commons IO is a library of utilities to assist with developing IO functionality. <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version> </depe…

微服务链路追踪:SleuthZipkin

文章目录 Sleuth & Zipkin一、Sleuth\&Zipkin介绍二、搭建环境三、Sleuth入门操作四、Zipkin搭建及操作五、RabbitMQ方式发送信息六、Elasticsearch持久化 SpringBootAdmin一、Actuator介绍二、Actuator快速入门三、SpringBootAdmin介绍四、SpringBootAdmin快速入门4.1…

java面试篇 4.9(mybatis+微服务+线程安全+线程池)

目录 mybatis&#xff1a; 1、mybatis的执行流程 2、mybatis是否支持延迟加载&#xff1f; 当我们需要去开启全局的懒加载时&#xff1a; 3、mybatis的一级和二级缓存 微服务 1、springcloud五大组件有哪些 2、服务注册和发现是什么意思&#xff1f;springcloud如何实现…

基于电子等排体的3D分子生成模型 ShEPhERD - 评测

一、背景介绍 ShEPhERD 是一个由 MIT 开发的一个 3D 相互作用感知的 ligand-based的分子生成模型&#xff0c;以 arXiv 预印本的形式发表于 2024 年&#xff0c;被ICLR2025 会议接收。文章链接&#xff1a;https://openreview.net/pdf?idKSLkFYHlYg ShEPhERD 是一种基于去噪扩…

GR00T N1:面向通用类人机器人的开放基础模型

摘要 通用型机器人需要具备多功能的身体和智能的大脑。近年来&#xff0c;类人机器人的发展在构建人类世界中的通用自主性硬件平台方面展现出巨大潜力。一个经过大量多样化数据源训练的机器人基础模型&#xff0c;对于使机器人能够推理新情况、稳健处理现实世界的多变性以及快…

QT简单实例

QT简单实例 QT简单实例一&#xff1a;通过拖动创建1.创建工程2.拖动控件实现响应3.文件目录3.1 TestQDialog.pro3.2 main.cpp3.3 dialog.h3.4 dialog.cpp 二&#xff1a;通过动态创建1.创建工程2.文件目录2.1 TestQDialogSelf.pro2.2 main.cpp2.3 dialog.h2.4 dialog.cpp QT简单…

Linux:初学者的简单指令

文章目录 pwd&#xff08;Print working directory&#xff09;whoamilsmkdir ~~cd ~~touch ~~rm ~~ 充当后端服务,我们用xshell工具来进行操作 其中Linux文件是/目录/目录/目录或文件/来表示的&#xff08;其中目录可以看作是windows操作系统的文件夹&#xff0c;只是Linux中…

端侧大模型综述On-Device Language Models: A Comprehensive Review

此为机器翻译&#xff0c;仅做个人学习使用 设备端语言模型&#xff1a;全面回顾 DOI&#xff1a;10.48550/arXiv.2409.00088 1 摘要 大型语言模型 &#xff08;LLM&#xff09; 的出现彻底改变了自然语言处理应用程序&#xff0c;由于减少延迟、数据本地化和个性化用户体验…

python实现音视频下载器

一、环境准备 确保当前系统已安装了wxPython 、 yt-dlp 和FFmpeg。当前主要支持下载youtube音视频 1、安装wxPython pip install wxPython2、安装yt-dp pip install wxPython yt-dlp3、安装FFmpeg 在Windows 10上通过命令行安装FFmpeg&#xff0c;最简便的方式是使用包管理…

三、小白如何用Pygame制作一款跑酷类游戏(按键图片和距离的计算)

三、小白如何用Pygame制作一款跑酷类游戏&#xff08;实现移动距离的计算&#xff0c;以及按键指引的添加&#xff09; 文章目录 三、小白如何用Pygame制作一款跑酷类游戏&#xff08;实现移动距离的计算&#xff0c;以及按键指引的添加&#xff09;前言一、创建字体文件夹1.可…

H5:实现安卓和苹果点击下载App自动跳转到对应的应用市场

一、需求场景 手机扫描下载App&#xff0c;需要根据不同手机自动跳转到对应的应用市场&#xff08;商店&#xff09;里&#xff0c;苹果手机直接打开App Store里指定的app页面&#xff0c;安卓手机如果是海外用户则打开GooglePlay 商店里指定的app页面&#xff0c;国内直接下载…

【Linux】文件传输归档与压缩

目录 配置实验环境 文件传输方法--scp&#xff0c;rsync scp rsync 归档与压缩--tar&#xff0c;gz&#xff0c;bz2&#xff0c;xz&#xff0c;zip 归档---tar 压缩 zip gzip bzip2 xz 归档并压缩 gz bz2 xz 拓展du 配置实验环境 在多个linux系统进行系统传输…

3D人脸扫描技术如何让真人“进入“虚拟,虚拟数字人反向“激活“现实?

随着虚拟人技术的飞速发展&#xff0c;超写实数字人已经成为数字娱乐、广告营销和虚拟互动领域的核心趋势。无论是企业家、知名主持人还是明星&#xff0c;数字分身正在以高度还原的形象替代真人参与各类活动&#xff0c;甚至成为品牌代言、直播互动的新宠。 3D人脸扫描&#…

Git标签的认识

Git标签完全指南&#xff1a;从基础到企业级发布策略 前言 在软件发布领域&#xff0c;Git标签是版本管理的基石。根据2023年GitHub年度报告显示&#xff0c;85%的开源项目使用标签进行版本控制。然而&#xff0c;许多开发者仅停留在git tag的基础使用层面&#xff0c;未能充分…

【Rust基础】使用Rocket构建基于SSE的流式回复

背景 我们正在使用Rust开发基于RAG的知识库系统&#xff0c;其中对于模型的回复使用了常用的SSE&#xff0c;Web框架使用Rocket&#xff0c;Rocket提供了一个简单的方式支持SSE&#xff0c;但没有会话保持、会话恢复等功能&#xff0c;因此我们自己简单实现这两个功能。 使用R…

大前端基础学习

一、cs架构和bs架构 c&#xff1a;客户端&#xff0c; b&#xff1a;浏览器&#xff08;无需安装&#xff0c;无需更新&#xff0c;可跨平台&#xff09;√ s&#xff1a;server服务端&#xff0c;帮我们保 存信息&#xff0c;传递信息 二、 altshift向下键向下复制一行 …

Axios 的 POST 请求:QS 处理数据的奥秘与使用场景解析

在现代前端开发中&#xff0c;Axios 已经成为了进行 HTTP 请求的首选库之一&#xff0c;它的简洁易用和强大功能深受开发者喜爱。当使用 Axios 进行 POST 请求时&#xff0c;我们常常会遇到一个问题&#xff1a;是否需要使用 QS 库来处理请求数据&#xff1f;什么时候又可以不用…