随着智能化浪潮席卷全球,如今的车辆早已不再是单纯的交通工具,而是一个具备自主推理能力、能和云端交互进行车路协同的移动智能节点。
很多的新型应用场景不但计算量巨大,而且对通信链路有非常强的低时延、低能耗和高可靠要求。传统的通信协议如HTTP等并不能同时满足以上要求。而作为目前物联网领域事实上的标准协议,MQTT提供了Pub/Sub的消息模式,具备精简优良的协议设计,可以满足低延时和低功耗的需求,适用于资源有限的车机系统。但不同于智能家居、机器人这类设备固定且网络环境稳定的场景,车联网中快速移动、场景切换快、网络情况复杂多变等特性,对MQTT协议在车端和服务端的应用提出了更高的要求。
本文将深入分析车联网移动场景下MQTT消息传输面临的问题及产生原因,并利用MQTT协议特性对其加以解决和优化,帮助用户构建更稳定的车联网通信架构。
相信大家使用4G手机时都有过类似体验:进入地下室时信号强度突然变弱,虽然网络没有显示中断,但是实际使用体验就和断网一样;亦或是在一个很大区域的WiFi网络范围内移动,在不同的AP(无线接入点)覆盖范围之间切换时也会有类似情况。这就是一个典型的移动设备导致的网络迁移问题。而在车联网中,由于车辆是高速移动,特别是在高速公路基站覆盖稀疏或穿过隧道的情况,都会导致这种问题更加频繁地出现,从而引起车机端MQTT连接中断重连。
首先我们来看看车联网场景面对的网络现状:根据2020年底的数据,我国基站总数为931万个,其中3G/4G基站总数为575万个。但这些基站大多集中在城市区域,而在乡村,高速公路甚至是隧道内的信号覆盖就远没有城市那么全面。目前,针对高速公路和国道省道等区域的网络覆盖方案基本分为公网延伸覆盖和专网覆盖方案。
可以发现,我们使用的网络是依靠通信从业者建设的一个个蜂窝基站提供的。而车辆在快速移动的过程中,位置更新频繁,经常会在多个基站覆盖范围之间切换。这导致其网络信令负荷大,基站切换频繁,最终将导致车载4G模块的网络链路中断。虽然专网覆盖可以通过采用BBU+RRU小区合并的技术来减少网际切换和同频干扰,进而解决这一问题,但由于专网方案建设成本高昂,所以实际场景里,车联网更多面对的还是第一种公网覆盖方案。
于是,我们就会发现车机端的4G连接出现如上图所示的不断上下线的情况。
多普勒效应和隧道覆盖
除了基站覆盖带来的网络问题外,当车辆行驶速度很快的时候,也会由于多普勒效应造成延迟增加和丢包。车速越大,频偏越大,延迟越大,丢包的概率也越大。
我们知道了车辆的网络情况,那么这些因素是如何影响车机端MQTT连接的呢?
众所周知,MQTT连接也是基于TCP/IP协议栈。看到这里大家可能会有疑问:TCP/IP协议栈里有连接保活机制,MQTT协议里也有KeepAlive参数供连接重建恢复,哪怕基站切换导致了短暂的通信中断,但是等到进入下一个基站的范围,通信链路也很快就恢复了,那么为什么还会导致车辆设备MQTT连接的频繁离线呢?要回答这个疑问,我们需要结合TCP/IP和移动网络入网过程一起来分析。
TCP/IP协议诞生之初,主要针对的是稳定的有线网络,作为一个可靠传输协议,其内部有数据ACK,能够进行数据重传和连接复用。但是,这一切都是基于IP地址不变的前提下,而在车联网场景里,基站切换是会导致车机端的IP地址变更的。每次车机4G模块进入新的基站覆盖范围时都会重新发起一次入网附着请求。
其中的协议细节这里不进行详细解释。由于目前我们仍然在使用IPV4标准,所以车机4G模块在重新入网过程中会向新搜寻到的eNB基站发送一个关键的信令PDN(PacketDomainNetwork)来请求为自己分配一个新的IP地址,而这个地址往往都是NAT地址,这也是4G终端开机即在线的技术的一环。此时还伴随着网络质量检测、APN匹配等流程来判断终端使用的网络类型和推送网络路由以保证连通性。如果此时的边缘eNB基站没有针对车机端的4G卡和PDN信令进行对应优化,是无法获知其原先使用的IP地址的,那么这时候IP地址就发生了改变,需要进行NAT地址重绑定。而对于MQTT和TCP/IP这一类长链接协议来说,IP地址变化后,TCP服务端无法识别出现在的客户端是否还是原先的客户端,所以TCP连接是必须要重新建立的,从而导致MQTT连接也必须重建。
以上是一个正常的快速移动的车辆在蜂窝基站间正常切换会发生的过程。而实际情况中网络更加复杂,公网覆盖方案由于共享基站和接入网资源,若边缘基站负载过高还会发生eNB基站对PDN请求不响应等情况。网络侧对承载请求不响应,更不用说伪基站。此外地理环境和多普勒效应引起的多径效应和信号衰减都会导致延时增加和连接中断。
清楚了问题的根源,接下来我们将借助MQTT协议的特性来解决上述问题,构建更稳定的车联网通信架构,避免因为连接重连和中断造成的数据丢失。
虽然TCP/IP部分无法改变,但MQTT协议提供了许多供配置的参数和消息QoS等级供我们配置。针对一些关键数据,比如车机端重要的状态变化和用户发出的请求,我们需要保证消息到达,这就需要我们使用QoS1/2。
首先,我们要解决IP更新导致TCP重连后客户端无法识别的问题。我们可以通过MQTT会话保持特性来解决。
客户端使用会话保持的方式以Java为例:
publicMQTTPublisher(Stringaddress,StringclientId,booleancleanSession,intqos)throwsMqttException{this.clientId=clientId;this.qos=qos;this.client=newMqttClient(address,clientId,persistence);MqttConnectOptionsconnOpts=newMqttConnectOptions();connOpts.setCleanSession(cleanSession);//置为fasle即为保留会话this.client.connect();}MQTT5.0基于这种网络连接频繁断开重连的情况,为了避免应用层频繁收到上下线事件,影响业务进行。MQTT5.0也对协议进行了响应的优化:
设置完会话保留状态,我们就可以使用QoS消息来保证消息的到达。
QoS消息在Broker端有内存持久化功能,除了客户端有内置的消息队列,Broker也有一个QoS消息队列。如上文所述,车联网场景经常发生的基站切换导致连接重置,反映到MQTT连接就体现为QoS消息积压现象。客户端和服务端都会有未确认的消息积压在队列里。所以我们要根据实际情况设置消息队列的长度。
以EMQX为例,消息队列设置:
打开emqx.conf
mqtt{##@docMaximumQoS2packets(Client->Broker)awaitingPUBREL.max_awaiting_rel=100##@docTheQoS2messages(Client->Broker)willbedroppedifawaitingPUBRELtimeout.await_rel_timeout=300s##@docMaximumqueuelength.Enqueuedmessageswhenpersistentclientdisconnected,orinflightwindowisfull.max_mqueue_len=1000}max_awaiting_rel为接受QoS2的消息队列长度。QoS1此项无限制。
max_mqueue_len为下发QoS1/2的队列缓存长度
由于TCP采用四元组来判断识别连接的独特性,而UDP并没有同样的要求。2022年6月11日,IETF正式颁布了HTTP/3RFC技术标准文档后,基于UDP的QUIC正式成为了传输层标准之一。而基于QUIC的MQTT方案也有望成为下一个行业标准。
借助QUIC协议的地址迁移、流式多路复用、分路流控、更低的连接建立延迟,我们有望彻底解决车联网移动场景下的连接问题。
QUIC能够侦测到地址改变,自动采用0-RTT的方式重建连接,从而使得客户端和服务端对于IP地址的变动无感知,这样就彻底避免了上文所说的一系列问题。
本文分析了车联网移动场景中MQTT通信不稳定现象的成因,并通过客户端和服务端对会话保持、QoS、客户端ID的配置和内置消息队列缓存等MQTT协议特性,在一定程度上解决了高速移动带来的连接不稳定导致的数据丢失问题。
EMQ车联网行业白皮书现已正式上线!
汇聚EMQ多年服务车联网领域客户的实践经验,从协议选择等理论知识到平台架构设计等实战操作,为车联网从业者搭建可靠、高效、符合行业场景需求的车联网平台提供可操作、可落地的参考指南。
EMQ边缘计算研发总监,NanoMQ项目发起者
本文我们将讨论车联网场景中的MQTT消息采集与传递,以及如何构建一个千万级车联网MQTT消息平台。
MQTT协议是一种基于发布/订阅模式的轻量级物联网消息传输协议,可以用极少的代码和带宽为联网设备提供实时可靠的消息服务。