如何建立自己的网站教程,90设计官方,wordpress登录后可见,哪个网站可以做c语言的题文章目录 [toc]一、集群与基本逻辑单元1.主要逻辑单元2.节点之间的通讯3.一个典型的消息流程 二、存储模型与数据分区、分片1.存储模型2.数据分片3.数据分区4.负载均衡 三、数据写入与复制流程1.Master Vnode 写入流程2.Slave Vnode 写入流程3.主从选择4.同步复制 四、缓存与持… 文章目录 [toc]一、集群与基本逻辑单元1.主要逻辑单元2.节点之间的通讯3.一个典型的消息流程 二、存储模型与数据分区、分片1.存储模型2.数据分片3.数据分区4.负载均衡 三、数据写入与复制流程1.Master Vnode 写入流程2.Slave Vnode 写入流程3.主从选择4.同步复制 四、缓存与持久化1.缓存2.持久化存储3.多级存储 五、数据查询1.单表查询2.按时间轴聚合、降采样、插值3.多表聚合查询4.预计算 六、数据模型1.物联网典型场景2.数据特征3.关系型数据库模型4.一个数据采集点一张表5.超级表同一类型数据采集点的集合 其他
一、集群与基本逻辑单元
TDengine 的设计是基于单个硬件、软件系统不可靠基于任何单台计算机都无法提供足够计算能力和存储能力处理海量数据的假设进行设计的。因此 TDengine 从研发的第一天起就按照分布式高可靠架构进行设计是支持水平扩展的这样任何单台或多台服务器发生硬件故障或软件错误都不影响系统的可用性和可靠性。同时通过节点虚拟化并辅以自动化负载均衡技术TDengine 能最高效率地利用异构集群中的计算和存储资源降低硬件投资。
1.主要逻辑单元
TDengine 分布式架构的逻辑结构图如下 图 1 TDengine架构示意图
一个完整的 TDengine 系统是运行在一到多个物理节点上的逻辑上它包含数据节点(dnode)、TDengine 应用驱动(taosc)以及应用(app)。系统中存在一到多个数据节点这些数据节点组成一个集群(cluster)。应用通过 taosc 的 API 与 TDengine 集群进行互动。下面对每个逻辑单元进行简要介绍。
物理节点(pnode) pnode 是一独立运行、拥有自己的计算、存储和网络能力的计算机可以是安装有OS的物理机、虚拟机或 Docker 容器。物理节点由其配置的 FQDN (Fully Qualified Domain Name)来标识。TDengine 完全依赖 FQDN 来进行网络通讯如果不了解 FQDN请看博文《一篇文章说清楚 TDengine 的 FQDN》。
数据节点(dnode) dnode 是 TDengine 服务器侧执行代码 taosd 在物理节点上的一个运行实例一个工作的系统必须有至少一个数据节点。dnode 包含零到多个逻辑的虚拟节点(vnode)零或者至多一个逻辑的管理节点(mnode)。dnode 在系统中的唯一标识由实例的 End Point (EP)决定。EP 是 dnode 所在物理节点的 FQDN (Fully Qualified Domain Name)和系统所配置的网络端口号(Port)的组合。通过配置不同的端口一个物理节点(一台物理机、虚拟机或容器可以运行多个实例或有多个数据节点。
虚拟节点(vnode) 为更好的支持数据分片、负载均衡防止数据过热或倾斜数据节点被虚拟化成多个虚拟节点(vnode图中 V2, V3, V4等)。每个 vnode 都是一个相对独立的工作单元是时序数据存储的基本单元具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表数据采集点。当创建一张新表时系统会检查是否需要创建新的 vnode。一个数据节点上能创建的 vnode 的数量取决于该数据节点所在物理节点的硬件资源。一个 vnode 只属于一个 DB但一个 DB 可以有多个 vnode。一个 vnode 除存储的时序数据外也保存有所包含的表的 schema、标签值等。一个虚拟节点由所属的数据节点的EP以及所属的 VGroup ID 在系统内唯一标识由管理节点创建并管理。
管理节点(mnode) 一个虚拟的逻辑单元负责所有数据节点运行状态的监控和维护以及节点之间的负载均衡(图中 M)。同时管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理因此也称为 Meta Node。TDengine 集群中可配置多个(最多不超过 3 个) mnode它们自动构建成为一个虚拟管理节点组(图中 M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成无需人工干预。每个 dnode 上至多有一个 mnode由所属的数据节点的EP来唯一标识。每个 dnode 通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。
虚拟节点组(VGroup) 不同数据节点上的 vnode 可以组成一个虚拟节点组(vnode group)来保证系统的高可靠。虚拟节点组内采取 master/slave 的方式进行管理。写操作只能在 master vnode 上进行系统采用异步复制的方式将数据同步到 slave vnode这样确保了一份数据在多个物理节点上有拷贝。一个 vgroup 里虚拟节点个数就是数据的副本数。如果一个 DB 的副本数为 N系统必须有至少 N 数据节点。副本数在创建DB时通过参数 replica 可以指定缺省为 1。使用 TDengine 的多副本特性可以不再需要昂贵的磁盘阵列等存储设备就可以获得同样的数据高可靠性。虚拟节点组由管理节点创建、管理并且由管理节点分配一个系统唯一的 IDVGroup ID。如果两个虚拟节点的 vnode group ID 相同说明他们属于同一个组数据互为备份。虚拟节点组里虚拟节点的个数是可以动态改变的容许只有一个也就是没有数据复制。VGroup ID 是永远不变的即使一个虚拟节点组被删除它的ID也不会被收回重复利用。
TAOSC taosc 是 TDengine 给应用提供的驱动程序(driver)负责处理应用与集群的接口交互提供 C/C 语言原生接口内嵌于 JDBC、C#、Python、Go、Node.js 语言连接库里。应用都是通过 taosc 而不是直接连接集群中的数据节点与整个集群进行交互的。这个模块负责获取并缓存元数据将插入、查询等请求转发到正确的数据节点在把结果返回给应用时还需要负责最后一级的聚合、排序、过滤等操作。对于 JDBC、C/C、C#、Python、Go、Node.js 接口而言这个模块是在应用所处的物理节点上运行。同时为支持全分布式的 RESTful 接口taosc 在 TDengine 集群的每个 dnode 上都有一运行实例。
2.节点之间的通讯
**通讯方式**TDengine 系统的各个数据节点之间以及应用驱动与各数据节点之间的通讯是通过 TCP/UDP 进行的。因为考虑到物联网场景数据写入的包一般不大因此 TDengine 除采用 TCP 做传输之外还采用 UDP 方式因为 UDP 更加高效而且不受连接数的限制。TDengine 实现了自己的超时、重传、确认等机制以确保 UDP 的可靠传输。对于数据量不到15K的数据包采取 UDP 的方式进行传输超过 15K 的或者是查询类的操作自动采取 TCP 的方式进行传输。同时TDengine 根据配置和数据包会自动对数据进行压缩/解压缩数字签名/认证等处理。对于数据节点之间的数据复制只采用 TCP 方式进行数据传输。
**FQDN配置**一个数据节点有一个或多个 FQDN可以在系统配置文件 taos.cfg 通过参数fqdn进行指定如果没有指定系统将自动获取计算机的 hostname 作为其 FQDN。如果节点没有配置 FQDN可以直接将该节点的配置参数 fqdn 设置为它的IP地址。但不建议使用 IP因为 IP 地址可变一旦变化将让集群无法正常工作。一个数据节点的 EP(End Point) 由 FQDN Port 组成。采用 FQDN需要保证 DNS 服务正常工作或者在节点以及应用所在的节点配置好 hosts 文件。另外这个参数值的长度需要控制在 96 个字符以内。
**端口配置**一个数据节点对外的端口由 TDengine 的系统配置参数 serverPort 决定对集群内部通讯的端口是 serverPort5。为支持多线程高效的处理 UDP 数据每个对内和对外的 UDP 连接都需要占用5个连续的端口。
集群内数据节点之间的数据复制操作占用一个 TCP 端口是 serverPort10。集群数据节点对外提供 RESTful 服务占用一个 TCP 端口是 serverPort11。集群内数据节点与 Arbitrator 节点之间通讯占用一个 TCP 端口是 serverPort12。
因此一个数据节点总的端口范围为 serverPort 到 serverPort12总共 13 个 TCP/UDP 端口。使用时需要确保防火墙将这些端口打开。每个数据节点可以配置不同的 serverPort。详细的端口情况请参见 TDengine 2.0 端口说明
**集群对外连接**TDengine 集群可以容纳单个、多个甚至几千个数据节点。应用只需要向集群中任何一个数据节点发起连接即可连接需要提供的网络参数是一数据节点的 End Point(FQDN加配置的端口号。通过命令行CLI启动应用 taos 时可以通过选项-h来指定数据节点的 FQDN, -P 来指定其配置的端口号如果端口不配置将采用 TDengine 的系统配置参数 serverPort。
**集群内部通讯**各个数据节点之间通过 TCP/UDP 进行连接。一个数据节点启动时将获取 mnode 所在的 dnode 的 EP 信息然后与系统中的 mnode 建立起连接交换信息。获取 mnode 的 EP 信息有三步
检查 mnodeEpSet.json 文件是否存在如果不存在或不能正常打开获得 mnode EP 信息进入第二步检查系统配置文件 taos.cfg获取节点配置参数 firstEp、secondEp这两个参数指定的节点可以是不带 mnode 的普通节点这样的话节点被连接时会尝试重定向到 mnode 节点如果不存在或者 taos.cfg 里没有这两个配置参数或无效进入第三步将自己的EP设为 mnode EP并独立运行起来。
获取 mnode EP 列表后数据节点发起连接如果连接成功则成功加入进工作的集群如果不成功则尝试 mnode EP 列表中的下一个。如果都尝试了但连接都仍然失败则休眠几秒后再进行尝试。
**MNODE的选择**TDengine 逻辑上有管理节点但没有单独的执行代码服务器侧只有一套执行代码 taosd。那么哪个数据节点会是管理节点呢这是系统自动决定的无需任何人工干预。原则如下一个数据节点启动时会检查自己的 End Point, 并与获取的 mnode EP List 进行比对如果在其中该数据节点认为自己应该启动 mnode 模块成为 mnode。如果自己的 EP 不在 mnode EP List 里则不启动 mnode 模块。在系统的运行过程中由于负载均衡、宕机等原因mnode 有可能迁移至新的 dnode但一切都是透明的无需人工干预配置参数的修改是 mnode 自己根据资源做出的决定。
**新数据节点的加入**系统有了一个数据节点后就已经成为一个工作的系统。添加新的节点进集群时有两个步骤第一步使用 TDengine CLI 连接到现有工作的数据节点然后用命令create dnode将新的数据节点的 End Point 添加进去; 第二步在新的数据节点的系统配置参数文件 taos.cfg 里将 firstEp, secondEp 参数设置为现有集群中任意两个数据节点的 EP 即可。具体添加的详细步骤请见详细的用户手册。这样就把集群一步一步的建立起来。
**重定向**无论是 dnode 还是 taosc最先都是要发起与 mnode 的连接但 mnode 是系统自动创建并维护的因此对于用户来说并不知道哪个 dnode 在运行 mnode。TDengine 只要求向系统中任何一个工作的 dnode 发起连接即可。因为任何一个正在运行的 dnode都维护有目前运行的 mnode EP List。当收到一个来自新启动的 dnode 或 taosc 的连接请求如果自己不是 mnode则将 mnode EP List 回复给对方taosc 或新启动的 dnode 收到这个 list, 就重新尝试建立连接。当 mnode EP List 发生改变通过节点之间的消息交互各个数据节点就很快获取最新列表并通知 taosc。
3.一个典型的消息流程
为解释 vnode、mnode、taosc 和应用之间的关系以及各自扮演的角色下面对写入数据这个典型操作的流程进行剖析。 图 2 TDengine 典型的操作流程
应用通过 JDBC 或其他API接口发起插入数据的请求。taosc 会检查缓存看是否保存有该表的 meta data。如果有直接到第 4 步。如果没有taosc 将向 mnode 发出 get meta-data 请求。mnode 将该表的 meta-data 返回给 taosc。Meta-data 包含有该表的 schema, 而且还有该表所属的 vgroup信息vnode ID 以及所在的 dnode 的 End Point如果副本数为 N就有 N 组 End Point)。如果 taosc 迟迟得不到 mnode 回应而且存在多个 mnode, taosc 将向下一个 mnode 发出请求。taosc 向 master vnode 发起插入请求。vnode 插入数据后给 taosc 一个应答表示插入成功。如果 taosc 迟迟得不到 vnode 的回应taosc 会认为该节点已经离线。这种情况下如果被插入的数据库有多个副本taosc 将向 vgroup 里下一个 vnode 发出插入请求。taosc 通知 APP写入成功。
对于第二和第三步taosc 启动时并不知道 mnode 的 End Point因此会直接向配置的集群对外服务的 End Point 发起请求。如果接收到该请求的 dnode 并没有配置 mnode该 dnode 会在回复的消息中告知mnode EP 列表这样 taosc 会重新向新的 mnode 的 EP 发出获取 meta-data 的请求。
对于第四和第五步没有缓存的情况下taosc 无法知道虚拟节点组里谁是 master就假设第一个 vnodeID 就是 master,向它发出请求。如果接收到请求的 vnode 并不是 master,它会在回复中告知谁是 master这样 taosc 就向建议的 master vnode 发出请求。一旦得到插入成功的回复taosc 会缓存 master 节点的信息。
上述是插入数据的流程查询、计算的流程也完全一致。taosc 把这些复杂的流程全部封装屏蔽了对于应用来说无感知也无需任何特别处理。
通过 taosc 缓存机制只有在第一次对一张表操作时才需要访问 mnode因此 mnode 不会成为系统瓶颈。但因为 schema 有可能变化而且 vgroup 有可能发生改变比如负载均衡发生因此 taosc 会定时和mnode 交互自动更新缓存。
二、存储模型与数据分区、分片
1.存储模型
TDengine 存储的数据包括采集的时序数据以及库、表相关的元数据、标签数据等这些数据具体分为三部分
时序数据存放于 vnode 里由 data、head 和 last 三个文件组成数据量大查询量取决于应用场景。容许乱序写入但暂时不支持删除操作并且仅在 update 参数设置为 1 时允许更新操作。通过采用一个采集点一张表的模型一个时间段的数据是连续存储对单张表的写入是简单的追加操作一次读可以读到多条记录这样保证对单个采集点的插入和查询操作性能达到最优。标签数据存放于 vnode 里的 meta 文件支持增删改查四个标准操作。数据量不大有 N 张表就有 N 条记录因此可以全内存存储。如果标签过滤操作很多查询将十分频繁因此 TDengine 支持多核多线程并发查询。只要计算资源足够即使有数千万张表过滤结果能毫秒级返回。元数据存放于 mnode 里包含系统节点、用户、DB、Table Schema 等信息支持增删改查四个标准操作。这部分数据的量不大可以全内存保存而且由于客户端有缓存查询量也不大。因此目前的设计虽是集中式存储管理但不会构成性能瓶颈。
与典型的 NoSQL 存储模型相比TDengine 将标签数据与时序数据完全分离存储它具有两大优势
能够极大地降低标签数据存储的冗余度一般的 NoSQL 数据库或时序数据库采用的 K-V 存储其中的 Key 包含时间戳、设备 ID、各种标签。每条记录都带有这些重复的内容浪费存储空间。而且如果应用要在历史数据上增加、修改或删除标签需要遍历数据重写一遍操作成本极其昂贵。能够实现极为高效的多表之间的聚合查询做多表之间聚合查询时先把符合标签过滤条件的表查找出来然后再查找这些表相应的数据块这样大幅减少要扫描的数据集从而大幅提高查询效率。而且标签数据采用全内存的结构进行管理和维护千万级别规模的标签数据查询可以在毫秒级别返回。
2.数据分片
对于海量的数据管理为实现水平扩展一般都需要采取分片(Sharding)分区(Partitioning)策略。TDengine 是通过 vnode 来实现数据分片的通过一个时间段一个数据文件来实现时序数据分区的。
vnode(虚拟数据节点)负责为采集的时序数据提供写入、查询和计算功能。为便于负载均衡、数据恢复、支持异构环境TDengine 将一个数据节点根据其计算和存储资源切分为多个 vnode。这些 vnode 的管理是TDengine 自动完成的对应用完全透明。
对于单独一个数据采集点无论其数据量多大一个 vnode或 vnode group, 如果副本数大于 1有足够的计算资源和存储资源来处理如果每秒生成一条 16 字节的记录一年产生的原始数据不到 0.5G因此 TDengine 将一张表一个数据采集点的所有数据都存放在一个 vnode 里而不会让同一个采集点的数据分布到两个或多个 dnode 上。而且一个 vnode 可存储多个数据采集点(表的数据一个 vnode 可容纳的表的数目的上限为一百万。设计上一个 vnode 里所有的表都属于同一个 DB。一个数据节点上除非特殊配置一个 DB 拥有的 vnode 数目不会超过系统核的数目。
创建 DB 时系统并不会马上分配资源。但当创建一张表时系统将看是否有已经分配的 vnode, 且该 vnode 是否有空余的表空间如果有立即在该有空位的 vnode 创建表。如果没有系统将从集群中根据当前的负载情况在一个 dnode 上创建一新的 vnode, 然后创建表。如果DB有多个副本系统不是只创建一个 vnode而是一个 vgroup (虚拟数据节点组)。系统对 vnode 的数目没有任何限制仅仅受限于物理节点本身的计算和存储资源。
每张表的 meta data包含 schema, 标签等也存放于 vnode 里而不是集中存放于 mnode实际上这是对 Meta 数据的分片这样便于高效并行的进行标签过滤操作。
3.数据分区
TDengine 除 vnode 分片之外还对时序数据按照时间段进行分区。每个数据文件只包含一个时间段的时序数据时间段的长度由 DB 的配置参数 days 决定。这种按时间段分区的方法还便于高效实现数据的保留策略只要数据文件超过规定的天数系统配置参数 keep)将被自动删除。而且不同的时间段可以存放于不同的路径和存储介质以便于大数据的冷热管理实现多级存储。
总的来说TDengine 是通过 vnode 以及时间两个维度对大数据进行切分便于并行高效的管理实现水平扩展。
4.负载均衡
每个 dnode 都定时向 mnode(虚拟管理节点)报告其状态包括硬盘空间、内存大小、CPU、网络、虚拟节点个数等因此 mnode 了解整个集群的状态。基于整体状态当 mnode 发现某个dnode负载过重它会将dnode 上的一个或多个 vnode 挪到其他 dnode。在挪动过程中对外服务继续进行数据插入、查询和计算操作都不受影响。
如果 mnode 一段时间没有收到 dnode 的状态报告mnode 会认为这个 dnode 已经离线。如果离线时间超过一定时长时长由配置参数 offlineThreshold 决定该 dnode 将被 mnode 强制剔除出集群。该dnode 上的 vnodes 如果副本数大于 1系统将自动在其他 dnode 上创建新的副本以保证数据的副本数。如果该 dnode 上还有 mnode, 而且 mnode 的副本数大于1系统也将自动在其他 dnode 上创建新的 mnode, 以保证 mnode 的副本数。
当新的数据节点被添加进集群因为新的计算和存储被添加进来系统也将自动启动负载均衡流程。
负载均衡过程无需任何人工干预应用也无需重启将自动连接新的节点完全透明。
提示负载均衡由参数 balance 控制决定开启/关闭自动负载均衡。
三、数据写入与复制流程
如果一个数据库有 N 个副本那一个虚拟节点组就有 N 个虚拟节点但是只有一个是 master其他都是 slave。当应用将新的记录写入系统时只有 master vnode 能接受写的请求。如果 slave vnode 收到写的请求系统将通知 taosc 需要重新定向。
1.Master Vnode 写入流程
Master Vnode 遵循下面的写入流程 图 3 TDengine Master 写入流程
master vnode 收到应用的数据插入请求验证OK进入下一步如果系统配置参数 walLevel 大于 0vnode 将把该请求的原始数据包写入数据库日志文件 WAL。如果 walLevel 设置为 2而且 fsync 设置为 0TDengine 还将 WAL 数据立即落盘以保证即使宕机也能从数据库日志文件中恢复数据避免数据的丢失如果有多个副本vnode 将把数据包转发给同一虚拟节点组内的 slave vnodes, 该转发包带有数据的版本号(version)写入内存并将记录加入到 skip listmaster vnode 返回确认信息给应用表示写入成功。如果第 2、3、4 步中任何一步失败将直接返回错误给应用。
2.Slave Vnode 写入流程
对于 slave vnode写入流程是 图 4 TDengine Slave 写入流程
slave vnode 收到 Master vnode 转发了的数据插入请求。检查 last version 是否与 master 一致如果一致进入下一步。如果不一致需要进入同步状态。如果系统配置参数 walLevel 大于 0vnode 将把该请求的原始数据包写入数据库日志文件 WAL。如果 walLevel 设置为 2而且 fsync 设置为 0TDengine 还将 WAL 数据立即落盘以保证即使宕机也能从数据库日志文件中恢复数据避免数据的丢失。写入内存更新内存中的 skip list。
与 master vnode 相比slave vnode 不存在转发环节也不存在回复确认环节少了两步。但写内存与 WAL 是完全一样的。
3.主从选择
Vnode 会保持一个数据版本号(version)对内存数据进行持久化存储时对该版本号也进行持久化存储。每个数据更新操作无论是采集的时序数据还是元数据这个版本号将增加 1。
一个 vnode 启动时角色(master、slave) 是不定的数据是处于未同步状态它需要与虚拟节点组内其他节点建立 TCP 连接并互相交换 status其中包括 version 和自己的角色。通过 status 的交换系统进入选主流程规则如下
如果只有一个副本该副本永远就是 master所有副本都在线时版本最高的被选为 master在线的虚拟节点数过半而且有虚拟节点是 slave 的话该虚拟节点自动成为 master对于 2 和 3如果多个虚拟节点满足成为 master 的要求那么虚拟节点组的节点列表里最前面的选为 master
更多的关于数据复制的流程请见TDengine 2.0 数据复制模块设计。
4.同步复制
对于数据一致性要求更高的场景异步数据复制无法满足要求因为有极小的概率丢失数据因此 TDengine 提供同步复制的机制供用户选择。在创建数据库时除指定副本数 replica 之外用户还需要指定新的参数 quorum。如果 quorum 大于1它表示每次master转发给副本时需要等待 quorum-1 个回复确认才能通知应用数据在 slave 已经写入成功。如果在一定的时间内得不到 quorum-1 个回复确认master vnode 将返回错误给应用。
采用同步复制系统的性能会有所下降而且 latency 会增加。因为元数据要强一致mnode 之间的数据同步缺省就是采用的同步复制。
四、缓存与持久化
1.缓存
TDengine 采用时间驱动缓存管理策略First-In-First-OutFIFO又称为写驱动的缓存管理机制。这种策略有别于读驱动的数据缓存模式Least-Recent-UsedLRU直接将最近写入的数据保存在系统的缓存中。当缓存达到临界值的时候将最早的数据批量写入磁盘。一般意义上来说对于物联网数据的使用用户最为关心的是刚产生的数据即当前状态。TDengine 充分利用这一特性将最近到达的当前状态数据保存在缓存中。
TDengine 通过查询函数向用户提供毫秒级的数据获取能力。直接将最近到达的数据保存在缓存中可以更加快速地响应用户针对最近一条或一批数据的查询分析整体上提供更快的数据库查询响应能力。从这个意义上来说可通过设置合适的配置参数将 TDengine 作为数据缓存来使用而不需要再部署 Redis 或其他额外的缓存系统可有效地简化系统架构降低运维的成本。需要注意的是TDengine 重启以后系统的缓存将被清空之前缓存的数据均会被批量写入磁盘缓存的数据将不会像专门的 key-value 缓存系统再将之前缓存的数据重新加载到缓存中。
每个 vnode 有自己独立的内存而且由多个固定大小的内存块组成不同 vnode 之间完全隔离。数据写入时类似于日志的写法数据被顺序追加写入内存但每个 vnode 维护有自己的 skip list便于迅速查找。当三分之一以上的内存块写满时启动落盘操作而且后续写的操作在新的内存块进行。这样一个 vnode 里有三分之一内存块是保留有最近的数据的以达到缓存、快速查找的目的。一个 vnode 的内存块的个数由配置参数 blocks 决定内存块的大小由配置参数 cache 决定。
2.持久化存储
TDengine 采用数据驱动的方式让缓存中的数据写入硬盘进行持久化存储。当 vnode 中缓存的数据达到一定规模时为了不阻塞后续数据的写入TDengine 也会拉起落盘线程将缓存的数据写入持久化存储。TDengine 在数据落盘时会打开新的数据库日志文件在落盘成功后则会删除老的数据库日志文件避免日志文件无限制地增长。
为充分利用时序数据特点TDengine 将一个 vnode 保存在持久化存储的数据切分成多个文件每个文件只保存固定天数的数据这个天数由系统配置参数 days 决定。切分成多个文件后给定查询的起止日期无需任何索引就可以立即定位需要打开哪些数据文件大大加快读取速度。
对于采集的数据一般有保留时长这个时长由系统配置参数 keep 决定。超过这个设置天数的数据文件将被系统自动删除释放存储空间。
给定 days 与 keep 两个参数一个典型工作状态的 vnode 中总的数据文件数为向上取整(keep/days)1个。总的数据文件个数不宜过大也不宜过小。10到100以内合适。基于这个原则可以设置合理的 days。目前的版本参数 keep 可以修改但对于参数 days一旦设置后不可修改。
在每个数据文件里一张表的数据是一块一块存储的。一张表可以有一到多个数据文件块。在一个文件块里数据是列式存储的占用的是一片连续的存储空间这样大大提高读取速度。文件块的大小由系统参数 maxRows 每块最大记录条数决定缺省值为 4096。这个值不宜过大也不宜过小。过大定位具体时间段的数据的搜索时间会变长影响读取速度过小数据块的索引太大压缩效率偏低也影响读取速度。
每个数据文件(.data 结尾)都有一个对应的索引文件.head 结尾该索引文件对每张表都有一数据块的摘要信息记录了每个数据块在数据文件中的偏移量数据的起止时间等信息以帮助系统迅速定位需要查找的数据。每个数据文件还有一对应的 last 文件(.last 结尾)该文件是为防止落盘时数据块碎片化而设计的。如果一张表落盘的记录条数没有达到系统配置参数 minRows每块最小记录条数将被先存储到 last 文件等下次落盘时新落盘的记录将与 last 文件的记录进行合并再写入数据文件。
数据写入磁盘时根据系统配置参数 comp 决定是否压缩数据。TDengine 提供了三种压缩选项无压缩、一阶段压缩和两阶段压缩分别对应 comp 值为 0、1 和 2 的情况。一阶段压缩根据数据的类型进行了相应的压缩压缩算法包括 delta-delta 编码、simple 8B 方法、zig-zag 编码、LZ4 等算法。二阶段压缩在一阶段压缩的基础上又用通用压缩算法进行了压缩压缩率更高。
3.多级存储
说明多级存储功能仅企业版支持从 2.0.16.0 版本开始提供。
在默认配置下TDengine 会将所有数据保存在 /var/lib/taos 目录下而且每个 vnode 的数据文件保存在该目录下的不同目录。为扩大存储空间尽量减少文件读取的瓶颈提高数据吞吐率 TDengine 可通过配置系统参数 dataDir 让多个挂载的硬盘被系统同时使用。
除此之外TDengine 也提供了数据分级存储的功能将不同时间段的数据存储在挂载的不同介质上的目录里从而实现不同“热度”的数据存储在不同的存储介质上充分利用存储节约成本。比如最新采集的数据需要经常访问对硬盘的读取性能要求高那么用户可以配置将这些数据存储在 SSD 盘上。超过一定期限的数据查询需求量没有那么高那么可以存储在相对便宜的 HDD 盘上。
多级存储支持3级每级最多可配置 16 个挂载点。
TDengine 多级存储配置方式如下在配置文件/etc/taos/taos.cfg中
dataDir [path] level primarypath: 挂载点的文件夹路径level: 介质存储等级取值为 012。 0级存储最新的数据1级存储次新的数据2级存储最老的数据省略默认为 0。 各级存储之间的数据流向0 级存储 - 1 级存储 - 2 级存储。 同一存储等级可挂载多个硬盘同一存储等级上的数据文件分布在该存储等级的所有硬盘上。 需要说明的是数据在不同级别的存储介质上的移动是由系统自动完成的用户无需干预。primary: 是否为主挂载点0否或 1是省略默认为 1。
在配置中只允许一个主挂载点的存在level0, primary1例如采用如下的配置方式
dataDir /mnt/data1 0 1dataDir /mnt/data2 0 0dataDir /mnt/data3 1 0dataDir /mnt/data4 1 0dataDir /mnt/data5 2 0dataDir /mnt/data6 2 0注意
多级存储不允许跨级配置合法的配置方案有仅 0 级仅 0 级 1 级以及 0 级 1 级 2 级。而不允许只配置 level0 和 level2而不配置 level1。禁止手动移除使用中的挂载盘挂载盘目前不支持非本地的网络盘。多级存储目前不支持删除已经挂载的硬盘的功能。
五、数据查询
TDengine 提供了多种多样针对表和超级表的查询处理功能除了常规的聚合查询之外还提供针对时序数据的窗口查询、统计聚合等功能。TDengine 的查询处理需要客户端、vnode、mnode 节点协同完成。
1.单表查询
SQL 语句的解析和校验工作在客户端完成。解析 SQL 语句并生成抽象语法树(Abstract Syntax Tree, AST)然后对其进行校验和检查。以及向管理节点(mnode)请求查询中指定表的元数据信息(table metadata)。
根据元数据信息中的 End Point 信息将查询请求序列化后发送到该表所在的数据节点dnode。dnode 接收到查询请求后识别出该查询请求指向的虚拟节点vnode将消息转发到 vnode 的查询执行队列。vnode 的查询执行线程建立基础的查询执行环境并立即返回该查询请求同时开始执行该查询。
客户端在获取查询结果的时候dnode 的查询执行队列中的工作线程会等待 vnode 执行线程执行完成才能将查询结果返回到请求的客户端。
2.按时间轴聚合、降采样、插值
时序数据有别于普通数据的显著特征是每条记录均具有时间戳因此针对具有时间戳的数据在时间轴上进行聚合是不同于普通数据库的重要功能。从这点上来看与流计算引擎的窗口查询有相似的地方。
在 TDengine 中引入关键词 interval 来进行时间轴上固定长度时间窗口的切分并按照时间窗口对数据进行聚合对窗口范围内的数据按需进行聚合。例如
SELECT COUNT(*) FROM d1001 INTERVAL(1h);针对 d1001 设备采集的数据按照1小时的时间窗口返回每小时存储的记录数量。
在需要连续获得查询结果的应用场景下如果给定的时间区间存在数据缺失会导致该区间数据结果也丢失。TDengine 提供策略针对时间轴聚合计算的结果进行插值通过使用关键词 fill 就能够对时间轴聚合结果进行插值。例如
SELECT COUNT(*) FROM d1001 WHERE ts 2017-7-14 00:00:00 AND ts 2017-7-14 23:59:59 INTERVAL(1h) FILL(PREV);针对 d1001 设备采集数据统计每小时记录数如果某一个小时不存在数据则返回之前一个小时的统计数据。TDengine 提供前向插值(prev)、线性插值(linear)、NULL值填充(NULL)、特定值填充(value)。
3.多表聚合查询
TDengine 对每个数据采集点单独建表但在实际应用中经常需要对不同的采集点数据进行聚合。为高效的进行聚合操作TDengine 引入超级表STable的概念。超级表用来代表一特定类型的数据采集点它是包含多张表的表集合集合里每张表的模式schema完全一致但每张表都带有自己的静态标签标签可以有多个可以随时增加、删除和修改。应用可通过指定标签的过滤条件对一个 STable 下的全部或部分表进行聚合或统计操作这样大大简化应用的开发。其具体流程如下图所示 图 5 多表聚合查询原理图
应用将一个查询条件发往系统taosc 将超级表的名字发往 meta node管理节点)管理节点将超级表所拥有的 vnode 列表发回 taosctaosc 将计算的请求连同标签过滤条件发往这些 vnode 对应的多个数据节点每个 vnode 先在内存里查找出自己节点里符合标签过滤条件的表的集合然后扫描存储的时序数据完成相应的聚合计算将结果返回给 taosctaosc 将多个数据节点返回的结果做最后的聚合将其返回给应用。
由于 TDengine 在 vnode 内将标签数据与时序数据分离存储通过在内存里过滤标签数据先找到需要参与聚合操作的表的集合将需要扫描的数据集大幅减少大幅提升聚合计算速度。同时由于数据分布在多个 vnode/dnode聚合计算操作在多个 vnode 里并发进行又进一步提升了聚合的速度。 对普通表的聚合函数以及绝大部分操作都适用于超级表语法完全一样细节请看 TAOS SQL。
4.预计算
为有效提升查询处理的性能针对物联网数据的不可更改的特点在数据块头部记录该数据块中存储数据的统计信息包括最大值、最小值、和。我们称之为预计算单元。如果查询处理涉及整个数据块的全部数据直接使用预计算结果完全不需要读取数据块的内容。由于预计算数据量远小于磁盘上存储的数据块数据的大小对于磁盘 I/O 为瓶颈的查询处理使用预计算结果可以极大地减小读取 I/O 压力加速查询处理的流程。预计算机制与 Postgre SQL 的索引 BRINblock range index有异曲同工之妙。
六、数据模型
1.物联网典型场景
在典型的物联网、车联网、运维监测场景中往往有多种不同类型的数据采集设备采集一个到多个不同的物理量。而同一种采集设备类型往往又有多个具体的采集设备分布在不同的地点。大数据处理系统就是要将各种采集的数据汇总然后进行计算和分析。对于同一类设备其采集的数据都是很规则的。以智能电表为例假设每个智能电表采集电流、电压、相位三个量其采集的数据类似如下的表格
设备ID时间戳采集量标签Device IDTime StampcurrentvoltagephaselocationgroupIdd1001153854868500010.32190.31Beijing.Chaoyang2d1002153854868400010.22200.23Beijing.Chaoyang3d1003153854868650011.52210.35Beijing.Haidian3d1004153854868550013.42230.29Beijing.Haidian2d1001153854869500012.62180.33Beijing.Chaoyang2d1004153854869660011.82210.28Beijing.Haidian2d1002153854869665010.32180.25Beijing.Chaoyang3d1001153854869680012.32210.31Beijing.Chaoyang2
表 1智能电表数据示例
每一条记录都有设备 ID时间戳采集的物理量如上图中的电流、电压、相位还有与每个设备相关的静态标签如上述表1中的位置 Location 和分组 groupId。每个设备是受外界的触发或按照设定的周期采集数据。采集的数据点是时序的是一个数据流。
2.数据特征
除时序特征外仔细研究发现物联网、车联网、运维监测类数据还具有很多其他明显的特征
数据高度结构化数据极少有更新或删除操作无需传统数据库的事务处理相对互联网应用写多读少流量平稳根据设备数量和采集频次可以预测出来用户关注的是一段时间的趋势而不是某一特定时间点的值数据有保留期限数据的查询分析一定是基于时间段和空间区域除存储、查询操作外还需要各种统计和实时计算操作数据量巨大一天可能采集的数据就可以超过 100 亿条。
充分利用上述特征TDengine 采取了经特殊优化的存储和计算设计来处理时序数据它将系统处理能力显著提高同时大幅降低了系统运维的复杂度。
3.关系型数据库模型
因为采集的数据一般是结构化数据同时为降低学习门槛TDengine 采用传统的关系型数据库模型管理数据。因此用户需要先创建库然后创建表之后才能插入或查询数据。TDengine 采用的是结构化存储而不是 NoSQL 的 key-value 存储。
4.一个数据采集点一张表
为充分利用其数据的时序性和其他数据特点TDengine 要求对每个数据采集点单独建表比如有一千万个智能电表就需创建一千万张表上述表格中的 d1001, d1002, d1003, d1004 都需单独建表用来存储这个采集点所采集的时序数据。这种设计有几大优点
能保证一个采集点的数据在存储介质上是以块为单位连续存储的。如果读取一个时间段的数据它能大幅减少随机读取操作成数量级的提升读取和查询速度。由于不同采集设备产生数据的过程完全独立每个设备的数据源是唯一的一张表也就只有一个写入者这样就可采用无锁方式来写写入速度就能大幅提升。对于一个数据采集点而言其产生的数据是时序的因此写的操作可用追加的方式实现进一步大幅提高数据写入速度。
如果采用传统的方式将多个设备的数据写入一张表由于网络延时不可控不同设备的数据到达服务器的时序是无法保证的写入操作是要有锁保护的而且一个设备的数据是难以保证连续存储在一起的。采用一个数据采集点一张表的方式能最大程度的保证单个数据采集点的插入和查询的性能是最优的。
TDengine 建议用数据采集点的名字(如上表中的 D1001)来做表名。每个数据采集点可能同时采集多个物理量(如上表中的 current, voltage, phase)每个物理量对应一张表中的一列数据类型可以是整型、浮点型、字符串等。除此之外表的第一列必须是时间戳即数据类型为 timestamp。对采集的数据TDengine 将自动按照时间戳建立索引但对采集的物理量不建任何索引。数据用列式存储方式保存。
5.超级表同一类型数据采集点的集合
由于一个数据采集点一张表导致表的数量巨增难以管理而且应用经常需要做采集点之间的聚合操作聚合的操作也变得复杂起来。为解决这个问题TDengine 引入超级表(Super Table简称为 STable)的概念。
超级表是指某一特定类型的数据采集点的集合。同一类型的数据采集点其表的结构是完全一样的但每个表数据采集点的静态属性标签是不一样的。描述一个超级表某一特定类型的数据采集点的集合除需要定义采集量的表结构之外还需要定义其标签的 schema标签的数据类型可以是整数、浮点数、字符串标签可以有多个可以事后增加、删除或修改。如果整个系统有 N 个不同类型的数据采集点就需要建立 N 个超级表。
在 TDengine 的设计里表用来代表一个具体的数据采集点超级表用来代表一组相同类型的数据采集点集合。当为某个具体数据采集点创建表时用户使用超级表的定义做模板同时指定该具体采集点表的标签值。与传统的关系型数据库相比表一个数据采集点是带有静态标签的而且这些标签可以事后增加、删除、修改。一张超级表包含有多张表这些表具有相同的时序数据 schema但带有不同的标签值。
当对多个具有相同数据类型的数据采集点进行聚合操作时TDengine 会先把满足标签过滤条件的表从超级表中找出来然后再扫描这些表的时序数据进行聚合操作这样需要扫描的数据集会大幅减少从而显著提高聚合计算的性能。
其他
参考https://www.taosdata.com/docs/cn/v2.0/architecture