【问题标题】:Good way to design mqtt topic?设计mqtt主题的好方法?
【发布时间】:2018-06-22 15:07:49
【问题描述】:

我是 mqtt 设计的新手。

我从网上的一些教程中看到,常见的 mqtt 主题格式如下:/home/room/device_type/device_id

我看不出这样做有什么好处。并且不知道如何使用这种设计。

在我看来,设备 (dev) 可能订阅 (sub) 控制主题并发布 (pub) 到状态主题。像这样:

  • 发布:clients/dev/devid/stat
  • 子:clients/dev/devid/ctrl

这样看来sub,pub逻辑对于客户端和设备来说都非常简单

有人可以告诉我一些设计mqtt主题的好方法吗?

(!) 请不要以 '/' 开头的话题(这个是 HiveMQ 团队推荐的)

编辑:

我刚刚发现对于任何类型的设计,模型至少必须是可服务的:

  1. 单独控制:向特定设备发送控制命令。
  2. 组控制:向一组设备发送控制命令:类型,定义组
  3. 能够接收设备状态。

非常感谢

【问题讨论】:

  • 首先,主题不应以/开头
  • 发件人:hivemq.com/blog/…。他们说:“应该避免这种情况,因为它没有任何好处,而且经常导致混乱。”我很抱歉,但我认为没有理由避免这种情况。 '/'代表顶层,比任何词都简单:top、boss、father等
  • 是的,我同意
  • 它在主题树的开头添加了一个空值,这使得正确使用通配符变得更加困难。
  • 这是一个额外的搜索树级别,对于+ 通配符匹配更是一个问题。此外,由于记录了不良做法,它使互操作性变得更加困难,所以不要这样做

标签: mqtt


【解决方案1】:

我发现以下主题拆分方案在多个应用程序中效果很好

protocol_prefix / src_id / dest_id / message_id / extra_properties
  • protocol_prefix 用于区分可以同时使用的不同协议/应用程序
  • src_id是发布消息的mqtt客户端的ID。预计与用于连接 MQTT 代理的“客户端 ID”相同。它允许快速 ACL 控制来检查客户端是否被允许发布特定主题。
  • dest_id 是“目标”单元的客户端 ID,即消息的目标用户。还允许快速 ACL 控制代理是否允许客户端订阅特定主题。可以保留“目标”字符串来指定将消息广播给任何感兴趣的人。例如全部
  • message_id 是所用协议中消息的实际 ID。我通常使用数值(当然是字符串),因为连接到 MQTT 代理的 IOT 或其他嵌入式系统可以有其他 I/O 链接,我想使用相同的协议(但使用不同的传输帧)来控制使用这些其他 I/O 链接的设备。我通常在此类通信链接中使用数字消息 ID。
  • extra_properties 是一个可选的子主题,可用于传达其他 MQTT 特定的额外信息(例如,逗号分隔的 key=value 对)。一个很好的例子是在客户端实际发送消息时报告消息的时间戳。在“保留”消息的情况下,它可以帮助识别接收到的消息的相关性。随着 MQTTv5 协议预计很快到来,对这个子主题的需求可能会消失,因为会有其他方式来传达额外的属性。

希望对你有帮助。

【讨论】:

  • 我喜欢在主题中集成 src 和 dst 的想法。订阅者可以使用通配符从“所有发件人”或“所有目的地”获取主题。似乎是一种相当灵活的方法。
【解决方案2】:

我认为,如果主题要反映物理世界,我们应该看看 Signal K 之类的东西。

编辑: 该规范还在成熟中,但它包含了诸如服务器/代理的“自我”之类的概念,以及可以从当前船只/家开始,但很容易向上延伸到其他船只/飞机/事物的树。

我的两分钱:

  1. 所有主题都是只读的,除非它们以“/set”结尾
  2. 理想情况下,主题是合理规范化和细化的。我可以理解将值分组到一个组主题中。恕我直言,这种决定应该是特定于应用程序的。
  3. 有效负载应该是字符串,以避免字节序问题

这是推荐的一棵树:

  • broker = 此特定代理的信息
    • 经纪人/客户
    • 经纪人/客户/计数
    • broker/clients/0/name 或 broker/clients[0]/name
    • 经纪人/主题
  • home = 当前位置(也可以是“这里”或其他)
    • 家/厨房/温度“19C”
    • 家庭/厨房/温度/硬件/类型“ESP8266”
    • 家/车库/大门/设置“关闭”
  • locations = 所有已知位置的列表
    • locations/0/uuid
    • locations/0/name
    • locations/0/address

【讨论】:

  • 我刚刚为经纪人的想法添加了 1 个赞。但我也发现为什么我们需要这样做?因为每个代理都包含其特定的 IP/端口。我们应该减少这个以降低主题的复杂性吗?
  • 如果我正确理解了您的问题,我认为代理主题实际上更像是一个命名空间。您可能需要大量关于代理本身的信息,并且该主题将这些子主题与其他更“特定于任务”的子主题(厨房灯、门廊温度等)区分开来
  • 在玩了一些话题之后,我想修改我的列表。我认为应该有一个“设备”主题,并且每个设备都应该在该列表上有一个唯一的 id。这将是新设备连接到代理的方式。从那里,用户可以通过代理为客户端提供一个逻辑名称/位置作为发布的“标题”。例如: * "devices" - 返回连接到代理的所有设备的列表 * "devices/ESP1337/location/set" = "home/garage" - 告诉设备 ESP1337 在该主题下发布其传感器数据,例如“home/车库/温度”
【解决方案3】:

我们已经为制造领域(工业物联网,而不是物联网!)做了一些工作。

在我们的场景中,有很多不同公司的服务器端应用程序通过 MQTT 进行通信。因此,我们需要一些整体结构。我们称之为“制造消息堆栈”。

最底层是MQTT,然后是“消息层”。它主要由

  • 基本主题规范
  • 基本负载规范

在消息层之上有域消息层,涵盖各种特定领域的主题,如系统消息、警报、物理设备/数字孪生消息或其他制造相关消息。

主题

主题大致定义为<senderapp>/<app-id>/<message-name>/<args>,例如pacman/pacman-1/gameover(这只是一个示例!)

发布 MQTT 消息的应用程序的开发人员根据负载的语义定义 <message-name><args>

<senderapp><app-id> 指的是发送应用程序,并允许从定义的来源(发布者)快速选择消息。我们在使用 Docker、Rancher 以及即将推出的 Kubernetes 构建的微服务环境中部署应用程序。

有效载荷

负载以 JSON 格式指定。每个都有一个 JSON 模式参考 URL 构建一个指向发布应用程序 API 的 URL,该 API 包含所发送消息的更多信息(例如 JSON 模式)。因此,订阅者可以按需获取 MQTT 消息的元数据。静态元数据不随消息一起发送以减少有效负载大小。

有效负载示例:

{
    "$schema": "http://app/api/messages/message1.json",
    "score": 1234,
    "highscore": false
}

发布者的消息元数据

发布应用保存所有可以在 API 中发送的消息的索引 http://<app>/api/messages/index.json:

{
    "message1": "message1.json",
    ...
}

每条消息都由其 JSON 架构 message1.json 描述:

{
    "$schema": "http://json-schema.org/draft-06/schema#",
    "title": "Pacman end of game",
    "properties": {
        "score": {
            "description": "Players score at the end of game",
            "type": "integer"
        },
        ...
    }
}

很遗憾,我们尚未发布制造消息堆栈。计划在未来几个月内出版。欢迎反馈。

【讨论】:

    猜你喜欢
    • 2020-09-28
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 2018-12-22
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    相关资源
    最近更新 更多