MQTT version upgrade process and resolve the source

MQTT version upgrade process and resolve the source


  First talk about why write this article it, I found the article on the Internet MQTT introduced is too small, it may also use this relatively low frequency it! There is the problem of locating and addressing ways and means too little, so he wrote this article hoping to make some contribution to help some people in need.

  The main problem MQTT record what appeared in the original version 1.2.0 course, to troubleshoot problems that occur during the upgrade version 1.2.1, the source code through a step by step investigation and the final point of the problem, until in line with expectations.

 

<!-- https://mvnrepository.com/artifact/org.eclipse.paho/org.eclipse.paho.client.mqttv3 -->
<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>1.2.1</version>
</dependency>

  MQTT to build and SSL certificate can refer to this blog: https://www.cnblogs.com/yueli/p/7490453.html  not set forth in this carefully


  Qos introduction 

  In the beginning of the first look at the meaning of some of Qos, is the problem for the fuse

  • Qos = 0 up to a transmission

       Publisher PUBLISH message to the server (broker), i.e., the transmission is discarded. No confirmation message, I do not know whether the other party is received. The network level, small pressure transmission

  • Qos = 1 at least one transmission

   The publisher announced saving message, the server (broker) receives a message, the server (broker) PUBLISH to the subscriber server (broker) back to a PUBACK information to the publisher let delete the message, then the subscriber after receiving a message PUBACK to the server so that deleted messages. If it fails, there is no confirmed information received over a period of time, the sender will be DUP header is set to 1, and then send the message again, the message at least once to reach the service. Such as network latency and other issues, the publisher repeat to send a message, subscribers subscribe to repeat the message several times 

  • Qos = 2 only one transmission

  In fact, Qos = 2 just did a rush to get rid of the foot on the basis of 1, the publisher PUBLISH to the server after more than a confirmation message, and more news msgID cache , to repeat information heavy. After the subscriber server PUBLISH to be more than a confirmation message.

  The difference between the three cases

   0 not saved message, there is no retransmission mechanism, do not know what matter, 1 and 2 of the publisher and the server has saved message, the publisher has retransmission mechanism, confirmation mechanism PUBACK after the server has PUBLISH, but the server 2 a plurality of cache msgID feature that provides de-duplication function to prevent repeated transmission of the message, and the message received acknowledgment mechanism. Subscribers introduction here, but more interested to go to understand.


 MQTT1.2.1 version emerging issues 

  Description of the problem: because more places to use MQTT communication projects, usually in a form of Qos = 0, this time found that will always remind error Too many publishes in progress (32202), the place looked at the source code error

   From here you can set up their own judgment actualInFlight exceed the maximum maxInflight caused by attempts to increase maxInflight also useless, but the delay error time only


 Troubleshooting process

  First Internet search to see if there are similar problems, sure enough have a buddy met, blog address: https://blog.csdn.net/lblblblblzdx/article/details/81159478  this article gave me a lot of help, thanks to bloggers, but the final solution is not very good.

  Source logical track release process

  The first step: the process publish

//1
public IMqttDeliveryToken publish(String topic, MqttMessage message, Object userContext,IMqttActionListener callback)
//2
public void sendNoWait(MqttWireMessage message, MqttToken token)
//3
void internalSend(MqttWireMessage message, MqttToken token)
//4
public void send(MqttWireMessage message, MqttToken token) 

  Step Two: Qos of all types, configured in the top-level parent publish message default settings msgId = 0  

  The third step: the message made major deal in the send method

   Step Four: According to the description above Qos, that we publish news of this place all cached tokens here, in fact, placed in the Hashtable, no matter what level of Qos

   In these steps, the good news is already cached, ready to send asynchronous, in which the lock mechanism is not much to explain

  Step five: asynchronous send, it is mainly in the client link to complete when he had begun to listen up, connect flow

 1 //1
 2 public IMqttToken connect(MqttConnectOptions options)
 3 
 4 //2 异步链接
 5 ConnectActionListener connectActionListener = new ConnectActionListener(this, persistence, comms, options,userToken,userContext, callback, reconnecting);
 6 connectActionListener.connect();
 7 
 8 //3 客户端的通信链接,包括发送和接收
 9 ClientComms.connect(options, token);
10 
11 //4 个人理解是 将通信信息塞进线程池中,分别开启发送和接收的线程处理
12 ConnectBG conbg = new ConnectBG(this, token, connect, executorService);
13 conbg.start();

  第六步:在ConnectBG的run中 new CommsSender. start线程run中while循环发送的信息流程,一直发送消息中

 

   第七步:在notifySent的方法中判断Qos = 0 的作出了判断及操作

   这些差不多就是发布过程的主题流程结构,了解这些才会知道让你解决问题更加的容易


  问题点

  在上面的第六步的图中黄色箭头指出了问题出现的点,主要是在大数据量高并发的时候,因为在Qos = 0 的时候,在tokens(Hashtable)中的key一直是0,默认初始化。后面的流程中并没有改变过,在黄色那块tokenStore.getToken 在发送之后才remove数据,但是多条数据高并发的时候,在remove数据之后,后一条在get的时候会出现空的状况,不发送信息,导致actualInFlight没有减,一直增加,一定时间后就会超出最大值。Qos =1 、2 是不会发送这样的情况,因为他们的messageId是唯一的。


  解决办法

  1. 将Qos设置为1 (这是网上主流的解决办法,但是这个太耗费资源问题,在我看来只是规避问题点而已)
  2. 升级MQTT版本1.2.1    (这个版本解决了刚才说的bug)      
  3. 也可以想想在不升级版本的情况下如何去改善这个问题,重写那些类可以实现···

  


 

   解决过程

  既然说了第一种解决办法不是很赞同,那就直接进去第二种办法吧。升级到1.2.1版,时间:Feb, 2019,但是在升级版本的时候又出现了一些问题,因为改动还是有点多的。

  接下来说说1.2.1版本的改动了什么呢


  首先主要改动的是在Qos = 0 的不放入tokens中了,首先想到的是不会get到了,也不用担心重复了,直接从集合pendingMessages中拿

   然后从信息的自身获取数据的token,获取不到再去tokens中拿

    以上两个就是主要解决这个高并发冲突的原因


    跳入另一个坑中···

   为什么这么说呢,在我们开发的意识中,升级版本怎么也要向下兼容吧,那就顺其自然的换个版本就完事了,结果一跑起来,一堆红色的出现,那心情···我太南了。以我的性子,就是不能惯着她,继续深挖为什么,既然坑已经有了,就不怕有多深。

   另一个坑的过程

    第一时间也是上网搜一些为啥,大家的解决也差不多,都是SSL验证出现问题,但是解决方案也是五花八门


 

  解决方案

       第一种:设置系统属性  类似这样的文章 https://blog.csdn.net/hxpjava1/article/details/77937026

   第二种:有看了一些代码了,就是重写X509TrustManagerImpl,绕过SSL的验证,试过有用,类似这样的文章 https://blog.csdn.net/iverson_AL/article/details/100669777

   第三种:再深入看一些源码,你会看到会什么会报错,为什么会验证,主要是你的属性没有设置好,采用了默认验证导致


   解决过程

  这里主要说一下解决的过程,如何从这些网络文章种找出适合自己的出路。

  首先 第一种我就不咋喜欢,动不动就设置了系统全局属性,第二种方案,有两种可能性,一是这个api真的有问题或是不符合自己的项目需要重写代码逻辑结构,二是在不了解的情况下直接绕过验证。我在测试第二个的时候就是如此只是稍微看了一下源码,没有深入看进去,试了一下,果真可以实现我想要目的。

  但是过后又想了一下,不该如此,既然开源出来的东西,不可能如此**,应该会有什么地方可以简单设置一下的。既然有这个想法就一直深入探究下去,果不其然,真相出来了。

  在1.2.1版本中MqttConnectOptions 的httpsHostnameVerificationEnabled属性默认true,导致不是Https的被验证不通过导致的,也可能MQTT开发人员安全意识很强,在1.2.0版本中没有这个概念存在,所以在版本升级的时候需要加上MqttConnectOptions.setHttpsHostnameVerificationEnabled(false);

  以下源码查看的过程

    若是有Https证书是不会有问题的。


  总结一下

   其实很简单的问题,居然整的时候那么复杂,原因是我们不够强,面对源码的时候还是比较害怕的,还有比较懒吧。

   整个过程比较繁琐,啰嗦吧,耐心看下来,应该有收获。

   操作总结:

    1. 升级MQTT版本1.2.1
    2. 若不是https的需要设置为false
    3. 不要走,跑起来

   扩展点及疑惑地点可以供参考

  

 

              转载请注明出处  https://www.cnblogs.com/zhouguanglin/p/11986446.html

 

Guess you like

Origin www.cnblogs.com/zhouguanglin/p/11986446.html