InfluxDB是一个很流行的基于时间序列的数据库,下面是这个数据库的最基本的查询命令。InfluxDB使用类SQL(实际上它就是一种特殊的“SQL”)的语言。
SELECT * FROM "foodships" WHERE time > now() - 1h
一开始InfluxDB就支持这种类SQL语言,所以它也同时兼备了这类语言的优缺点:
- 对于新用户来说很容易用他们掌握的语言与数据库进行交互。SQL很流行,所以许多开发人员都会使用。这种查询语法对InfluxDB的早期发展很有帮助。
- 正如我之前所说的,InfluxQL是一种“类SQL”的语言。编写SQL查询语言不是一件简单的工作。其中一个问题就是DBA包含了一些SQL的预期设计,但是我们的语言与SQL并不完全兼容。这就造成了许多无法令人头疼的问题。
- 时间序列数据库的特点之一是读写可以同时进行。这其实也是这类数据库的必备特性。你的物联网设备或服务器一直在写入数据,而与此同时仪表板,分析工具和警报管理器将从数据库读取数据。InfluxDB需要更好的可扩展性。
- 如果相同时刻存储引擎和查询语言都在同一个项目中,这会阻碍我们想要的代码的快速迭代功能。与存储引擎相比,查询语言更快地优化。引擎需要稳定性,而查询语言需要的更多的是功能和性能。
- InfluxQL需要重新进行架构,因为开发者团队无法保证满足社区里面千奇百怪的想法。
- 现在的话,SQL学习起来非常简单,但我们的栈中还有另一个DSL可采用:从Kapacitor使用的TICK脚本发送警报并对缩减你的系列样本。
- 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用户,可以随时打开论坛或者提供有关您的使用的反馈信息,以帮助我们改进语法。