我的积分发生了什么?

导航到

本文探讨了在写入InfluxDB时拒绝无效数据的一些方法,并描述了一个新的功能,该功能使得更容易知道何时以及为什么会发生这种情况。

语法错误

让我们使用命令行工具influx 将一些数据写入InfluxDB Cloud。

% echo '
humidity,location=greenhouse value=85
temperature, location=house value=23
temperature, location=greenhouse value=10
' | influx write
Error: failed to write data: 400 Bad Request: partial write error (1 accepted): 2/3 points rejected; first error: at line 3:13: expected tag key after comma; got white space instead (check rejected_points in your _monitoring bucket for further information)

哎呀,看起来我们弄错了!幸运的是,这个错误消息,虽然有些吓人,但它告诉我们很多关于发生了什么的信息。让我们将其分解成几个部分。

错误:写入数据失败:400 请求错误

这告诉我们,错误是从服务器返回的,作为对写入数据的HTTP请求的响应,问题出在客户端,而不是服务器上出了问题。

部分写入错误(1个接受):2/3个点被拒绝

这告诉我们,并非所有数据都是坏的。InfluxDB Cloud会尽可能接受您的大部分数据。在这里,有一个点是好的,但其他两个有问题。

第一个错误

可以在单个写入中发送成千上万的数据点。而不是返回成千上万的错误消息,它只返回第一个。

第3行第13列

这告诉我们问题出现在输入中的位置:在第3行的第13列。这指向了my_point后面的逗号之后的空格。

在逗号之后期望标签键;得到的是空格

我们在第一个逗号后面有一个空格,所以它不是有效的语法。(如果您在问自己,什么是有效的行协议语法,您就在正确的地方:请参阅本文后面的详细信息)。

(在您的_monitoring存储桶中检查rejected_points以获取更多信息)

错误信息的最后一部分是将您的注意力引向一个新功能:当点被拒绝时,拒绝信息会被写入您组织的_monitoring存储桶下的rejected_points 度量。写入的信息将包括有关所有被拒绝点的信息,而不仅仅是第一个。

在下一部分,我们将更详细地探讨这一点。

监控拒绝的点

在上一个部分中,我们看到了write端点是如何返回它遇到的第一个语法错误的。它还将一些信息写入您的_monitoring桶,描述所有已遇到的错误。

在上述示例中,它写入以下数据

rejected_points,bucket=6355a1b5287f84c2,reason=parse\ error count=1,error="at line 3:13: expected tag key after comma; got white space instead"
rejected_points,bucket=6355a1b5287f84c2,reason=parse\ error count=1,error="at line 4:13: expected tag key after comma; got white space instead"

该桶是正在写入的桶的十六进制ID(您可以通过在Cloud 2 UI的“加载数据”选项卡中查找您的桶来找到这一点)。reason标签提供了点被拒绝的一般原因。error字段提供了您之前看到的语法错误——我们可以看到现在有两个错误,每个错误对应一行。count 字段可以用来轻松地汇总随时间拒绝的点数。

与写入_monitoring桶的所有数据一样,这些数据将被保留七天

将拒绝点的信息存储在普通桶中,可以轻松地使用所有常规Influx工具来跟踪这种情况发生的程度。如果有一个有误的客户端,您将能够在那里看到它。

传输中丢失

当写入行协议数据时,API会检查语法有效性,这也是为什么Influx客户端能够打印上面的语法错误,但并非所有错误都会立即进行检查。当一个点进入InfluxDB Cloud时,它会被添加到一个持久队列中,但不会立即与其他数据库部分集成。这是它如此高效的一个原因,但也意味着如果写入了一个具有冲突类型的字段(例如,用字符串代替了浮点数),则无法将结果错误返回给客户端,因为客户端已经得到了响应。

直到最近,这是一个无声的错误。具有冲突字段类型的点被丢弃,没有向用户发出任何提示。

但现在您可以通过查看_monitoring桶来了解这些错误,就像查看语法错误一样。

让我们试试。在这里,我们将写入一些点,这些点有一个字符串字段value ,而我们之前写入的是浮点数

% echo '
humidity,location=greenhouse value="bad1"
humidity,location=greenhouse value="bad2"
humidity,location=greenhouse value=94
' | influx write
%

写入似乎成功了。然而,如果我们查看_monitoring桶,我们会看到以下条目已经出现

rejected_points,bucket=6355a1b5287f84c2,field=value,gotType=String,measurement=humidity,reason=type\ conflict\ with\ existing\ data,wantType=Float count=2
rejected_points,bucket=6355a1b5287f84c2,field=value,gotType=Float,measurement=humidity,reason=type\ conflict\ in\ batch\ write,wantType=String count=1

这告诉我们,有两个点(count=2)因为与value 字段的现有数据类型冲突而被拒绝。另一个点也被拒绝,因为它与其批次内其他点的字段类型冲突——即使这个点(写入中的第三个)在技术上对该桶具有正确的类型,但单个写入中的点的类型必须保持一致,无论当前存储了什么,所以它在最终类型检查之前就被拒绝了。

请注意,location=greenhouse 标签没有出现在拒绝点信息中。只有字段和测量值。这样做的原因是为了控制rejected_point 测量的基数——我们不想让拒绝点使用与数据已存储时的基数一样多的资源!

绘图

在本节中,我将描述一些我们发现有用的查询,以跟踪拒绝的点。您可以使用这些作为您自己的仪表板的起点。

我们可以使用类似以下的查询来了解随时间发生的拒绝点的总体数量

from(bucket: "_monitoring")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r._measurement == "rejected_points")
  |> filter(fn: (r) => r._field == "count")
  |> group()
  |> aggregateWindow(every: v.windowPeriod, fn: sum, createEmpty: false)
  |> yield(name: "rejected points by reason")

Rejected point count

为了深入了解上述图表中突出的潜在原因,这里提供了一个查询,用于总结拒绝点的理由

from(bucket: "_monitoring")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r._measurement == "rejected_points")
  |> filter(fn: (r) => r._field == "count")
  |> keep(columns: ["reason", "_value"])
  |> group(columns: ["reason"])
  |> sum()
  |> rename(columns: {"_value": "count"})
  |> group()
  |> yield(name: "reasons")

Reasons for rejected points

行协议语法定义

行协议格式的语法是什么?表面上看起来很简单,但魔鬼藏在细节里,直到最近,答案一直是“实现者说了算”,因为语法并没有精确定义。我们有语法参考,现在我们非常高兴能够分享新的、正式的行协议定义文档。我们编写了这份文档,并与新的行协议解析代码一起,力求准确无误,消除歧义。

对先前不同实现或文档中存在分歧的区域的几个值得注意的澄清

  • 只有ASCII空格字符和可选的结尾回车符才算作空白。具体来说,制表符和换页符不允许,除非在字符串字段值内。
  • 在字符串字段值内允许使用字面意义上的换行符。
  • 所有行协议数据必须编码为有效的UTF-8。
  • 度量、标签键、标签值和字段键不能包含非打印ASCII(代码点0-31和127)。

有一个新的Go参考实现实现了新的语法:github.com/influxdata/line-protocol/v2/lineprotocol,以及一个GitHub仓库,其中包含大量示例及其预期结果:https://github.com/influxdata/line-protocol-corpus