为啥IoT(物联网)选择了MQTT协议?

物联网设备要实现互相通信,须一套标准通信协议,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图:

@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

<img src="https://p.ipic.vip/wl5sdu.png" style="zoom: 33%;" />

Proxy收发消息的时序图:

<img src="https://p.ipic.vip/5cqqhw.png" style="zoom:33%;" />

Proxy生产消息流程的时序图:

<img src="https://p.ipic.vip/swzi3k.png" style="zoom:33%;" />

Proxy消费消息流程的时序图:

<img src="https://p.ipic.vip/kr60pu.png" alt="image-20231208134111361" style="zoom:33%;" />

6 总结

MQTT是专门为物联网设备设计的一套标准的通信协议。这套协议在消息模型和功能上与普通的消息队列协议是差不多的,最大的区别在于应用场景不同。在物联网应用场景中,IoT设备性能差,网络连接不稳定。服务端面临的挑战主要是,需要支撑海量的客户端和主题。

已有的开源的MQTT产品,对于协议的支持都不错,在客户端数量小于十万级别的情况下,可以选择。对于海量客户端的场景,服务端必须使用集群来支撑,可以选择收费的云服务和企业版产品。也可以选择自行来构建MQTT集群。

自行构建集群,最关键技术点,就是通过前置Proxy集群解决海量连接、会话管理和海量主题:

  • 前置Proxy负责在Broker和客户端之间转发消息,通过这种方式,将海量客户端连接收敛为少量的Proxy与Broker之间的连接,解决了海量客户端连接数的问题
  • 维护会话的实现原理,和Tomcat维护HTTP会话一样
  • 海量主题,可在后端部署多组Broker小集群,每个小集群分担一部分主题这样的方式来解决

参考:

本文由博客一文多发平台 OpenWrite 发布!

博通宣布终止现有 VMware 合作伙伴计划 B站崩了两次、腾讯“3.29”一级事故……盘点 2023 十大宕机事故“冥场面” Vue 3.4 “灌篮高手”发布 养乐多公司确认 95 G 数据被泄露 MySQL 5.7、魔趣、李跳跳……盘点 2023“停更”的(开源)项目和网站 《2023 中国开源开发者报告》正式发布 回顾 30 年前的 IDE:只有 TUI、背景颜色亮瞎眼…… Julia 1.10 正式发布 Rust 1.75.0 发布 英伟达推出特供中国销售的 GeForce RTX 4090 D
{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/3494859/blog/10320373