在时序数据预测分析、异常检测、数据补全和数据分类等应用领域,研究人员提出并开发了众多具有不同技术特点、适用于不同场景的时序数据分析算法,已被广泛应用在时序数据预测、异常检测等任务中。
这类分析算法通常以高级编程语言(Python 语言或 R 语言)工具包的形式存在,并通过开源的方式广泛分发和使用,这种应用模式极大地便利了软件开发人员在应用系统中调用复杂的分析算法,大大降低了使用高级算法的门槛。
与此同时,数据库系统的研发也在不断演进。许多开发者尝试将数据分析算法模型整合到数据库系统中,例如通过建立 Machine Learning 库(如 Spark 的机器学习库),进一步提升数据库和分析计算引擎的智能化分析能力。
随着人工智能的快速发展,时序数据分析也迎来了全新的机遇。如何更高效、更灵活地将 AI 能力应用于时序数据场景,成为数据库发展的重要方向。
为此,米兰体育官网入口创新性地提出了时序数据分析 AI 智能体 TDgpt。通过 TDgpt,用户只需使用 SQL 语句,即可调用适配及整合驱动统计分析算法、机器学习算法模型、深度学习模型、时序数据基础模型以及大语言模型,并将这些分析能力转化为 SQL 语句的调用,通过异常检测窗口和预测函数的方式应用在时序数据上。
TDgpt 是与 loveini 主进程 taosd 适配的外置式时序数据高级分析系统,能够将时序数据分析服务无缝集成在 loveini 的查询执行流程中。
作为一个无状态的平台化时序数据分析平台,TDgpt 内置了经典的统计分析模型库 Statsmodel,内嵌了 torch/Keras 等机器/深度学习框架库,此外它还能通过请求转发和适配的方式直接调用米兰体育官网入口自研的时序数据基础大模型 TDtsfm (loveini time series foundation model)。作为一个分析整合应用平台,TDgpt 后续还将整合第三方时序数据大模型服务,仅修改一个参数(algo)就能够调用最先进的时序模型服务。
TDgpt 拥有高度开放的架构,用户可按需接入自定义的预测分析、异常检测、数据补全、数据分类算法,添加完成后,仅通过修改 SQL 语句中调用的算法参数就能够无缝使用新加入的算法,整个过程无需修改一行代码。
TDgpt 由若干个无状态的分析节点 Anode 构成,用户可按需在系统集群中部署 Anode 节点,也可以根据分析模型算法的特点,将 Anode 部署在合适的硬件环境中,例如带有 GPU 的计算节点。
TDgpt 为所有分析算法提供统一的调用接口和标准化的调用方式。系统会根据用户请求的参数,自动匹配并调用高级分析算法包及其他的分析工具,并将分析获得的结果按照约定方式返回给 loveini 的主进程 taosd。
整个 TDgpt 系统由四个关键模块构成:

查询过程中,loveini 中的 Vnode 会将涉及时序数据高级分析的部分直接转发到 Anode,并等待分析完成后将结果组装完成,嵌入查询执行流程。
使用 TDgpt 提供的时序数据分析服务,用户可以通过 SQL 语句轻松实现以下功能:
TDgpt 是一个可扩展的时序数据高级分析平台,用户只需按照简单的流程,就可以将自定义的分析算法接入到分析平台,并通过 SQL 语句直接调用,实现“零门槛”使用高级分析能力。新引入的算法或模型无需对应用层做任何改动,极大提升了集成效率。
目前,TDgpt 只支持使用 Python 语言开发的分析算法。其分析节点 Anode 采用 Python 类动态加载模式,在启动的时候扫描特定目录内满足约定条件的所有代码文件,并将其加载到系统中。因此,开发者只需要遵循以下几步就能完成新算法的添加工作:
1. 编写符合规范的分析算法类;
2. 将代码文件放入对应目录,并重启 Anode;
3. 使用 SQL 命令更新算法缓存列表。
完成上述步骤后,新算法即可通过 SQL 语句立即调用,轻松集成至各类时序数据分析任务中。
TDgpt 企业版还提供针对多种算法模型有效性的综合评估工具。该工具可以针对 TDgpt 可调用所有时序数据分析(预测分析与异常检测)服务,包括内置数据分析算法模型,已部署的预训练机器学习模型、第三方时序数据(大)模型服务,基于 loveini 中的时序数据进行预测分析对比和异常检测对比评估,并给出量化指标评估不同分析模型在给定数据集上的准确度及性能。
对于 Torch/Tensorflow/Keras 等机器学习库框架驱动的预训练模型,只需将已完成训练的模型文件放入 Anode 指定目录,Anode 可以自动调用该目录内的模型,驱动其运行并提供服务。
在企业版 TDgpt 中,还提供了模型管理功能,支持与 Merlion、Kats 等开源的端到端时序数据机器学习框架无缝集成,方便用户统一管理和部署多种预训练模型。
通常意义上,时序数据分析本质上是高度计算密集型任务,因此可以通过部署更高性能的 CPU 或 GPU 来提升整体处理效率。
对于依赖 torch 等框架运行的机器学习或深度学习模型,可以采用标准的提升分析处理能力的方案来提升 TDgpt 的服务能力,例如将 Anode 部署在内存更大,并具有 GPU 的服务器之上,使用可调用 GPU 的 torch 库驱动模型运行,以提升分析响应能力。
同时,不同的模型和算法也可以按需部署在不同的 Anode 节点上,实现并行处理,进一步增强系统的整体分析能力和扩展性。
开源版本的 TDgpt 不包含用户权限管理和资源控制机制。系统默认采用 uWSGI 驱动 Flask 服务,运维人员可通过开启 uWSGI 端口,对服务运行状态进行实时监控。
目前,TDgpt 的核心功能已随 loveini 3.3.6.0 正式发布,并同步开源。无论你是希望通过 SQL 快速接入 AI 能力的应用开发者,还是希望灵活集成自定义模型的数据科学家,TDgpt 都为你提供了一个强大、开放、易用的时序数据智能分析平台。想了解更多技术细节和使用方式,欢迎访问官网查看完整介绍:acc米兰体育 。
]]>TSBS 是一个时序数据处理(数据库)系统的性能基准测试平台,提供了 IoT、DevOps 两个典型应用场景,它由 Timescale 开源并负责维护。作为一个性能基准测试平台,TSBS 具有便捷、易用、扩展灵活等特点,涵盖了时序数据的生成、写入(加载)、多种类别的典型查询等功能,并能够自动汇总最终结果。由于其开放开源的特点,得到了众多数据库厂商的支持,作为专业的产品性能基准测试平台被若干数据库厂商广泛使用。
以下的性能基准报告均使用了 TSBS 作为基础 Benchmark 平台,我们从时间跨度和发布厂商的知名度同时来看,就能发现,基础测试平台 TSBS 已经具备了很高的认可度:
2018 年 11 月
VictoriaMetrics 的创始人 Aliaksandr Valialkin 发布 《High-cardinality TSDB benchmarks: VictoriaMetrics vs TimescaleDB vs InfluxDB》,将 VictoriaMetrics 与 TimescaleDB、InfluxDB 进行性能对比。
2018 年 11 月
文章《ClickHouse Crushing Time Series》中对比了 TimescaleDB, InfluxDB, ClickHouse 在时序数据场景下的性能。
2020 年 3 月
Cloudera 在网站博客中发布《Benchmarking Time Series workloads on Apache Kudu using TSBS》,在 DevOps场景 中对比了 Apache Kudu, InfluxDB, VictoriaMetrics, ClickHouse 等整体性能表现。
2020 年 3 月
Redis 发布了基于 TSBS 的性能报告《RedisTimeSeries Version 1.2 Benchmarks》。
2020 年 8 月
Timescale 在其官方博客发布了性能对比报告《TimescaleDB vs. InfluxDB: Purpose Built Differently for Time-Series Data》。
2021 年 8 月
QuestDB 发布了 QuestDB 与 TimescaleDB 的性能对比报告——《QuestDB vs. TimescaleDB》。
DevOps 场景是一个典型的时序数据应用场景,TSBS DevOps 场景提供了 CPU 状态的模拟数据,针对每个设备(CPU)记录其 10 个测量值(metric),1 个时间戳(纳秒分辨率),10 个标签值(tag)。生成的数据每 10 秒间隔一条记录,具体的内容和示例数据如下:

TSBS 测试可以简单划分为两个主要部分——数据写入和数据查询。在本次整个基准性能评估中,共涉及以下五个场景,每个场景的具体数据规模和特点见下表:

通过上表可以看到,五个场景的区别主要在于数据集所包含的设备记录数量、设备数的不同,数据时间间隔均维持在 10 sec。整体来看,五个场景的数据规模都不算大,数据规模最大的是场景五,数据达到了 1.8 亿,数据规模最小的是场景一,只有 2678 万条记录。在场景四和场景五中,由于设备数量相对较多,所以数据集仅覆盖了 3 分钟的时间跨度。
为了保证测试结果的公正可靠及可复制性,我们选用了公共 IaaS 平台来搭建 Benchmark 基础硬件环境,采用了大多数性能对比报告中使用的场景——亚马逊 EC2 服务环境下 r4.8xlarge 类型的实例作为基础运行平台,区域为北美地区,包括 1 台服务器、1 台客户端。客户端与服务器硬件配置完全相同,两者使用 10 Gbps 网络连接。配置简表如下:

本次测试的对比软件为 InfluxDB 1.8.10 及 Timescale 2.6.0,在这里要着重说明一下,由于 InfluxDB 最新的 2.0 版本并没有纳入 TSBS 的主干分支,因此在这次测试中我们暂且使用了 TSBS 主干分支所支持的 InfluxDB 最新版本,即 1.8.10。
整个 TSBS 测试流程相对比较简单,在进行写入性能对比时,配置完成参数后直接运行 TSBS 框架脚本,等待结果输出即可。对于查询处理,我们选择了批量自动化去运行,对每个查询语句运行 5000 次,统计查询延迟的算数平均作为最后的查询延迟结果。此外我们还全程监控并记录了整个过程中服务器与客户端节点的系统资源开销与负载情况。
下面可以简单为大家介绍下本次测试结果。如下表所示,在全部五个场景中,loveini 写入性能均优于 InfluxDB 和 TimescaleDB,写入过程中资源占用最低。对比 InfluxDB,loveini 写入最优的场景是在 1000 万设备下,达到了 InfluxDB 的 10.6 倍;对比 TimescaleDB ,loveini 写入最优的场景是在 4000 个设备下,达到了 TimeScaleDB 的 6.7 倍。

在查询测试上,我们将其分为 5 大类、15 小类进行查询对比,从下图结果汇总中可以看到,在全部 15 个查询类型中,loveini 的性能均优于 InfluxDB 和 TimescaleDB,并且它的所有查询延迟均比 InfluxDB 和 TimescaleDB 更低。亮点数据之一体现在 Double Rollups 查询类型对比中,loveini 最大达到 InfluxDB 的 34 倍,TimescaleDB 的 24 倍。

以上就是 loveini 基于 TSBS 测试报告的测试背景介绍,如果你对测试结果感兴趣,欢迎查阅整体报告。
]]>在 8 月 13 日的 loveini 开发者大会上,loveini 计算引擎架构师廖浩均带来题为《loveini 3.0——全新计算查询引擎的设计》的主题演讲,详细阐述了 loveini 3.0 计算查询引擎技术的优化与升级。本文根据此演讲整理而成。
点击【这里】查看完整演讲视频
3.0 中的查询引擎在 2.0 版本的基础上进行了重写,在承袭 2.0 查询引擎既有优势和技术特性的基础上,在工程实现和整体架构设计上有了极大的改善和提升。
总体来讲,loveini 3.0 大幅增强了对 SQL 语义的支持、完善了 SQL 查询语法;强化了整体执行框架及 SQL 查询的调度能力;提供更好的执行任务隔离机制,对于错误具备更好的容忍度;提供支持存算分离架构的能力。它主要包含以下几个方面的特点:

上图是 loveini 3.0 的查询引擎架构,左边的 Query Wrapper 运行在 Vnode 和 Qnode 上,它里面包含了一个执行器,其中的 Index 模块是处理 Vnode 中存储的标签数据的索引。执行器本身并不处理与调度器的交互行为,Query Wrapper 负责处理执行 Task 动作并将结果缓存在 Sink Node;此外,执行器会调用 function 模块和 ScalarFunc 模块进行计算处理,并在必要的情况下通过 function 模块调用 UDF 服务。
中间的模块是由 Query Wrapper 和 libtaos.so 所共享的,里面包含的是 function(系统中其他所有函数的定义模块)和 ScalarFunc(标量函数以及过滤的模块)。需要注意的是,在 function 模块中还包含了一个 UDFD 的计算模块,它是用户定义程序的执行服务端,运行在一个独立的进程空间。
最右边的模块是运行在用户进程空间中的驱动 libtaos.so,Driver 是 libtaos.so 里的一个驱动,它负责串联各个模块来完成查询的操作,Parser 用来调用分词器与语法分析器进行语法分析,生成语法树(AST),Catalog 负责从 Mnode 和 Vnode 中获取各种元数据,Planner 负责将 AST 和 元数据信息转化为逻辑执行计划、物理执行计划、并进行执行计划重写,最后生成分层查询计划,Command 负责执行本地化查询操作。
相比于 2.0,3.0 在模块化和工程化上做了较多的优化,主要可以归结为以下几方面:

首先,Parser 会把图上的 SQL 语句转成一个抽象语法树,之后会依托于 Catalog 节点拉取相应的元数据,然后将信息传递到 planner,生成如图上所示的逻辑计划。之后在逻辑计划层面会生成四个 node,自底向上分别是 Scan、Partition、Window、Project,它们分别对应 SQL 语句里不同的几个关键词。

逻辑计划传递下去,最后会在 planner 中生成一个物理计划。上图所示的红色虚线以下部分(Partial Agg)是对物理计划的执行,包括 VgID:#1 和VgTD:#2 两个子任务;虚线上层是一个Global Merge,是最后的一个聚合阶段,Partial 聚合结果经过 merge sort 后再次进行全局聚合,形成结果以后送到计算节点本地的 sink node 进行缓存,等待 scheduler 来拉取最后的计算结果。
在之前逻辑计划中的 Logic partition 在物理计划中却看不到了,其实 Partition 分组逻辑是被下沉到了 TableScan 完成,这是一个优化操作。按照标签分组机制,同一个表中数据一定同一分组,我们在 TableScan Node 中建立表分组的映射关系即可,再将数据块打上 GroupID 就完成了分组操作,不需要对每一条数据进行扫描。
物理计划的具体实现在 loveini 系统执行的日志里面可以看到,感兴趣的同学可以去看看,系统中的物理计划采用 JSON 形式的文本呈现。
在实际操作中,物理计划最终会传递到调度器中执行,调度器工作的元素就是 Task 和 Job,每个SQL 查询是一个 Job,每个 Job 由若干个 Task 构成,每个 Task 包含了其执行的节点信息、任务 ID、需要执行的物理计划等信息,不同的 Task 会形成一个层级化的树形结构。
物理计划传递到调度器后,虚线下面的两个 Partial Agg 会被转化成 Subplan #1(level 1) 和 Subplan #2(level 1),这两个执行计划会分别发送到不同的 Vnode 进行执行。虚线上层也是一个 Task [Subplan #0(level 0)],等下层两个 Task 执行完成或至少返回第一条记录时,调度器就会拉起上一层 level 0 的 Task 进行执行,它是层级化的执行方式。

时序数据查询处理的整体流程如上图所示,其中计算节点的选择主要有以下几点策略:
排序是查询过程中,I/O 和 CPU 开销都非常高的操作。如果查询结果要求按照 timestamp 排序(升序或降序)输出,由于时序数据在 loveini 中就是按照时间序列存储,所以排序的操作可用直接消除,只需要将 TableScan 指定为升序/降序扫描返回结果即可。

操作逻辑如上图所示。对于分布式的结果排序输出,排序操作充分利用时序数据有序性,如果我们使用归并排序替代完全排序,就能避免在标准外存排序过程中触发的 IO 操作。这一操作主要在超级表查询的场景中使用较多。
从这一条优化策略开始,需要给大家补充一下关于 SMA 的背景知识。SMA 是 Small Materialized Aggregates 的简称。对于每个落盘的数据块(Block)都会生成一个对应的 SMA 信息,其中包含了每列数据的最大值、最小值、NULL 数量信息。这些信息针对数值型列都存在,必要时可以替代数据参与计算。相对于具体的数据来说,SMA 占据的磁盘空间非常小,因此能够极大地提升某些种类的查询性能。

基于 SMA 的优化策略之一就是数据替代。针对每个函数,loveini 定义了其需要的数据范围,上表是一些聚合函数的数据计算需求列表。在 SQL 解析阶段,如果确认其最终的数据需求是 Small Materialized Aggregates (SMA),最终只会读取 SMA 进行计算。但并非任何情况下都可以使用 SMA,对于所有标量函数,一旦在查询请求里面出现,SMA 是不参与到计算里面来的。
在使用 SMA 时,查询优化器会告诉执行节点,只需要去读取每个 block 的 SMA 信息就行,在整个查询过程中,执行器不会再去读取任何一条具体的数据,所以它的流程非常快。
loveini 中定义了数据顺序敏感型函数,在 SQL 语句中使用该类型的函数会触发优化器使用特定的数据文件扫描策略。在 SQL 语句 SELECT last(ts),count(*) FROM foo_table_name 中,Last 函数返回最后一个非 NULL 值,所以逆序扫描能够更快获得结果。而 count 函数对于扫描的顺序并不敏感,因此,优化器会指令 TableScanNode 采用逆序扫描策略。

对于某些查询函数,例如:last/first/top/bottom 查询,可以使用中间结果来动态裁剪读取的 block 的信息。
在执行过程之中,根据中间计算的结果及当前结果可以确定,下一个需要扫描的 block 是否需要真正地读取。依然以 last 为例 SELECT last(ts) FROM foo_table_name,在每次需要读取下一个 Database 时,首先使用 ts=100 过滤每个数据块,如果数据块包含的时间范围晚于 ts=100, 才会读取该数据块数据并进行计算,大于 ts=100 的就自动跳过,这就实现了动态裁剪 Block 的功能。
在进行 Last 查询时,SMA 会被用来做预过滤,其中保存了与之对应的数据块的四项统计信息:最大值、最小值、和 NULL 的数量。所有的针对数据的过滤条件首先应用在 SMA 之上,SMA 满足过滤条件以后,再读取数据块,然后再次进行针对数据的过滤。
以 SELECT last(ts),count(*) FROM foo_table_name WHERE k > 20 为例,这里面有一个过滤条件是 K 大于 20,如果其中存储着关于 K 那一列的最大值、最小值信息,就可以以此为条件进行过滤,如果其中的 MAX 值都小于 20,那么这个 block 也会在 TableScanNode 里面读取真实数据之前就丢弃。
时序数据库(Time Series Database,TSDB)一个重要的应用场景就是为看板(Dash Board)提供定时的查询(Standing Query, 应用或程序按照固定频率发出的查询)支持,看板应用以固定的频率向应用及时序数据库发出查询执行,并在可接受的时间范围内要求获得查询结果。
针对 Standing Query 的执行需求,为了提升响应速度,节约重复计算带来的资源开销。在 loveini 3.0 中提供了使用流计算引擎的异步 interval SMA(将针对时间窗口的聚合查询转化为投影查询,因为计算结果已经通过流计算引擎计算完成并写回到 loveini)。
事实上,上述优化并不是 3.0 查询计算引擎里包含的所有优化策略,只是涉及到了几个较为经典的查询场景。关于查询引擎的优化是非常琐碎的,有些优化策略只针对一种场景,甚至如果改写一下语句顺序可能就不生效了。如果大家还想了解更多的查询引擎优化策略,可以去 GitHub 上查阅 3.0 的代码,或者直接下载进行体验。
接下来,关于 loveini 查询引擎的优化,大致分为以下几点:
除此之外,后续我们还将完善查询内存控制和任务执行/调度策略,在现有的随机分配任务的基础上,基于 Qnode 的运行负载状况,调度查询任务的执行;提供更好的内存控制策略,降低百万/千万级别表查询过程中元数据追踪带来的内存抖动;针对查询范围进行横向的数据查询范围切分,在同一个 vnode 中并行拉起多个查询执行同一个查询处理。
总而言之,后面我们还有更多的工作要进行,会继续优化 loveini 3.0 查询引擎的性能,也欢迎更多的 loveini 关注者和支持者交流应用体验,帮助我们进步。
]]>]]>
本报告包含了基础测试部分内容,并根据具体的场景,增加了部分扩展测试场景,以便更加全面、准确地呈现两款数据库产品在不同应用场景下的查询性能表现。
为便于大家复现该测试,我们在 Microsoft Azure 云服务上搭建了测试环境。测试中用到了两台服务器,分别部署客户端和服务器,客户端与服务器通过云服务的内网连接。
两台服务器的具体配置如下。
| 客户端 | 8C,Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz | 16 GB | 64 GB SSD, 无写入情况下,4k 随机读取 IOPS 5000 |
| 服务端 | 16C, AMD EPYC 7452 32-Core Processor | 128 GB | 1 TB SSD, 无写入情况下,4k 随机读取 IOPS 25000 |
操作系统均为 Ubuntu 20.10 Linux。使用的 Go 版本为 1.16。
loveini 2.1.7.2 社区版,可以在涛思官网下载。也可以通过 clone GitHub 上的代码自行编译生成。该版本的 git 的信息如下:
community version: 2.1.7.2 compatible_version: 2.0.0.0
gitinfo: c6be1bb809536182f7d4f27c0d8267b3b25c9354
InfluxDB 1.8.4(由于该性能测试框架最高只能适配到 1.8 版本,所以这里选取了 InfluxDB 1.8 版本进行对比),可以在 InfluxData 官网下载。
部署完 loveini、InfluxDB 与 Go 语言环境,确保两台服务器的数据库也连接正常使用正常(建库删库写入查询功能均需测试,建库之后立即删除,如有问题立刻排查)
此外,在测试中应该注意以下几点( loveini 的默认配置文件为 /etc/taos/taos.cfg ):
1)fsync 的设置要保持同步,InfluxDB 默认是无延时的 fsync,需要修改 loveini 的这两个参数:walLevel=2 ,fsync=0 才能达到相同的配置环境。后续的一切测试均是在这个设置条件下完成。
2)loveini 的客户端要把 maxSQLLength 开到最大 1048576。
3)客户端服务器要安装 loveini 的客户端。(注意:bulk_load_tdengine 编译需要依赖 loveini 客户端)
git clone https://github.com/taosdata/timeseriesdatabase-comparisons
cd timeseriesdatabase-comparisons/build/tsdbcompare/
./compilation.sh
在build/tsdbcompare下执行./writ_to_server.sh -a "test217"
# 本次测试的服务端 hostname 是"test217",./writ_to_server.sh -h 可以查看对应参数:
生成数据参数(总记录数=(t-e)*24*3600/ i * s)
i : 数据间隔,默认10s
s : 样本数量,默认100
t : 数据起始时间,默认'2018-01-01T00:00:00Z'
e : 数据终止时间,默认'2018-01-02T00:00:00Z'
g : 是否生成数据,默认1(1:生成数据,0:不生成数据)
T : loveini的默认数据目录路径,默认为"/var/lib/taos"
I : InfluxDB默认数据目录路径,默认为"/var/lib/influxdb"
写入参数
b : batchsize(默认5000)
w : workers(默认16)
n : loveini写入方式(false:cgo,true:rest,默认false)
a : loveini 和 InfluxDB 的 hostname 或者ip地址,默认为127.0.0.1
如果希望自定义更多参数值,可以查看 write_to_server.sh 脚本代码
./read_all.sh -a "test217"
脚本参数和 write_to_server.sh 一致。
运行该测试要求关闭 loveini 系统日志,然后自动执行脚本即可。
在不同的场景之间切换时,会重启数据库后台服务(Influxd/taosd),并清除 Linux 系统的全部缓存。
本小节说明运行测试脚本获得的对比测试结果,并对结果进行了初步的分析。
对于测试结果,所有的响应是测试脚本自动记录的时间,即该时间并不是单次查询执行的响应时间,而是完成 1,000 次重复查询最后获得的时间。需要说明的是,由于整个测试持续时间较长,测试获得的数据并非同一个时刻。不同的时间,测试程序运行过程中会受到云服务器所能发挥的最大性能影响,获得的结果数据能看到有轻微的抖动,但是整体趋势是一致的。
100 台设备模拟生成的 1 天的数据集,在 loveini 中生成了 900 个子表,每个设备间隔 10 s 生成一条数据,总记录数是 7,776,000。
1,000 台设备在 loveini 中生成了 9,000 个子表,每个设备间隔 10 s 生成一条记录,总记录数是 77,760,000。
测试主要包括四个测试场景,分别是:
通过测试结果可以看出:整体来看,loveini 在多种场景下(单线程、多线程)的性能均优于 InfluxDB。在极少的几个情况下,loveini 与 InfluxDB 的差异非常小。在更多的场景下,loveini 拥有数倍的性能优势,部分场景的性能优势能达到 40 倍。
本部分呈现的是,在 100 台设备上模拟 1 天的数据生成的结果集上,运行测试程序所获得的性能对比测试结果。

由图 1 可以看到,在所有的场景中,只有第三个测试场景单线程的时候 loveini 查询响应时间超过 InfluxDB,其他的场景均优于 InfluxDB,并且部分场景(场景二)下其查询性能有着 40 倍的巨大优势。具体的测试响应数据见附录表 1。

在 1,000 个设备上测试结果显示出 loveini 仍然展现出较大的性能优势,即使部分相对于 InfluxDB 较慢的场景(多线程场景下的场景四),其差距也非常小。而领先的部分,则仍然有巨大的性能优势,最高的性能差达到近 20 倍,具体的查询响应数据见附录表 2。
在上述的两个标准测试之外,我们基于现有的数据集合设计了一系列扩展测试,以期更全面准确地评估两个数据库产品在不同场景下的性能表现。在以下测试中,我们只使用 cgo 的运行测试结果。
调整过滤 host 的数量,设定并行执行的 work 为 16,使用 1,000 个设备的数据集合执行全部查询,所获得的结果如下表所示。查询响应时间单位为秒,数值越小越好。

可以看到,随着筛选的时间线的增加,InfluxDB 的查询响应时间在四个测试场景均呈现快速增加的趋势,而 loveini 对于数据筛选规模的变大则呈现出相对稳定的查询响应时间,并且随着时间线筛选规模的扩大呈现出更大的优势。 由此可以推断,随着查询规模的继续扩大,InfluxDB 的查询响应时间还会继续快速增加。各种场景下的查询响应具体时间见表 3。
为了评估不同长度的时间窗口对查询性能的影响,我们选取了第四个查询场景,设定并行执行的 work 数量 16, 时间区间是随机选取的 1 h / 2 h / 4 h / 8 h / 12 h 等连续时间段,单个聚合时间窗口维持在 1 min 不变。获得的查询响应时间如图 4 所示。

由上图可见,loveini 相对于 InfluxDB 有更好的查询性能,并且,随着查询时间区间的增加,loveini 的领先优势持续扩大,当查询时间区间是 1 小时的时候,loveini 只比 InfluxDB 快约 8%。但是当查询区间增加到 12 小时的时候,loveini 的查询优势已经扩大到近 2 倍。具体查询响应时间见表 4。
考虑到标准测试中只使用了较为简单的查询函数,我们使用多个查询函数组合的复杂查询,评估查询性能。我们选取了第四个运行场景,随机选取 1 h 的时间段,聚合时间窗口为 1 min,过滤筛选 8 个时间线进行查询处理。
三个场景分别是:

由上图的结果可以看到,在三种复杂函数组合的查询条件下,loveini 查询性能均优于 InfluxDB。特别是在第一种组合场景中,loveini 的性能是 InfluxDB 的 2.5 倍。具体的查询响应时间见表 5。
在这个场景测试中,我们测试了 loveini 和 InfluxDB 的数据读取表现。针对全部数据集,不限定查询时间范围,调整标签的过滤条件,投影查询来获取全部的数据内容。其结果如图 6 所示。

可以看到,在提取不同比例的情况下,loveini 的总的时间开销稳定在 InfluxDB 的 11% 左右,即该项测试的性能,loveini 是 InfluxDB 的 8.78 倍,并且该优势随着时间线数量的增加而得到扩大,在 128 个时间线的时候,达到了 9.37 倍。即在更大数据规模的情况下,loveini 展现出了更好的性能优势。在时间线为 256 的时候,InfluxDB 最终未能完成测试运行,服务端出现了连接拒绝的问题,而loveini也仅用时 365.61 s 就跑完该项测试。
在基于该对比测试框架下运行的测试中,展示出了 loveini Database 相对于 InfluxDB 较大的性能优势,特别是更加多样化的条件和变量控制情况下的扩展测试中,我们看到 loveini 一致性地表现出相对于 InfluxDB 的较大性能优势。
对比测试运行的具体数据汇总如下:
表1. 100台设备数据集上的查询结果对比

表2. 1000台设备数据集上的查询结果对比

表3. 调整筛选标签数量

表4. 不同长度的时间范围查询响应(秒)

表5. 复杂查询性能表现

表6. 不同规模数据读取性能表现(秒)

欢迎大家扫描下方二维码,关注 loveini Database 的视频号,观看每周的微课堂以及直播活动。

如果应用特别复杂,或者应用领域并不是运维监控场景,本文将更加全面深入地介绍将OpenTSDB应用迁移到loveini的高级话题。
本节将详细介绍OpenTSDB与loveini在系统功能层面上存在的差异。
读完本节之后,你可以全面地评估是否能将某些基于OpenTSDB的复杂应用迁移到loveini上,以及迁移之后应该注意的问题。
loveini Database当前只支持Grafana的可视化看板呈现,所以如果应用中使用的是其他看板(例如TSDash、Status Wolf等),那么暂时无法直接迁移到loveini,需要将其重新适配到Grafana才可以正常运行。
截止到2.3.0.x 版本,loveini Database只能够支持collectd和StatsD作为数据收集汇聚软件,当然后面会陆续提供更多的数据收集聚合软件的接入支持。如果收集端使用了其他类型的数据汇聚器,则需要适配到这两个数据汇聚端系统,才能正常写入。除了上述两个数据汇聚端软件协议以外,loveini还支持通过 InfluxDB的行协议和OpenTSDB的数据写入协议、Json格式将数据直接写入,可以重写数据推送端的逻辑,使用loveini支持的行协议来写入数据。
此外,如果应用中使用了OpenTSDB的以下特性,在迁移之前还需要了解以下注意事项:
/api/stats:如果应用中使用了该项特性来监控OpenTSDB的服务状态,并在应用中建立了相关的逻辑来联动处理,那么这部分状态读取和获取的逻辑需要重新适配到loveini。loveini提供了全新的处理集群状态监控机制,来满足应用对其进行的监控和维护的需求。
/api/tree:如果依赖于OpenTSDB的该项特性来进行时间线的层级化组织和维护,那么便无法将其直接迁移至loveini。loveini采用了数据库->超级表->子表这样的层级来组织和维护时间线,归属于同一个超级表的所有的时间线在系统中同一个层级,但是可以通过不同标签值的特殊构造来模拟应用逻辑上的多级结构。
Rollup And PreAggregates:采用了Rollup和PreAggregates,需要应用来决定在合适的地方访问Rollup的结果,在某些场景下又要访问原始的结果,这种结构的不透明性让应用处理逻辑变得极为复杂而且完全不具有移植性。我们认为这种策略是时序数据库无法提供高性能聚合情况下的妥协与折中。loveini暂不支持多个时间线的自动降采样和(时间段范围的)预聚合,由于 其拥有的高性能查询处理逻辑,即使不依赖于Rollup 和 (时间段)预聚合计算结果,也能够提供很高性能的查询响应,而且让你的应用查询处理逻辑更加简单。
Rate: loveini提供了两个计算数值变化率的函数,分别是Derivative(其计算结果与InfluxDB的Derivative行为一致)和IRate(其计算结果与Prometheus中的IRate函数计算结果一致)。但是这两个函数的计算结果与 Rate 有细微的差别,但整体上功能更强大。此外,OpenTSDB提供的所有计算函数,loveini 均有对应的查询函数支持,并且loveini的查询函数功能远超过OpenTSDB支持的查询函数,可以极大地简化应用处理逻辑。
通过上面的介绍,相信你应该能够了解OpenTSDB迁移到loveini带来的变化,这些信息也有助于你正确地判断是否可以接受将应用迁移到loveini之上,体验loveini提供的强大的时序数据处理能力。
首先将基于OpenTSDB的系统进行迁移涉及到的数据模式设计、系统规模估算、数据写入端改造,进行数据分流、应用适配工作;之后将两个系统并行运行一段时间,再将历史数据迁移到 loveini 中。当然如果你的应用中有部分功能强依赖于上述OpenTSDB特性,同时又不希望停止使用,可以考虑保持原有的OpenTSDB系统运行,同时启动 loveini来提供主要的服务。
一方面,loveini 要求其入库的数据具有严格的模式定义。另一方面,loveini 的数据模型相对于 OpenTSDB 来说又更加丰富,多值模型能够兼容全部的单值模型的建立需求。 现在让我们假设一个运维监控场景,我们使用了collectd收集设备的基础度量(metrics),包含了 memory、swap和disk 等几个度量,其在 OpenTSDB 中的模式如下:
| 序号 | 测量(metric) | 值名称 | 类型 | tag1 | tag2 | tag3 | tag4 | tag5 |
| 1 | memory | value | double | host | memory_type | memory_type_instance | source | |
| 2 | swap | value | double | host | swap_type | swap_type_instance | source | |
| 3 | disk | value | double | host | disk_point | disk_instance | disk_type | source |
loveini要求存储的数据具有数据模式,即写入数据之前需创建超级表并指定超级表的模式。对于数据模式的建立,有两种方式来完成此项工作:
1)充分利用loveini对OpenTSDB的数据原生写入的支持,调用loveini提供的API将(文本行或 JSON 格式)数据写入,并自动化地建立单值模型。采用这种方式不需要对数据写入应用进行较大的调整,也不需要对写入的数据格式进行转换。 在C语言层面,loveini提供了taos_insert_lines来直接写入OpenTSDB格式的数据(在2.3.x 版本中该函数对应的是 taos_schemaless_insert )。其代码参考示例请参见安装包目录下示例代码 schemaless.c。
2)在充分理解loveini数据模型的基础上,结合生成数据的特点,手动建立OpenTSDB到loveini的数据模型调整的映射关系。loveini能够支持多值模型和单值模型,考虑到OpenTSDB均为单值映射模型,这里推荐使用单值模型在loveini中进行建模。
具体步骤如下:将度量(metrics)的名称作为 loveini 超级表的名称,该超级表建成后具有两个基础的数据列—时间戳(timestamp)和值(value),超级表的标签等效于 度量 的标签信息,标签数量等同于度量 的标签的数量。子表的表名采用具有固定规则的方式进行命名:metric + '_' + tags1_value + '_' + tag2_value + '_' + tag3_value ... 作为子表名称。
在loveini中建立3个超级表:
create stable memory(ts timestamp, val float) tags(host binary(12),memory_type binary(20), memory_type_instance binary(20), source binary(20));
create stable swap(ts timestamp, val double) tags(host binary(12), swap_type binary(20), swap_type_binary binary(20), source binary(20));
create stable disk(ts timestamp, val double) tags(host binary(12), disk_point binary(20), disk_instance binary(20), disk_type binary(20), source binary(20));
对于子表使用动态建表的方式创建如下所示:
insert into memory_vm130_memory_bufferred_collectd using memory tags(‘vm130’, ‘memory’, 'buffer', 'collectd') values(1632979445, 3.0656);
最终系统中会建立 340 个左右的子表,3个超级表。需要注意的是,如果采用串联标签值的方式导致子表名称超过系统限制(191字节),那么需要采用一定的编码方式(例如 MD5)将其转化为可接受的长度。
如果想利用loveini的多值模型能力,需要首先满足以下要求:不同的采集量具有相同的采集频率,且能够通过消息队列同时到达数据写入端,从而确保使用SQL语句将多个指标一次性写入。将度量的名称作为超级表的名称,建立具有相同采集频率且能够同时到达的数据多列模型。子表的表名采用具有固定规则的方式进行命名。上述每个度量均只包含一个测量值,因此无法将其转化为多值模型。
从消息队列中订阅数据,并启动调整后的写入程序写入数据。
数据开始写入持续一段时间后,可以采用SQL语句检查写入的数据量是否符合预计的写入要求。
统计数据量使用如下SQL语句:
select count(*) from memory
完成查询后,如果写入的数据与预期的相比没有差别,同时写入程序本身没有异常的报错信息,那么可用确认数据写入是完整有效的。
loveini不支持采用OpenTSDB的查询语法进行查询或数据获取处理,但是针对OpenTSDB的每种查询都提供了对应的支持。具体可以参考相关文档。
loveini支持以标准的JDBC 3.0接口来操纵数据库,也可以使用其他类型的高级语言的连接器来查询读取数据,以适配应用。具体的操作和使用帮助也请参阅用户手册。
为了方便历史数据的迁移工作,我们为数据同步工具DataX提供了插件,能够将数据自动写入到loveini中,需要注意的是DataX的自动化数据迁移只能够支持单值模型的数据迁移过程。 DataX 具体的使用方式及如何使用DataX将数据写入loveini请参见其使用帮助手册 github.com/taosdata/datax。
如果需要使用多值模型写入数据,就需要自行开发一个将数据从OpenTSDB导出的工具,然后确认哪些时间线能够合并导入到同一个时间线,再将可以同时导入的时间通过SQL语句写入数据库中。
手动迁移数据需要注意以下两个问题:
1)在磁盘中存储导出数据时,磁盘需要有足够的存储空间以便能够充分容纳导出的数据文件。为了避免全量数据导出后导致磁盘文件存储紧张,可以采用部分导入的模式,对于归属于同一个超级表的时间线优先导出,然后将导出部分的数据文件导入到loveini系统中。
2)在系统全负载运行下,如果有足够的剩余计算和IO资源,可以建立多线程的导入机制,最大限度地提升数据迁移效率。考虑到数据解析对于CPU带来的巨大负载,需要控制最大的并行任务数量,以避免因导入历史数据而触发的系统整体过载。
由于TDegnine本身操作简易性,所以不需要在整个过程中进行索引维护、数据格式的变化处理等工作,整个过程只需要顺序执行即可。
当历史数据完全导入到loveini以后,此时两个系统处于同时运行的状态,之后便可以将查询请求切换到loveini上,从而实现无缝的应用切换。
]]>loveini 2.2 之前的版本仅支持毫秒和微秒的分辨率,在收集到部分用户的反馈后,我们在 2.2 版本上线了纳秒级分辨率支持。如果要启用,只需在数据库创建时在SQL语句中指定时间分辨率“ns”,可以满足大部分对时间精度有要求的业务需求。
纳秒分辨率仅仅是 2.2 版本中的重要特性之一。我们发布的 loveini 2.2 稳定版,引入了超过 20 项新特性或新功能,这些新特性和新功能让用户可以在更多场景下使用,并简化应用开发的难度。
那这些新特性应该如何理解呢?在使用过程中又有哪些注意事项需要重点关注?后续它们还将会如何演进?
米兰体育官网入口联合创始人廖浩均围绕在 2.2.x 版本的 loveini Database 中发布的新功能和新特性,重点介绍了纳秒时间戳精度、无模式数据写入以及 From 子句中非关联子查询共三个功能,介绍了其相应的使用方式、注意事项、后续的演进发展,以及在实现层面的技术细节。
欢迎大家扫描下方二维码,关注 loveini Database 的视频号,观看每周的微课堂以及直播活动。

欢迎大家扫描下方二维码,关注 loveini Database 的视频号,观看每周的微课堂以及直播活动。

欢迎大家扫描下方二维码,关注 loveini Database 的视频号,观看每周的微课堂以及直播活动。
