什么是服务质量?
 服务质量(QualityofService,QoS)等级是消息发送方与消息接收方之间的协议,对应着消息传递时不同的可靠程度。
 MQTT有三种QoS等级:
- 至多一次(QoS 0)
- 至少一次(QoS 1)
- 只有一次(QoS 2)
MQTT中消息的发布和订阅都有QoS等级的设置,我们需要将其分开理解
 1.publish的QoS等级
 1.1 QoS 0
 当client1 publish一条消息时,如果设置的QoS等于0,那么client1只会发送一次这条消息,就算broker没有收到,client1也不会管。对于broker来说,它收到client1 publish的消息,就会PUBLISH给众多客户端,收不到自然也不会PUBLISH。产生的效果:broker最终会PUBLISH 0条或1条消息,即至多一次。 
1.2 QoS 1
 上面那个例子,如果设置QoS等于1,那么client1发送一条消息,broker收到后会发给client1一个应答PUBACK,client1如果收到应答就会停止发送,否则,继续发送。broker做的事情也很简单,收到一次消息,就将消息PUBLISH给众多客户端,同时发现QoS等级为1,就向刚刚给自己publish消息的client1发送一个响应PUBACK。但是在这种交互中存在两个问题,1:client1 publish的消息有可能broker没能收到,2:broker回复的PUBACK client1没能收到。这样会造成:broker收到消息,将消息PUBLISH出去后,client1没能收到PUBACK,就会继续发送消息,broker就会继续PUBLISH,直到client1收到PUBACK为止。产生效果:broker最终会PUBLISH 至少1条消息,即至少一次。 
1.3 QoS 2
 还是上面的例子,如果设置QoS等于2,那么client1发送一条消息后,broker会回一个PUBREC(publish recevied)(但是这里注意broker虽然已经收到了消息但是它不会立马PUBLISH给众多客户端,还要等待后续步骤),client1收到PUBREC会回应一个PUBREL(publish release)(即既然你broker收到了,我client1就把这条消息释放了,保存起来太占地方),client1也不会再重复发这条消息了,因为都已经释放这个包了,broker收到PUBREL后会回复client1一个PUBCOMP(publish complete)(即这次消息传递完毕),broker发完PUBCOMP后,才会将刚才的消息PUBLISH给众多客户端。在PUBCOMP之前的交互中,如若有丢包同样会重传。产生效果:broker最终会PUBLISH 1条消息,不会多于1条,也不会少于1条。 
应用场景:
 为什么要有这三种服务质量等级呢?我们结合具体需求来思考一下 
 QoS 0 适合什么场景呢?适合那种消息很频繁但又不那么重要的应用,如每隔几分钟上报一次气温,数据丢了就丢了,反正待会还会上报,并且丢失一次数据也不会产生多大影响。 
 但是,如果消息对你很重要,你宁愿收到重复的也不愿意丢失一条,那你就采用QoS 1 
 但是,如果像支付类的应用也采用QoS 1的话,会产生重复支付的问题(其实已经支付成功了,只是手机没有收到回应,又再次发起支付),这时候就需要使用QoS 2了,它保证有且仅有一次消息成功传递。
2.subscribe的QoS等级
 说完了publish的QoS,我们再来谈谈subscribe的QoS。其实我们完全可以使用上面三个例子的分析,因为clientA、clientB、clientC 订阅 broker的消息就相当于broker发布消息给他们(这点从后面的抓包分析也可得以验证),我们仍然可用publish的那一套去理解subscribe的QoS,即client A subscribe消息时设置的QoS等于0,那么broker最多只会发一次消息给clientA。QoS设置为1,那么broker至少会发一次消息给到clientA,给不到就重发。QoS设置为2,那么broker保证有且只有一次消息给到clientA。 
 但是有一个问题需要注意一下,对于同一个topic,如果client1以QoS 2等级发布,clientA以QoS 0等级订阅,那么clientA最多只会收到一条消息,即两者质量等级取最低。同样的,如果clinet1以QoS 0发布一条消息,clientA以QoS 2等级去订阅,clientA仍然最多只会收到一条消息,因为原则是两者QoS取最低。所以如果要想达到真正的QoS 2质量,就要保证publish和subscribe都设置为 QoS 2
3.抓包
 下面结合抓包做一些直观的展示
 192.168.2.195为客户端
 211.159.1.50为服务端
 3.1 connect 连接请求报文 
3.5 发布消息 
现在我们将publish 的服务质量等级设为 QoS 1 
 再次抓包 
 发现每一个publish的消息服务端都会有一个回应
再将服务质量等级提升到 QoS 2 
 抓包 
 和上面分析的QoS 2一致,每次消息传递都需要四次交互,即(publish)Publish Message、(PUBREC)Publish Received、(PUBREL)Publish Release、(PUBCOMP)Publish Complete
3.6 还想看一下subscribe的QoS 
 我在客户端同时发布和订阅了相同的topic,服务质量等级都设为QoS 2, 
 截图中,方框框住的上面四条为客户端向服务端publish消息时产生的交互,满足上面的QoS 2等级的分析。下面四条为客户端订阅了topic而收到消息时的交互,同时也验证了客户端订阅就相当于服务端发布的猜想。
参考文章:
