为啥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图:

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小集群,每个小集群分担一部分主题这样的方式来解决

参考:

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

相关推荐
luckywuxn4 分钟前
EurekaServer 工作原理
java·eureka
壹米饭7 分钟前
Java程序员学Python学习笔记一:学习python的动机与思考
java·后端·python
java金融9 分钟前
Java 锁升级机制详解
java
Young556613 分钟前
还不了解工作流吗(基础篇)?
java·workflow·工作流引擎
让我上个超影吧14 分钟前
黑马点评【缓存】
java·redis·缓存
ajassi200023 分钟前
开源 java android app 开发(十一)调试、发布
android·java·linux·开源
YuTaoShao36 分钟前
Java八股文——MySQL「存储引擎篇」
java·开发语言·mysql
crud42 分钟前
Java 中的 synchronized 与 Lock:深度对比、使用场景及高级用法
java
王德博客1 小时前
【Java课堂笔记】Java 入门基础语法与面向对象三大特性详解
java·开发语言
seventeennnnn1 小时前
Java大厂面试真题:谢飞机的技术挑战
java·spring boot·面试·aigc·技术挑战·电商场景·内容社区