使用二进制负载 - AWS IoT Core

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用二进制负载

当将消息负载作为原始二进制数据(而不是 JSON 对象)进行处理时,可以使用 * 运算符在 SELECT 子句中对其进行引用。

二进制负载示例

当您使用 * 将消息负载作为原始二进制数据进行引用时,您可以向规则添加数据。如果您有空的或 JSON 有效负载,生成的有效负载可以使用规则添加数据。下面显示了支持 SELECT 子句的示例。

  • 对于二进制有效负载,您可以将以下 SELECT 子句仅与 * 一起使用。

    • SELECT * FROM 'topic/subtopic'
    • SELECT * FROM 'topic/subtopic' WHERE timestamp() % 12 = 0
  • 您还可以添加数据并使用以下 SELECT 子句。

    • SELECT *, principal() as principal, timestamp() as time FROM 'topic/subtopic'
    • SELECT encode(*, 'base64') AS data, timestamp() AS ts FROM 'topic/subtopic'
  • 您还可以使用带二进制负载的 SELECT 子句。

    • 以下是指在 WHERE 子句中的 device_type

      SELECT * FROM 'topic/subtopic' WHERE device_type = 'thermostat'
    • 还支持以下内容。

      { "sql": "SELECT * FROM 'topic/subtopic'", "actions": [ { "republish": { "topic": "device/${device_id}" } } ] }

以下规则操作不支持二进制负载,因此您必须对它们进行解码。

  • 一些规则操作不支持二进制负载输入(例如,Lambda 操作),您必须解码二进制负载。如果 Lambda 规则操作是 base64 编码并在 JSON 负载中,则可以接收二进制数据。为此,您可以将规则更改如下:

    SELECT encode(*, 'base64') AS data FROM 'my_topic'
  • SQL 语句不支持字符串作为输入。要将字符串输入转换为 JSON,您可以运行以下命令。

    SELECT decode(encode(*, 'base64'), 'base64') AS payload FROM 'topic'

解码 protobuf 消息有效负载

协议缓冲区 (protobuf) 是一种开源数据格式,用于以紧凑的二进制形式序列化结构化数据。它用于通过网络传输数据或将数据存储在文件中。Protobuf 允许您以比其他消息格式更快的速度以较小的数据包大小发送数据。 AWS IoT Core 规则通过提供解码(值,decodingScheme)SQL 函数来支持 protobuf,该函数允许您将由 protobuf 编码的消息负载解码为 JSON 格式并将其路由到下游服务。本节详细介绍了在 “规则” 中配置 protobuf 解码的 step-by-step 过程。 AWS IoT Core

先决条件

创建描述符文件

如果您已有描述符文件,可以跳过此步骤。描述符文件 (.desc) 是 .proto 文件的编译版本,它是一个文本文件,用于定义 protobuf 序列化中使用的数据结构和消息类型。要生成描述符文件,必须定义一个 .proto 文件,并使用 protoc 编译器对其进行编译。

  1. 创建定义消息类型的 .proto 文件。示例 .proto 文件可能如下所示:

    syntax = "proto3"; message Person { optional string name = 1; optional int32 id = 2; optional string email = 3; }

    在此示例 .proto 文件中,使用 proto3 语法并定义消息类型 PersonPerson 消息定义指定三个字段(名称、ID 和电子邮件)。有关 .proto 文件消息格式的更多信息,请参阅语言指南 (proto3)

  2. 使用 protoc 编译器编译 .proto 文件并生成一个描述符文件。创建描述符 (.desc) 文件的示例命令如下所示:

    protoc --descriptor_set_out=<FILENAME>.desc \ --proto_path=<PATH_TO_IMPORTS_DIRECTORY> \ --include_imports \ <PROTO_FILENAME>.proto

    此示例命令生成一个描述符文件<FILENAME>.desc, AWS IoT Core 规则可以使用该文件来解码符合中定义的数据结构的 protobuf 有效负载。<PROTO_FILENAME>.proto

    • --descriptor_set_out

      指定应生成的描述符文件 (<FILENAME>.desc) 的名称。

    • --proto_path

      指定正在编译的文件所引用的任何导入的 .proto 文件的位置。如果您有多个位于不同位置的已导入 .proto 文件,可以多次指定此标志。

    • --include_imports

      指定还应编译任何已导入的 .proto 文件,并将其包含在 <FILENAME>.desc 描述符文件中。

    • <PROTO_FILENAME>.proto

      指定要编译的 .proto 文件的名称。

    有关 protoc 参考的更多信息,请参阅 API 参考

将描述符文件上传到 S3 存储桶

创建描述符文件后,使用 AWS API <FILENAME>.desc、S AWS DK 或,<FILENAME>.desc将描述符文件上传到 Amazon S3 存储桶。 AWS Management Console

重要注意事项

  • 请务必将描述符文件上传到您的 Amazon S3 存储桶,与您打算配置规则的 AWS 区域 位置相同。 AWS 账户

  • 请确保您授予FileDescriptorSet从 S3 读取的 AWS IoT Core 权限。如果您的 S3 存储桶已禁用服务器端加密 (SSE),或者 S3 存储桶已使用 Amazon S3 托管密钥 (SSE-S3) 加密,则不需要进行额外的策略配置。这可以通过示例存储桶策略来实现:

    { "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Principal": { "Service": "iot.amazonaws.com" }, "Action": "s3:Get*", "Resource": "arn:aws:s3:::<BUCKET NAME>/<FILENAME>.desc" } ] }
  • 如果您的 S3 存储桶使用 AWS Key Management Service 密钥 (SSE-KMS) 进行加密,请确保授予在访问 S3 存储桶时使用该密钥的 AWS IoT Core 权限。这可以通过将此语句添加到密钥策略中来实现。

    { "Sid": "Statement1", "Effect": "Allow", "Principal": { "Service": "iot.amazonaws.com" }, "Action": [ "kms:Decrypt", "kms:GenerateDataKey*", "kms:DescribeKey" ], "Resource": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab" }

在规则中配置 protobuf 解码

将描述符文件上传到 Amazon S3 桶后,配置一条规则,该规则可以使用 decode(value, decodingScheme) SQL 函数解码您的 protobuf 消息有效负载格式。详细的函数签名和示例可以在《AWS IoT SQL 参考》decode(value, decodingScheme) SQL 函数中找到。

下面是使用 decode(value, decodingScheme) 函数的 SQL 表达式示例:

SELECT VALUE decode(*, 'proto', '<BUCKET NAME>, '<FILENAME>.desc', '<PROTO_FILENAME>', '<PROTO_MESSAGE_TYPE>') FROM '<MY_TOPIC>'

在此示例表达式中:

  • 您可以使用 decode(value, decodingScheme) SQL 函数来解码 * 引用的二进制消息有效负载。这可以是 protobuf 编码的二进制有效负载,也可以是表示 base64 编码的 protobuf 有效负载的 JSON 字符串。

  • 提供的消息有效负载使用中 PROTO_FILENAME.proto 定义的 Person 消息类型进行编码。

  • 名为 BUCKET NAME 的 Amazon S3 桶中包含从 PROTO_FILENAME.proto 生成的 FILENAME.desc

完成配置后,向发布一条 AWS IoT Core 有关订阅该规则的主题的消息。

限制

AWS IoT Core 规则支持 protobuf,但有以下限制:

  • 不支持在替换模板中解码 protobuf 消息有效负载。

  • 解码 protobuf 消息有效负载时,可以在单个 SQL 表达式中使用解码 SQL 函数多达 2 次。

  • 最大入站有效负载大小为 128 KiB(1KiB = 1024 字节),最大出站有效负载大小为 128 KiB,存储在 Amazon S3 存储桶中的 FileDescriptorSet 对象的最大大小为 32 KiB。

  • 不支持使用 SSE-C 加密进行加密的 Amazon S3 存储桶。

最佳实践

以下是一些最佳实践和故障排查提示。

  • 在 Amazon S3 存储桶中备份您的原型文件。

    备份您的原型文件是一种很好的做法,以防出现问题。例如,如果您在运行 protoc 时错误地修改了没有备份的原型文件,这可能会导致您的生产堆栈出现问题。有多种方法可以在 Amazon S3 存储桶中备份您的文件。例如,您可以在 S3 存储桶中使用版本控制。有关如何备份 Amazon S3 存储桶中的文件的更多信息,请参阅 Amazon S3 开发人员指南

  • 配置 AWS IoT 日志以查看日志条目。

    最好配置 AWS IoT 日志记录,这样你就可以在中查看账户的 AWS IoT 日志 CloudWatch。当规则的 SQL 查询调用外部函数时, AWS IoT Core Rules 会生成一个带为eventType的日志条目FunctionExecution,其中包含可帮助您排除故障原因字段。可能的错误包括找不到 Amazon S3 对象,或者 protobuf 文件描述符无效。有关如何配置 AWS IoT 日志记录和查看日志条目的更多信息,请参阅配置 AWS IoT 日志记录规则引擎日志条目

  • 使用新的对象键更新 FileDescriptorSet,并更新规则中的对象键。

    您可以通过将更新后的描述符文件上传到 Amazon S3 桶来更新 FileDescriptorSet。您对 FileDescriptorSet 的更新最多需要 15 分钟能够反映出来。为了避免这一延迟,使用新的对象键上传更新后的 FileDescriptorSet,然后更新规则中的此对象密钥是一种很好的做法。