mqtt协议基础概要
目录
mqtt拓扑图
[图片来源网络]
mqtt优缺点
MQTT的优点是:协议简洁轻巧,数据冗余量低。并且支持的设备从智能硬件到智能手机无所不包。
MQTT的缺点是:服务器端实现难度大,虽然已经有了C++版本的服务端组件,但是并不开源。而且在推送数量较大时如何处理并发是很考验技术。
MQTT客户端和代理通过session机制保证消息的传输可靠性。MQTT客户端和broker端底层通过session来保障不同的qos等级。
可以通过MQTT over websocket来穿越防火墙,不需要开1883、8883端口。
使用场景
在基于位置服务的移动应用领域(最典型的是打车应用),移动设备端和服务端之间总是存在大量的交互(用户可实时获取自已附近网约车的实时位置信息)。设备向服务端发送它的位置信息和其它设备信息,服务端接收这些数据,对它们进行处理,并返回给设备端一些命令。设备端根据这些命令执行一些操作,比如GPS数据的收集和发送频率等。
基于以上业务场景,如此频繁的数据交互,要达到数据的实时推送级别。
如果设备不用在意功耗问题,直接 socket 就好,将socket服务剥离,设备和 web 服务都作为 client 端连接到 socket server。方便以后拓展 socket server,例如更换实现,集群,HA 能特性,而不用更改已有的 web 服务。
如果设备在意功耗,可以尝试使用MQTT,和socket server的方式类似。设备和 web 都作为 mqtt client,由mqtt broker作为消息代理
使用方式
物联网硬件用原生 MQTT 连接服务器 MQTT Broker,Web/App应用通过 MQTT 连接 Broker
Websocket/TCP MQTT Client <----> MQTT Broker <----> Websocket/TCP MQTT Client
物联网设备与 Web 应用服务器通信,用什么通信协议比较合适?
mqtt版本
使用MQTT协议一般有几个目的:
- 更省电,报文更小
- 更丰富,扩充内容
- 性能更好
- 专门针对某类IoT设备进行优化
先看看最新的MQTT5.0的协议,有些优化目的可能已经在5.0中实现,比如共享订阅在MQTT5.0已经成为标准。
v3.1.1和v5.0之间的差异 · Youjingyu/mqtt.github.io Wiki
需要mqtt做什么
做什么
- 支持远端设备长连接(对网络条件要求苛刻),实现在线与离线状态
- 支持发布与订阅消息,实现phone端与web端的简单消息与指令通信
- 支持自定义鉴权,实现Token验证
- 支持broker与业务服务器交互,实现比如在线/离线推送、连接数相关统计、业务数据存储等
- 支持prometheus监控
我们更多的用于设备连接与消息路由,对于数据的处理与持久化不在考虑范围之内。
为什么
- 更轻量、报文更小、资源消耗更少、客户端更省电
- 专门为物理网设备设计,对某些IoT设备进行优化
- 支持三个等级的QoS
- 支持多对多
mqtt broker
对broker的要求
- 支持mqtt5.0
- 支持三个级别的QoS()
- 支持遗愿消息(非IM类,对遗愿消息的支持期待不高)
- 支持持久化
- 支持4种连接,tcp(ssl)、websocket(ssl)
- 支持集群
- 支持自定义验证方式
- 支持共享订阅
- 支持自定义插件
MQTT Broker的需求和各大Broker对比 | 文章 | BEWINDOWEB
server support · mqtt/mqtt.org Wiki
主流比对
Server | Language | 开源 | QoS 0 | QoS 1 | QoS 2 | Auth | Bridge | $ | SSL | 动态topics | cluster | websockets | plugin | Mqtt5 | 活跃 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
HiveMQ | Java | ✔ | ✔ | ✔ | ✔ | Username/Password | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
VerneMQ | Erlang | ✔ | ✔ | ✔ | ✔ | Username/Password | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔(beta) | ✔ |
EMQX | Erlang | ✔ | ✔ | ✔ | ✔ | Username/Password, JWT, LDAP, ClientID, … | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
mosquitto | C++ | ✔ | ✔ | ✔ | ✔ | Username/Password | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
emitter | Go | ✔ | ✔ | ✘ | ✘ | Per-channel authorization | ✘ | ✘ | ✔ | ✔ | ✔ | ✔ | ✘ | ✘ | ✔ |
Gmqtt | Go | ✔ | ✔ | ✔ | ✔ | 可自定义验证 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
主流MQTT Broker:
HiveMQ - Enterprise ready MQTT to move your IoT data
Mosquitto-官网 \ Eclipse Mosquitto - github
mqtt client
client
mqtt package - github.com/eclipse/paho.mqtt.golang - pkg.go.dev
mqtt demo
How to use MQTT in Golang | EMQ
主题约定
-
如何约定主题,减少主题订阅数
From client to server you may pack client-id into payload, e.g. if it is JSON, one of the keys can have client-id value.
Response from server to client should contain client-id in order to broker to not to broadcast message, but to send it directly to one connected client.
At the same time you may subscribe your server to something like: “requests/+” and each client will publish to “request/{client-id-1}", “request/{client-id-2}", and server will receive both with just one subscription.
-
主题定义规则
MQTT Topics & Best Practices - MQTT Essentials: Part 5
初步根据phone、web的功能,假设定义主题:
web端subscribe主题phone/phone_device_id,publish到主题phone_device_id/web/web_device_id
phone端subscribe主题phone_device_id/web/+,publish到主题phone/phone_device_id
考虑web订阅消息还可以共享订阅,支持消息负载均衡。
-
系统主题定义
-
前缀:
$SYS/brokers/
-
broker状态信息:
$SYS/brokers/version、$SYS/brokers/uptime….
-
客户端上下线时间:
${client}/connected,${client}/disconected
-
客户端统计:
connections/count,connections/max(历史最大值)
-
订阅统计:
subscribers/count:当前订阅者数量
subscribeoptions/count:当前订阅总数
subscribeoptions/shared/count:当前共享订阅个数
另外可以补充各自历史最大值
-
主题统计:
topics/count:主题总数
-
收发流量统计
bytes/received:累计接收流量
bytes/sent:累计发送流量
-
报文统计
packets/received 累计接收 MQTT 报文 packets/sent 累计发送 MQTT 报文 packets/connect 累计接收 MQTT CONNECT 报文 packets/connack 累计发送 MQTT CONNACK 报文 packets/publish/received 累计接收 MQTT PUBLISH 报文 packets/publish/sent 累计发送 MQTT PUBLISH 报文 packets/puback/received 累计接收 MQTT PUBACK 报文 packets/puback/sent 累计发送 MQTT PUBACK 报文 packets/puback/missed 累计丢失 MQTT PUBACK 报文 packets/pubrec/received 累计接收 MQTT PUBREC 报文 packets/pubrec/sent 累计发送 MQTT PUBREC 报文 packets/pubrec/missed 累计丢失 MQTT PUBREC 报文 packets/pubrel/received 累计接收 MQTT PUBREL 报文 packets/pubrel/sent 累计发送 MQTT PUBREL 报文 packets/pubrel/missed 累计丢失 MQTT PUBREL 报文 packets/pubcomp/received 累计接收 MQTT PUBCOMP 报文 packets/pubcomp/sent 累计发送 MQTT PUBCOMP 报文 packets/pubcomp/missed 累计丢失 MQTT PUBCOMP 报文 packets/subscribe 累计接收 MQTT SUBSCRIBE 报文 packets/suback 累计发送 MQTT SUBACK 报文 packets/unsubscribe 累计接收 MQTT UNSUBSCRIBE 报文 packets/unsuback 累计发送 MQTT UNSUBACK 报文 packets/pingreq 累计接收 MQTT PINGREQ 报文 packets/pingresp 累计发送 MQTT PINGRESP 报文 packets/disconnect/received 累计接收 MQTT DISCONNECT 报文 packets/disconnect/sent 累计接收 MQTT DISCONNECT 报文 packets/auth 累计接收 MQTT AUTH 报文
-
其他
Language Guide | Protocol Buffers | Google Developers
疑问
-
为什么用mqtt代替websocket?
-
mqtt如何保持连接,也就是心跳机制如何?
mqtt约定了pingreq与pingresp心跳机制
-
如何设置保活时长?
在客户端连接时设置,broker在1.5倍保活时长内没有收到任何报文将主动disconnect连接。由于mqtt轻量报文小资源消耗少,所以这个保活机制可以由mqtt broker来维持,不需要再自定义保活机制
-
如何选择QoS?
内网或客户端与服务端的网络连接很稳定可以考虑0(可接受消息偶尔丢失);关注性能优化、资源消耗,可以考虑1(消息不丢失、但能接受并处理重复消息);对数据完整性与及时性要求比较高,可以考虑2(消息丢失会造成较大损失)
小数据服务,常用操作是心跳、web通知phone的一些控制指令,可以考虑1。
-
broker可以支持多少主题
这取决于client数量、每个主题的消息数、订阅每个主题的客户端数、broker机器参数,需要进一步的测试找出
Eclipse Community Forums: Paho » MqttClient Topic Subscription
-
可能会用到5.0的功能
session过期:
消息过期:支持设置消息到期时间间隔
所有ACK原因码:支持原因码和原因描述
服务器断开:允许服务器发送disconnect以指示连接关闭的原因
共享订阅:允许负载均衡订阅的消费者
主题别名:将主题名缩写成一个小整数,较少mqtt数据包大小
用户属性:大多数数据包支持用户属性,不同控制报文的用户属性由不同主体定义,比如publisher、broker;用户属性不由mqtt协议定义,可以自定义。
最大包体积:客户端和服务端可以约定支持的最大数据包体积。
服务器保活:允许服务器指定它希望客户端用作保活时间值。
-
黑名单支持
自动封禁那些被检测到短时间内频繁登录的客户端,并且在一段时间内拒绝这些客户端的登录,以避免此类客户端过多占用服务器资源而影响其他客户端的正常使用。
比如:如果客户端在 1 分钟内离线次数达到 30 次,那么该客户端使用的客户端标识符将被封禁 5 分钟
支持限制某个客户端标识或ip或
-
broker插件支持
参考
Websocket vs. MQTT vs. CoAP: Which is the Best Protocol?
MQTT Broker的需求和各大Broker对比 | 文章 | BEWINDOWEB
MQTT Topics, Wildcards, & Best Practices - MQTT Essentials: Part 5