物联网设备要实现互相通信,须一套标准通信协议,MQTT(Message Queuing Telemetry Transport)专为物联网设备设计的一套标准消息队列通信协议。使用MQTT协议的IoT设备,可以连接到任何支持MQTT协议的消息队列上,进行通信。
- 宏观,MQTT和其他MQ传输协议差不多。也是"发布-订阅"消息模型
- 网络结构,也是C/S架构,IoT设备是客户端,Broker是服务端,客户端与Broker通信进行收发消息
但毕竟使用场景不同,所以,MQTT和普通MQ比,还有很多区别。
1 客户端都运行在IoT设备
1.1 IoT设备特点
① 便宜
最大特点,一个水杯才几十块钱,它上面智能模块成本十块钱最多,再贵就卖不出去。十块钱的智能设备内存都是按KB计算,可能都没有CPU,也不一定有os,整个设备就一个SoC(System on a Chip)。这样的设备就需要通信协议不能复杂,功能不能太多。
② 无线连接
IoT设备一般采用无线连接,很多设备经常移动,导致IoT设备网络连接不稳定,且是常态。
MQTT协议设计上充分考虑这些特点。协议的报文设计极简,惜字如金。协议功能也非常简单,基本就只有:
- 发布订阅主题
- 收发消息
这两个最核心功能。为应对网络连接不稳定问题,MQTT增加机制:
- 心跳机制,可让客户端和服务端双方都能随时掌握当前连接状态,一旦发现连接中断,可尽快重连
- 会话机制,在服务端来保存会话状态,客户端重连后就可恢复之前会话,继续收发消息。这样,把复杂度转移到服务端,客户端实现更简单
2 服务端高要求
MQTT面临的使用场景中,服务端需支撑海量IoT设备同时在线。
普通的消息队列集群,服务的客户端都运行在性能强大的服务器,所以客户端数量不会特别多。如京东的JMQ集群,日常在线客户端数量大概十万左右,就足够支撑全国人民在京东买买买。
而MQTT使用场景中,需支撑的客户端数量,远不止几万几十万。如北京交通委若要把全市车辆都接入进来,就是个几百万客户端的规模。路侧的摄像头,每家每户的电视、冰箱,每个人随身携带的各种穿戴设备,这些设备规模都是百万、千万级甚至上亿级。
3 不支持点对点通信
MQTT协议的设计目标是支持发布-订阅(Publish-Subscribe)模型,而不是点对点通信。
MQTT的主要特点之一是支持发布者(Publisher)将消息发布到一个主题(Topic),而订阅者(Subscriber)则可以通过订阅相关主题来接收这些消息。这种模型在大规模的分布式系统中具有很好的可扩展性和灵活性。因此,MQTT更适合用于多对多、多对一的通信场景,例如物联网(IoT)应用、消息中间件等。
虽然MQTT的设计目标不是点对点通信,但在实际使用中,你仍然可以通过一些设计来模拟点对点通信。例如,使用不同的主题来模拟点对点通信,或者在应用层进行一些额外的协议和逻辑以实现点对点通信的效果。
一般做法都是,每个客户端都创建一个以自己ID为名字的主题,然后客户端来订阅自己的专属主题,用于接收专门发给这个客户端的消息。即MQTT集群中,主题数量和客户端数量基本是同一量级。
4 MQTT产品选型
如何支持海量在线IoT设备和海量主题,是每个支持MQTT协议的MQ面临最大挑战。也是做MQTT服务端技术选型时,需重点考察技术点。
开源MQTT产品
有些是传统MQ,通过官方或非官方扩展,实现MQTT协议支持。也有一些专门的MQTT Server产品,这些MQTT Server在协议支持层面,大多没问题,性能和稳定性方面也都满足要求。但还没发现能很好支撑海量客户端和主题的开源产品。why?
传统MQ
虽可通过扩展来支持MQTT协议,但整体架构设计之初,并未考虑支撑海量客户端和主题。如RocketMQ元数据保存在NameServer的内存,Kafka是保存在zk,这些存储都不擅长保存大量数据,所以也支撑不了过多客户端和主题。
另外一些开源MQTT Server
很多就没集群功能或集群功能不完善。集群功能做的好的产品,大多都把集群功能放到企业版卖。
所以做MQTT Server技术选型,若你接入IoT设备数量在10w内,可选择开源产品,选型原则和选择普通消息队列一样,优先选择一个流行、熟悉的开源产品即可。
若客户端规模超过10w量级,需支撑这么大规模客户端数量,服务端只有单节点肯定不够,须用集群,并且这集群要支持水平扩容。这时就几乎没开源产品了,此时只能建议选择一些云平台厂商提供的MQTT云服务,价格相对较低,也可选择价格更高商业版MQTT Server。
另外一个选择就是,基于已有开源MQTT Server,通过一些集成和开发,自行构建MQTT集群。
5 构建一个支持海量客户端的MQTT集群
MQTT集群如何支持海量在线的IoT设备? 一般来说,一个MQTT集群它的架构应该是这样的:
从左向右看,首先接入的地址最好是一个域名,这样域名后面可配置多个IP地址做负载均衡,当然这域名不是必需。也可直接连负载均衡器。负载均衡可选F5这种专用的负载均衡硬件,也可Nginx这样软件,只要是四层或支持MQTT协议的七层负载均衡设备,都可。
负载均衡器后面要部署一个Proxy集群
Proxy集群作用
- 承接海量IoT设备连接
- 维护与客户端的会话
- 作为代理,在客户端和Broker之间进行消息转发
在Proxy集群后是Broker集群,负责保存和收发消息。
有的MQTT Server集群架构:
架构中没Proxy。实际上,只是把Proxy和Broker功能集成到一个进程,这两种架构本质没有太大区别。可认为就是同一种架构来分析。
前置Proxy,易解决海量连接问题,由于Proxy可水平扩展,只要用足够多的Proxy节点,就可抗海量客户端同时连接。每个Proxy和每个Broker只用一个连接通信即可,这对每个Broker来说,其连接数量最多不会超过Proxy节点的数量。
Proxy对于会话的处理,可借鉴Tomcat处理会话的两种方式:
- 将会话保存在Proxy本地,每个Proxy节点都只维护连接到自己的这些客户端的会话。但这要配合负载均衡来使用,负载均衡设备需支持sticky session,保证将相同会话的连接总是转发到同一Proxy节点
- 将会话保存在一个外置存储集群,如Redis集群或MySQL集群。这样Proxy就可设计成完全无状态,对负载均衡设备也没特殊要求。但这要求外置存储集群具备存储千万级数据能力,同时具有很好性能
如何支持海量主题?
较可行的解决方案,在Proxy集群的后端,部署多组Broker小集群,如可以是多组Kafka小集群,每个小集群只负责存储一部分主题。这样对每个Broker小集群,主题数量就可控制在可接受范围内。由于消息是通过Proxy进行转发,可在Proxy中采用一些像一致性哈希等分片算法,根据主题名称找到对应Broker小集群。这就解决支持海量主题的问题。
UML
Proxy的UML图:
json
@startuml
package "MQTT Proxy Cluster" {
class MQTTProxy {
+handleIncomingMessage()
+handleOutgoingMessage()
+produceMessage()
+consumeMessage()
}
class Client {
+sendMessage()
+receiveMessage()
}
class Broker {
+publish()
+subscribe()
}
Client --> MQTTProxy
MQTTProxy --> Broker
}
@enduml
@startuml
actor Client
entity MQTTProxy
entity Broker
Client -> MQTTProxy : sendMessage()
activate MQTTProxy
MQTTProxy -> Broker : produceMessage()
deactivate MQTTProxy
@enduml
@startuml
entity MQTTProxy
entity Broker
actor Client
Broker -> MQTTProxy : publishMessage()
activate MQTTProxy
MQTTProxy -> Client : consumeMessage()
deactivate MQTTProxy
@enduml
Proxy收发消息的时序图:
Proxy生产消息流程的时序图:
Proxy消费消息流程的时序图:
6 总结
MQTT是专门为物联网设备设计的一套标准的通信协议。这套协议在消息模型和功能上与普通的消息队列协议是差不多的,最大的区别在于应用场景不同。在物联网应用场景中,IoT设备性能差,网络连接不稳定。服务端面临的挑战主要是,需要支撑海量的客户端和主题。
已有的开源的MQTT产品,对于协议的支持都不错,在客户端数量小于十万级别的情况下,可以选择。对于海量客户端的场景,服务端必须使用集群来支撑,可以选择收费的云服务和企业版产品。也可以选择自行来构建MQTT集群。
自行构建集群,最关键技术点,就是通过前置Proxy集群解决海量连接、会话管理和海量主题:
- 前置Proxy负责在Broker和客户端之间转发消息,通过这种方式,将海量客户端连接收敛为少量的Proxy与Broker之间的连接,解决了海量客户端连接数的问题
- 维护会话的实现原理,和Tomcat维护HTTP会话一样
- 海量主题,可在后端部署多组Broker小集群,每个小集群分担一部分主题这样的方式来解决
参考:
- ChatGPT
- MQTT协议:如何支持海量的在线IoT设备?
- EMQX MQTT 教程
- 百度开源 MQTT 服务端(支持集群)bifromq.io/zh-Hans/
本文由博客一文多发平台 OpenWrite 发布!