物聯網(Internet of Things,IoT)最近曝光率越來越高。雖然HTTP是網頁的事實標准,不過機器之間(Machine-to-Machine,M2M)的大規模溝通需要不同的模式:之前的請求/回答(Request/Response)模式不再合適,取而代之的是發布/訂閱(Publish/Subscribe)模式。這就是輕量級、可擴展的MQTT(Message Queuing Telemetry Transport)可以施展拳腳的舞台。
MQTT簡介
MQTT是基於二進制消息的發布/訂閱編程模式的消息協議,最早由IBM提出的,如今已經成為OASIS規范。由於規范很簡單,非常適合需要低功耗和網絡帶寬有限的IoT場景,比如:
- 遙感數據
- 汽車
- 智能家居
- 智慧城市
- 醫療醫護
由於物聯網的環境是非常特別的,所以MQTT遵循以下設計原則:
- 精簡,不添加可有可無的功能。
- 發布/訂閱(Pub/Sub)模式,方便消息在傳感器之間傳遞。
- 允許用戶動態創建主題,零運維成本。
- 把傳輸量降到最低以提高傳輸效率。
- 把低帶寬、高延遲、不穩定的網絡等因素考慮在內。
- 支持連續的會話控制。
- 理解客戶端計算能力可能很低。
- 提供服務質量管理。
- 假設數據不可知,不強求傳輸數據的類型與格式,保持靈活性。
運用MQTT協議,設備可以很方便地連接到物聯網雲服務,管理設備並處理數據,最后應用到各種業務場景,如下圖所示:
發布/訂閱模式
與請求/回答這種同步模式不同,發布/訂閱模式解耦了發布消息的客戶(發布者)與訂閱消息的客戶(訂閱者)之間的關系,這意味着發布者和訂閱者之間並不需要直接建立聯系。打個比方,你打電話給朋友,一直要等到朋友接電話了才能夠開始交流,是一個典型的同步請求/回答的場景;而給一個好友郵件列表發電子郵件就不一樣,你發好電子郵件該干嘛干嘛,好友們到有空了去查看郵件就是了,是一個典型的異步發布/訂閱的場景。
熟悉編程的同學一定非常熟悉這種設計模式了,因為它帶來了這些好處:
- 發布者與訂閱者不必了解彼此,只要認識同一個消息代理即可。
- 發布者和訂閱者不需要交互,發布者無需等待訂閱者確認而導致鎖定。
- 發布者和訂閱者不需要同時在線,可以自由選擇時間來消費消息。
主題
MQTT是通過主題對消息進行分類的,本質上就是一個UTF-8的字符串,不過可以通過反斜杠表示多個層級關系。主題並不需要創建,直接使用就是了。
主題還可以通過通配符進行過濾。其中,+可以過濾一個層級,而#只能出現在主題最后表示過濾任意級別的層級。
舉個例子:
- building-b/floor-5:代表B樓5層的設備。
- +/floor-5:代表任何一個樓的5層的設備。
- building-b/#:代表B樓所有的設備。
注意,MQTT允許使用通配符訂閱主題,但是並不允許使用通配符廣播。
服務質量
為了滿足不同的場景,MQTT支持三種不同級別的服務質量(Quality of Service,QoS)為不同場景提供消息可靠性:
- 級別0:盡力而為。消息發送者會想盡辦法發送消息,但是遇到意外並不會重試。
- 級別1:至少一次。消息接收者如果沒有知會或者知會本身丟失,消息發送者會再次發送以保證消息接收者至少會收到一次,當然可能造成重復消息。
- 級別2:恰好一次。保證這種語義肯定會減少並發或者增加延時,不過丟失或者重復消息是不可接受的時候,級別2是最合適的。
服務質量是個老話題了。級別2所提供的不重不丟很多情況下是最理想的,不過往返多次的確認一定對並發和延遲帶來影響。級別1提供的至少一次語義在日志處理這種場景下是完全OK的,所以像Kafka這類的系統利用這一特點減少確認從而大大提高了並發。級別0適合雞肋數據場景,食之無味棄之可惜,就這么着吧。
消息類型
MQTT擁有14種不同的消息類型:
- CONNECT:客戶端連接到MQTT代理
- CONNACK:連接確認
- PUBLISH:新發布消息
- PUBACK:新發布消息確認,是QoS 1給PUBLISH消息的回復
- PUBREC:QoS 2消息流的第一部分,表示消息發布已記錄
- PUBREL:QoS 2消息流的第二部分,表示消息發布已釋放
- PUBCOMP:QoS 2消息流的第三部分,表示消息發布完成
- SUBSCRIBE:客戶端訂閱某個主題
- SUBACK:對於SUBSCRIBE消息的確認
- UNSUBSCRIBE:客戶端終止訂閱的消息
- UNSUBACK:對於UNSUBSCRIBE消息的確認
- PINGREQ:心跳
- PINGRESP:確認心跳
- DISCONNECT:客戶端終止連接前優雅地通知MQTT代理