文章目录

一、物联网和MQTT

随着各家嵌入式产品越来越多,技术也越来越成熟,大家都开始想要随便搭载一个AI算法,然后声称为人工智能产品去售卖,像天猫精灵、小米智能音箱之类。这些产品大多都是嵌入式设备,例如小米出了很多传感器,可以用手机APP控制。这就是万物联结的网络,称为物联网(Internet of Things,IoT)。

一个很重要的功能当然是通信了,以前的想法就是,要么用Wifi连上家里的路由器,然后搭建一台HTTP服务器来提供服务就好;要么直接用蓝牙等近场通信方式,手机直接和设备交换数据。无论哪种,对嵌入式设备的电量消耗都是巨大的,而且操作的体验并不好,就好像你用蓝牙还得凑近它10米以内。于是人们开始寻找更好的替代方式,1999年IBM开发的MQTT协议重新出现在舞台上。

MQTT全称是消息队列遥测传输(Message Queuing Telemetry Transport),是一种专为计算能力低的客户端设计的基于发布/订阅(Publish/Subscribe)模式的“轻量级”通讯协议。先来了解一下MQTT的基本设计思路:

1)发布、订阅模式

这是一个很经典的一对多消息发布模式了,像Redis就具有发布订阅功能。举一个具体的例子,我们有一个漫画家、有很多想看漫画的肥宅,先约定一个共同的主题叫做"连载漫画专栏",肥宅们非常想看下一期漫画,于是“订阅”了这个专栏,并一直"监听"着是否有新漫画到达。每当漫画家“发布”一期新漫画到这个专栏,所有的肥宅都能“消费”相同的下一期“漫画”,漫画家只需要往这个主题“连载漫画专栏”里面发布漫画,无需关心是哪些肥宅在看;肥宅们只需要订阅和监听“连载漫画专栏”,就能够第一时间得到最新漫画内容。

回到物联网,有非常多这种一对多消息发布的需求。例如一台温度传感器上传了温度数据,监控日志面板服务希望得到数据好去绘图、温度异常服务希望感知温度异常好做相应操作、手机推送服务希望能够及时地获取最新温度好呈现给手机端展示,这就是一对多的典型需求。

相比于一个一个地主动投递消息,发布订阅这种被动获取减少了生产者的负担,解除了耦合,提高了消息传输效率。

2)MQTT的工作层

MQTT工作于应用层,是基于TCP/IP之上的可靠连接,当然也有UDP版本叫做“MQTT-SN”,通常使用的都是TCP版。

3)MQTT轻量级的体现

MQTT的报文头部只有2字节,它一开始就假设了客户端是计算能力低需要节省资源的设备,用约定好的二进制位来传递控制消息,省电省流量。

4)MQTT的三种消息发布服务质量

【QoS0】最多一次,不管成功与否

这是最省电但最不可靠的方式,完全依赖底层TCP/IP网络,可能会发生消息丢失和重复。通常应用于物联网设备上报最新数据,例如温度传感器不断地上传最新温度,这次的数据丢了马上又会有下一次,所以丢失无所谓;由于只是修改状态,具有幂等性,无论重复传输多少次,结果都是一样的,所以重复也无所谓。

【QoS1】至少一次,保证消息到达,可能重复

在QoS0之上保证了消息一定会送到,重复无所谓(通常重复的概率很低),但必须要让消费者看见这条消息,这是最常用的服务质量,应用于手机推送消息等各项服务的数据生产消费。假设你的温度传感器监控到温度异常可能着火了,手机APP收到多条着火消息和一条着火消息都收不到,当然是收到多条着火消息更好了。

【QoS2】只有一次,保证消息只到达一次

这种当然是最好的情况,但这也是最费电、流程最复杂的情况,大部分物联网大厂都不支持QoS2,因为根本没有这种需求。通常QoS2用于支付,如果支付的数据丢失、或者多次重复支付,都是很难容忍的。或者用于手机聊天消息,手机APP只能接收到一条聊天消息推送,消息的丢失和重复都是不可以的,这种场景直接用HTTP服务器就好了啊,大家都是强大的手机又不是低功耗嵌入式设备。

5)MQTT的心跳和连接

MQTT维护了双工长连接,通过心跳机制来判断是否掉线。不要担心心跳机制给嵌入式设备带来的负担,通常这个心跳间隔都设置得很长,例如60秒。

6)MQTT的主题

MQTT的主题长这个样子:“/mydevice/abc”、"/mydevice/+/confs"、"mydevice/qwer/#"。

第一个是最普通的精确主题,用斜杠分隔主题层级。

第二个是通配符主题,“+”只能匹配一层的主题,例如“/mydevice/123/confs”是可以匹配的,"/mydevice/123/aaa/confs"是无法匹配的。

第三个是通配符主题,"#"可以匹配多层,但只能在末尾,例如"mydevice/qwer/aaa/123"是可以匹配的。

7)MQTT的保留消息

MQTT设置了一个保留消息(Retain Message),这是基于主题的,每个主题可以有一条保留消息,如果有新的订阅者订阅了该主题,就需要将这条保留消息推送给它,通常用于新订阅主题的设备初始化。

8)MQTT的遗嘱

MQTT设置了一个遗嘱消息(Will Message),这是基于客户端的,每个客户端在连接的时候可以保留一条遗嘱消息,当连接异常断开(例如网络中断、客户端崩溃、心跳信息没有发送)没有发送正常的DISCONNECT报文的时候,会将这条消息分发给订阅了这个遗嘱消息的客户端,其他客户端就知道它发生问题了,从而做相应的处理,通常用于设备的异常通知,例如当设备正常退出,手机APP需要显示设备正常退出,当设备异常退出,手机APP需要报警,那么手机APP只需要订阅设备的遗嘱消息,就能够知道它断开时是正常的还是异常的了。

9)MQTT的常用版本

最常用的是三个版本,MQTT3.1、MQTT3.1.1、MQTT5.0。

MQTT3.1.1是最常见的,是MQTT服务器至少应该支持的版本。MQTT3.1是早期版本,为了兼容性可以去支持。MQTT5.0是最新版本(3.1.1的下一版本是直接跳到5.0的),性能会有提升,如果设备也能采用MQTT5.0,那么服务器支持MQTT5.0是很好的决定,对于普通开发者,只需要支持MQTT3.1.1即可。

10)相比于HTTP,MQTT有哪些优势?

MQTT更加适合嵌入式设备:

对比项 MQTTHTTP 
报文长度 小,省电省流量,头部二进制大,头部是明文
订阅发布(多播)支持不支持
QoS等级支持不支持
双向通信支持用Websocket才行 
保留消息、遗嘱消息支持不支持

二、MQTT Broker 消息代理

刚接触物联网的同学应该经常看到这个名词,中文翻译得最准确的就是亚马逊AWS IoT的中文文档——“消息代理”。通常代理都是Proxy,这里换了一个词叫Broker(中间人、代理人),Kafka的订阅发布代理也叫做Broker。为什么要叫消息代理呢,因为所有的MQTT的转发都是由它在中间来代为协调的。

Broker所做的事情就是,替客户端维护所有MQTT订阅信息,提供发布订阅的QoS保证。客户端毕竟是嵌入式设备,没有那么强大的能力,那就让服务器来替代它完成消息的推送任务。设计Broker有很多困难的地方,目前开源的Java编写的MQTT Broker没一个能满足所有需求的,很气……


转载请注明出处http://www.bewindoweb.com/242.html | 三颗豆子
分享许可方式知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议
重大发现:转载注明原文网址的同学刚买了彩票就中奖,刚写完代码就跑通,刚转身就遇到了真爱。
你可能还会喜欢
具体问题具体杠