时间序列数据库的 What、Why 和 How

导航至

本文由 Thamatam Vijay Kumar 撰写。向下滚动查看作者简介和照片。

现代网站上充满了仪表板,其中包含丰富的图表、折线图、雷达图以及复合图。世界对这些图表和图形着迷,它们为千禧一代的 Web 应用程序提供了很多价值。有许多这样的图表库提供交互式可视化并为用户提供数据洞察。

图表使用数据点绘制线条。这些图表库帮助我们分析数据,数据点范围从数百个到数百万个,时间范围从几分钟到几年,并且还使用工具提示、图例和聚合显示其他信息。

Example-of-a-multigraph-showing-car-engine-data-for-every-minute-ranging-for-a-day

显示汽车发动机数据的复合图示例,数据间隔为每分钟,时间范围为一天

上面的示例显示了图表显示数千个数据点的能力,帮助用户更信息化地分析发动机数据并了解发动机健康状况。

在这篇文章中,我们将介绍如何存储和查询时间序列数据,这是现代图表的主要数据源。

什么是时间序列?

时间序列数据是为变量在时间间隔内收集的一系列数据点,使我们能够跟踪随时间的变化。时间序列是关于变量的时间导向或按时间顺序排列的观测序列。

由于时间序列中的数据点是在不同的时间段收集的,因此观测之间可能存在相关性。这是时间序列数据与其他数据区分开来的特征之一。

时间序列数据可以在金融、健康、制造、物联网、物理科学等领域找到。

示例包括

  • 公司的股票价值
  • 患者各种健康参数(如血压、血糖、氧气)的健康监测值
  • 各种汽车发动机传感器(如速度、扭矩、油、冷却液)的值
  • 用于调节温度和识别入侵者的智能家居监控器

以下是汽车发动机传感器的示例数据,采用时间序列格式

sample-data

如上所示,数据是关于汽车发动机中多个传感器在不同时间间隔内的数据。这些数据帮助我们了解和分析发动机在不同时间段(从几分钟到几年)内的状况。

何时使用时间序列

但是我们什么时候可以使用时间序列?在哪些用例中我们将数据存储在时间序列数据库中?

如上所述,当您有连续的数据流需要在并发或不同时间戳的时间段内存储值时,这些应用程序需要一种特殊的数据库。

常见的时间序列数据库用例包括

  1. 访问物联网数据(发动机、智能家电等)
  2. 监控 Web 服务、应用程序和基础设施
  3. 金融动向
  4. 自动驾驶汽车数据
  5. 自主交易算法
  6. 零售行业交付

此外,如果您预见到需要为不同值的连续时间戳存储任何数据流,那么对于存储时间序列数据,最明智的选择是使用专门构建的时间序列数据库。

您可能会问:为什么我们不能将这些数据存储在关系数据库中而不是时间序列数据库中

为什么要使用时间序列数据库

随着时间的推移,带时间戳的数据量不断增长,并且很难在常规数据库中存储连续的数据流。

我们正在观察物理世界中每个可用外部的仪器化——汽车、医疗器械、发电厂、电话、家用电器、人体和许多其他事物。一切都有或将会有传感器发出无情的时间序列数据流。这需要一个能够处理如此大数据负载的平台。

假设传感器每秒发送一次数据,而您拥有 10000 台发动机,每台发动机有 100 个传感器值。这将导致在数据库中存储 80 亿条以上的记录。一个月和一年后,在传统数据库中存储如此大量的数据变得不可能,并且对于诸如获取一年中 10 个传感器的数据之类的简单查询,查询此类数据库也是不可能的。这就是世界竞相采用时间序列数据库来存储和检索数据的原因,用于时间序列用例和连续数据流。

时间序列数据库的两个替代方案是 RDBMSNoSQL

关系数据库管理系统 (RDBMS) 可用于存储和检索时间序列数据。凭借 RDBMS 的灵活性,它们可以存储与 TSDB 相同的数据。一个关键的区别是 RDBMS 没有针对时间序列数据进行优化,并且随着数据量的不断增长(如上面的示例中讨论的那样),在插入和检索时间序列数据时往往会更慢。

另一种类型的数据库 NoSQL 也经常用于存储时间序列数据。由于NoSQL 数据库在每个记录的数据格式方面更灵活,因此它们非常适合从许多不同的来源捕获时间序列数据。但是,要查询 NoSQL 数据库意味着仔细检查模式并针对其编写自定义查询。诸如不同类型的连接之类的复杂操作,这些操作受益于 SQL 方面的数十年创新,在 NoSQL 阵营中可能会很慢甚至存在错误。

选择时间序列数据库

现在我们介绍了时间序列的定义和原因,让我们比较一下市场上一些流行的时间序列数据库,以及如何存储和检索连续数据流的数据。

  1. InfluxDB
  2. Graphite
  3. OpenTSDB
  4. TimescaleDB
名称 InfluxDB    Graphite    OpenTSDB    TimescaleDB   
描述 用于存储时间序列指标和事件的 DBMS 用于时间序列数据的数据记录和绘图工具 基于 HBase 的可扩展时间序列 DBMS 一种时间序列数据库,针对快速摄取和复杂查询进行了优化,基于PostgreSQL
主要数据库模型 时间序列 DBMS 时间序列 DBMS 时间序列 DBMS 时间序列 DBMS
辅助数据库模型 空间 DBMS  关系 DBMS
仅基于云
实现语言 Go Python Java C
数据模式 无模式 无模式
类型 数值数据和字符串 仅数值数据 指标的数值数据,标签的字符串 数值、字符串、布尔值、数组、JSON blob、地理空间维度、货币、二进制数据、其他复杂数据类型
XML 支持
二级索引
查询语言 类 SQL 查询语言
API 和其他访问方法 HTTP API JSON over UDP HTTP API 套接字 HTTP API Telnet API ADO.NET JDBC Native C library ODBC 流式 API 用于大型对象
支持的编程语言 .Net, Clojure, Erlang, Go, Haskell, Java, JavaScript, JavaScript (Node.js), Lisp, Perl, PHP, Python, R, Ruby, Rust, Scala JavaScript (Node.js), Python Erlang, Go, Java, Python R, Ruby .Net, C, C++, Delphi, Java, JavaScript, Perl, PHP, Python, R, Ruby, Scheme, Tcl
服务器端脚本 用户定义函数、PL/pgSQL、PL/Tcl、PL/Perl、PL/Python、PL/Java、PL/PHP、PL/R、PL/Ruby、PL/Scheme、PL/Unix shell
触发器
分区方法 分片 分片 是,跨时间和空间(哈希分区)属性

在评估用于您的工作负载的时间序列数据库时,需要考虑以下几个因素

  • 数据模型
  • 查询语言
  • 可靠性
  • 性能
  • 生态系统
  • 运营管理和支持

通常,数据库评估基于性能目标。但是,性能只是整体评估的一部分。如果数据库在数据模型、查询语言或生产工作负载所需的可靠性方面存在不足,则它将无法高效运行。上表比较了时间序列数据库在定性维度(数据模型、查询语言和可靠性)上的表现。

在当前不断增长的时间序列数据库市场中,InfluxDB 作为有前景的整体时间序列数据库脱颖而出。凭借良好的技术文档,InfluxDB 易于安装、配置和入门。由于它是一个类似 NoSQL 的数据库,我们插入数据就可以开始使用了。

在做出决定之前,请退后一步,研究您的技术栈、团队技能以及您现在和不久的将来的需求。

如何存储和查询时间序列数据

让我们研究一下如何在 InfluxDB 中存储和查询时间序列数据。

存储数据

下载安装 InfluxDB。(请注意,撰写本文时,最新版本是InfluxDB 2.2)。

一旦 InfluxDB 安装并设置了用户权限,我们就可以开始写入和查询数据了。

在写入 InfluxDB 之前,重要的是要学习一些关键术语

  • 测量:InfluxDB 数据结构的一部分,描述存储在关联字段中的数据

  • 标签:严格来说,标签是可选的,但大多数系列都包含标签以区分数据源,并使查询变得容易和高效。标签键和标签值都是字符串。

  • 字段(必需):字段键是必需的,并且始终是字符串;默认情况下,字段值是浮点数。

  • 时间戳:在行尾以 Unix 时间(自 1970 年 1 月 1 日 UTC 以来的纳秒数)提供 - 是可选的。如果您未指定时间戳,则 InfluxDB 使用服务器的本地纳秒时间戳(Unix 纪元)。默认情况下,InfluxDB 中的时间采用 UTC 格式。

如果您是时间序列新手,这些术语可能有点难以理解,因此这里有一个解释

InfluxDB 测量类似于 SQL 数据库表。
InfluxDB 标签类似于 SQL 数据库中的索引列。
InfluxDB 字段类似于 SQL 数据库中的非索引列。
InfluxDB 点类似于 SQL 行。

InfluxDB 提供了多种写入和查询数据的机制。

  1. Telegraf 插件

  2. InfluxDB API

  3. Influx 命令行

在这里,我们使用 API 机制,使用提供的写入端点来写入和存储数据

/write HTTP 端点

POST http://localhost:8086/write

我们可以使用上面的 API 将数据写入 InfluxDB。写入数据的语法如下:‘Measurement, tagkey = ’tag value’, fieldkey = ’fieldvalue’, Epoch timestamp‘。

$ curl -i -XPOST "http://localhost:8086/write?db=mydb" --data-binary 'enginespeed,serialnumber=10001 value=129 1463689152000000000
 enginespeed,serialnumber=10001 value=84 1463689152000000000
 enginespeed,serialnumber=10001 value=79 1463689152000000000
 torque,serialnumber=10001 value=11 1463689152000000000
 torque,serialnumber=10001 value=23 1463689152000000000
 torque,serialnumber=10001 value=32 1463689152000000000
 power,serialnumber=10001 value=1200 1463689152000000000
 power,serialnumber=10001 value=1100 1463689152000000000
 power,serialnumber=10001 value=1000 1463689152000000000

HTTP/1.1 204 No Content
Content-Type: application/json
Request-Id: [...]
X-Influxdb-Version: 1.4.x
Date: Wed, 08 Nov 2017 18:04:02 GMT

此写入会将数据插入到多个测量(发动机速度、扭矩、功率)中。

在这里,我们正在保存与汽车发动机值相关的数据,这些数据用于一系列纪元时间戳。

通过这种方式,我们可以将连续的数据流存储到 InfluxDB 中以供进一步查询。

同样,数据也可以使用 CLI 和 Telegraf 插件写入 InfluxDB。

查询数据

将数据写入 InfluxDB 后,可以使用简单的 InfluxDB 查询通过查询端点执行查询

/query HTTP 端点

GET http://localhost:8086/query

我们可以使用上面的 API 从 InfluxDB 查询数据;写入数据的语法如下

‘Measurement, tagkey = ’tag value’, fieldkey = ’fieldvalue’, Epoch timestamp‘。

$ curl -G 'http://localhost:8086/query?db=mydb' --data-urlencode 'q=SELECT * FROM "enginespeed"'

结果可以以 JSON 格式检索,如下所示

"results": [
        {
            "statement_id": 0,
            "series": [
                {
                    "name": "engiespeed",
                    "columns": [
                        "time",
                        "value",
                        "serialnumber"
                    ],
                    "values": [
                        [
                            "2017-03-01T00:16:18Z",
                            129,
                            10001
                        ],
                        [
                            "2017-03-01T00:17:18Z",
                            84,
                            10001
                        ],
                        [
                            "2017-03-01T00:17:18Z",
                            79,
                            10001
                        ]

                    ]
                }
            ]
        }
    ]
}

我们还可以在查询中执行所有聚合和分组,以检索所需的数据。具有选择和聚合器子句组合的示例查询将如下所示

选择与字段键关联的最大字段值,并包含多个子句

> SELECT MAX("water_level") FROM "h2o_feet" WHERE time >= '2015-08-17T23:48:00Z' AND time <= '2015-08-18T00:54:00Z' GROUP BY time(12m)

name: h2o_feet
tags: location=coyote_creek
time                   max
----                   ---
2015-08-17T23:48:00Z   9.01
2015-08-18T00:00:00Z   8.12
2015-08-18T00:12:00Z   7.887
2015-08-18T00:24:00Z   7.635

这样,我们可以根据我们的需要使用不同的子句执行查询,并以时间序列格式获取数据。如开头所示,相同的数据可用于绘制各种图表,这些图表可用于生成更多关于该数据的见解和预测。此外,这些数据还可以用于故障排除和了解指标和事件流。

在本文中,我尝试以 InfluxDB 为例介绍了时间序列数据库的定义、原因和方法。由于专家们认识到对时间序列数据库的新兴需求,我建议更多地了解时间序列,因为以时间序列格式存储您的项目可能会改变游戏规则。

关于作者

Thamatam-Vijay-Kumar

Thamatam Vijay Kumar 是 Bosch 的数据架构师,在构建云解决方案和数据管理方面拥有 11 年以上的经验。他对构建解决方案和产品充满热情,并强烈希望架构它们。他曾从事多种技术工作,主要涉及云服务和数据管理,并从事解决方案的设计、开发和部署工作。