如何查询InfluxDB

December 17, 2023
测试
测试
测试
测试
13 分钟阅读

InfluxDB是一个很流行的基于时间序列的数据库,下面是这个数据库的最基本的查询命令。InfluxDB使用类SQL(实际上它就是一种特殊的“SQL”)的语言。

SELECT * FROM "foodships" WHERE time > now() - 1h

一开始InfluxDB就支持这种类SQL语言,所以它也同时兼备了这类语言的优缺点:

  1. 对于新用户来说很容易用他们掌握的语言与数据库进行交互。SQL很流行,所以许多开发人员都会使用。这种查询语法对InfluxDB的早期发展很有帮助。
  2. 正如我之前所说的,InfluxQL是一种“类SQL”的语言。编写SQL查询语言不是一件简单的工作。其中一个问题就是DBA包含了一些SQL的预期设计,但是我们的语言与SQL并不完全兼容。这就造成了许多无法令人头疼的问题。
  3. 时间序列数据库的特点之一是读写可以同时进行。这其实也是这类数据库的必备特性。你的物联网设备或服务器一直在写入数据,而与此同时仪表板,分析工具和警报管理器将从数据库读取数据。InfluxDB需要更好的可扩展性。
  4. 如果相同时刻存储引擎和查询语言都在同一个项目中,这会阻碍我们想要的代码的快速迭代功能。与存储引擎相比,查询语言更快地优化。引擎需要稳定性,而查询语言需要的更多的是功能和性能。
  5. InfluxQL需要重新进行架构,因为开发者团队无法保证满足社区里面千奇百怪的想法。
  6. 现在的话,SQL学习起来非常简单,但我们的栈中还有另一个DSL可采用:从Kapacitor使用的TICK脚本发送警报并对缩减你的系列样本。
  7. InfluxQL没有数学函数库,因为语言不允许我们用简单的方式添加数据。而使用IFQL,我们却很容易实现它们。

在旧金山的InfluxDays期间,InfluxData的首席技术官兼创始人Paul Dix发布了一种新的开源查询语言,其数据分析与InfluxDB很接近。我们称之为IFQL。

架构

var cpu = select(db: "telegraf")
  .filter(exp:{"_measurement" == "cpu" and "_field" == "usage_user"})
  .range(start: -30m)
  
select(db: "telegraf")
  .filter(exp:{"_measurement" == "mem" and "_field" == "used_percent"})
  .range(start: -30m)
  .join(on:["host"], eval:{$ + cpu})

IFQL不只是一种查询语言。它还包含有一个解析器,可以读取上面的查询,并生成一个可视化为JSON,然后通过IFQL直接运行。这意味着你所看到的语法只是其中一种可能的实现。真正重要的部分是在设计和处理器之间。

这个项目的架构和思想让我们可以在IFQL AST之上重新实现InfluxQL和PromQL,TICK Script。除此之外,如果你有你的查询构建器或者你需要创建一个自定义的实现来与InfluxDB交互,你可以简单地将JSON推送到IFQL。这的确很令人很意外。

IFQL的设计是可扩展的,为了实现这个特性 - 我们从Telegraf项目学到了深刻的教训。你需要一个简单的接口和一个接入点,这样开发人员才会很乐意为你的项目做出贡献。这就是为什么IFQL有一个叫做函数目录的原因。它包含当前支持的所有函数,并且希望添加功能的贡献者只在该目录中添加函数。

TICK Script和IFQL

IFQL的目的之一是能够提供TICK Script提供的所有功能,这样我们就能够在不学习两种语言的情况下进行查询,操作和发送警报。

目前,我们已经将两个项目中函数复制了,这样我们就可以通过IFQL再次使用它们。

目前,IFQL是GitHub上的一个独立项目。除了解析器和设计器之外,它还提供了一个简单的名叫 ifqld的http后台程序,用于进行一些测试。

IFQL仍处于测试阶段,这意味着API和查询语法可能将会更改,但它设置起来非常简单。我将使用Docker来举个例子,如果您不熟悉Docker,则可以在此处下载IFQL的安装包 。

我们先从IFQL存储库下载一个InfluxDB配置文件:

wget https://raw.githubusercontent.com/influxdata/ifql/master/docker-compose.yml
mkdir examples
wget https://raw.githubusercontent.com/influxdata/ifql/master/examples/influxdb.conf -O examples/influxdb.conf

主要区别在于后者支持IFQL的段落:

[ifql]
  enabled = true
  log-enabled = true
  bind-address = ":8082"

InfluxDB使用端口8082与IFQL的gRPC进行通信。

docker-compose up

如您所见,我们创建了一个网络并部署了两个容器。一个是InfluxDB,我们修改了配置,并暴露了8082和8086端口。第二个是IFQL v0.0.2。它使用了端口8093,我们可以通过运行一个简单的curl来验证一切是否正常工作。

15:21 $ curl -I http://localhost:8093/
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Tue, 28 Nov 2017 14:21:40 GMT
Content-Length: 19

现在让我们用一些示例数据填充我们的数据库:

curl https://s3.amazonaws.com/noaa.water-database/NOAA_data.txt -o NOAA_data.txt
influx -import -path=NOAA_data.txt -precision=s -database=NOAA_water_database
influx
use NOAA_water_database
SELECT COUNT(*) FROM NOAA_water_database
> SELECT COUNT(*) FROM h2o_feet
name: h2o_feet
time count_level description count_water_level
---- ----------------------- -----------------
0    15258                   15258

正如看到的,我们有一些时间点和记录值。现在我们将使用curl运行一些基本示例与进行ifqld交互:

20:11 $ curl -XPOST --data-urlencode 'q=from(db:"NOAA_water_database").filter(exp:{"_measurement"=="h2o_temperature"}).range(start: -500000h).limit(n: 10)' http://localhost:8093/query       
h2o_temperature,location=coyote_creek degrees=60 1439856000000000000                           
h2o_temperature,location=coyote_creek degrees=65 1439856360000000000                           
h2o_temperature,location=coyote_creek degrees=68 1439856720000000000                           
h2o_temperature,location=coyote_creek degrees=62 1439857080000000000                           
h2o_temperature,location=coyote_creek degrees=62 1439857440000000000                           
h2o_temperature,location=coyote_creek degrees=69 1439857800000000000                           
h2o_temperature,location=coyote_creek degrees=67 1439858160000000000                           
h2o_temperature,location=coyote_creek degrees=67 1439858520000000000                           
h2o_temperature,location=coyote_creek degrees=70 1439858880000000000                           
h2o_temperature,location=coyote_creek degrees=65 1439859240000000000                           
h2o_temperature,location=santa_monica degrees=70 1439856000000000000                           
h2o_temperature,location=santa_monica degrees=60 1439856360000000000                           
h2o_temperature,location=santa_monica degrees=62 1439856720000000000                           
h2o_temperature,location=santa_monica degrees=62 1439857080000000000                           
h2o_temperature,location=santa_monica degrees=60 1439857440000000000                           
h2o_temperature,location=santa_monica degrees=63 1439857800000000000                           
h2o_temperature,location=santa_monica degrees=64 1439858160000000000                           
h2o_temperature,location=santa_monica degrees=63 1439858520000000000                           
h2o_temperature,location=santa_monica degrees=63 1439858880000000000                           
h2o_temperature,location=santa_monica degrees=61 1439859240000000000

让我们将from(db:"NOAA_water_database").filter(exp:{"_measurement"=="h2o_temperature"}).range(start: -500000h).limit(n: 10)

与InfluxQL 进行比较:

  • from有点像SQL的select。它选择database来查询。
  • 在 filter里面有一些特定的关键字被数据库自身使用,比如_measurement。在这种情况下,它通过测量h2o-temperature进行过滤。
  • limit(10)在这种情况下返回20行。为什么是这样?这是我们构建的查询语言的第一个差异。有一种隐式的说法是按照 group by *的方式分组。在这种情况下,有两个系列:h2o_temperature, location=sata_monica和 h20_temperature,location=coyote_creek。如果你需要一个特定的系列,你应该添加.filter(exp:{"_measurement"=="h2o_temperature" AND "location" == "coyote_creek"})

查询语言背后的一些重要决定:

  • 参数的功能顺序并不重要。每个参数都有一个名称,并不是强制性的。
  • 必须使用 ",以避免单引号和双引号之间的不匹配。

IFQL将每个查询从特定语法简化为JSON AST。您可以通过添加查询参数 analyze=true

来获取特定查询的AST 。

from(db:"NOAA_water_database").filter(exp:{"_measurement"=="h2o_temperature"}).range(start:
-500000h).limit(n: 10)

IFQL项目文档中的README.md包含所有其他可用的功能的说明。

可扩展性

ifqld是一个无状态的HTTP守护进程程序,因此它可以比InfluxDB(或其他数据库)更容易地扩展和缩减,因为不涉及任何状态或数据。一些功能,例如filters,被推送到引擎(并非所有情况下),因为InfluxDB能够检索时间序列和所有要求的点。

其他的一些功能,如聚合功能,不会推送到InfluxDB,但是一旦从数据库获取数据,ifqld 进程就会立即运行。这使我们能够以更灵活的方式扩展阅读和聚合。如果有更多的查询或更多的计算需求,我们可以启动更多的 ifqld进程,而不必关心底层存储。

可伸缩性的另一个重要方面就是 ifqld可以查询多个。

19:56 $ curl -s -XPOST --data-urlencode 'q=from(db:"NOAA_water_database").range(start: 200h).count()' http://localhost:8093/query?analyze=true | jq
{
  "operations": [
    {
      "id": "from0",
      "kind": "from",
      "spec": {
        "database": "NOAA_water_database",
        "hosts": null
      }
    },
    {
      "id": "range1",
      "kind": "range",
      "spec": {
        "start": "200h0m0s",
        "stop": "now"
      }
    },
    {
      "id": "count2",
      "kind": "count",
      "spec": {}
    }
  ],
  "edges": [
    {
      "parent": "from0",
      "child": "range1"
    },
    {
      "parent": "range1",
      "child": "count2"
    }
  ]
}

使用CLI参数--host=或环境变量$HOSTS可以指定多个后端。这意味着如果您运行的是开源版本,并且您可以在更多利用更多的数据库管理数据分片,还可以进行横向扩展。

路线图

该项目还不稳定,仍快速发展阶段。API和输出可以根据您和我们在查询语言方面的经历进行更改。这个想法是在2018年初固定API样式。如果您是一名活跃的InfluxDB用户,可以随时打开论坛或者提供有关您的使用的反馈信息,以帮助我们改进语法。

继续阅读

更多来自我们博客的帖子

如何安装 BuddyPress
由 测试 December 17, 2023
经过差不多一年的开发,BuddyPress 这个基于 WordPress Mu 的 SNS 插件正式版终于发布了。BuddyPress...
阅读更多
Filter如何工作
由 测试 December 17, 2023
在 web.xml...
阅读更多
如何理解CGAffineTransform
由 测试 December 17, 2023
CGAffineTransform A structure for holding an affine transformation matrix. ...
阅读更多