2023年11月18日 星期六

MQTT 主題與通配符:初學者指南

 MQTT 主題與通配符Wildcards :初學者指南

https://www.emqx.com/en/blog/advanced-features-of-mqtt-topics

EMQX團隊
2023 年 6 月 25 日
MQTT 主題與通配符:初學者指南

目錄

  • 主題
  • MQTT 通配符
  • 以 $ 開頭的主題
  • 不同場景的主題
  • MQTT 主題常見問題解答

MQTT 主題是MQTT 協定中用於識別和路由訊息的字串。它是 MQTT 發布者和訂閱者之間溝通的關鍵元素。MQTT發布/訂閱模式中,發布者將訊息傳送到特定主題,而訂閱者可以訂閱這些主題來接收訊息。

與其他訊息系統(例如 Kafka 和 Pulsar)中的主題相比,MQTT 主題不需要事先建立。客戶端訂閱或發佈時會自動建立主題,不需要刪除主題。

以下是一個簡單的 MQTT 發布和訂閱流程。如果APP 1訂閱了該sensor/2/temperature主題,它將收到來自Sensor 2發佈到該主題的訊息。

MQTT 發布訂閱

主題

主題是 UTF-8 編碼的字串,它是 MQTT 協定中訊息路由的基礎。主題通常是分級的,並/在等級之間以斜線分隔。這與 URL 路徑類似,例如:

chat/room/1
sensor/10/temperature
sensor/+/temperature
sensor/#

儘管允許,但通常不建議使用以 開頭或結尾的主題/,例如/chatchat/

MQTT 通配符

MQTT 通配符是一種特殊類型的主題,只能用於訂閱,不能用於發布。客戶端可以訂閱通配符主題來接收來自多個匹配主題的訊息,從而無需單獨訂閱每個主題並減少開銷。MQTT 支援兩種類型的通配符:(+單級)和#(多層)。

單級通配符

+(U+002B) 是僅符合一個主題層級的通配符。使用單級通配符時,單級通配符必須佔據整個級別,例如:

"+" is valid
"sensor/+" is valid
"sensor/+/temperature" is valid
"sensor+" is invalid (does not occupy an entire level)

  

如果用戶端訂閱了該主題sensor/+/temperature,它將收到來自以下主題的訊息:

sensor/1/temperature
sensor/2/temperature
...
sensor/n/temperature

但它不會匹配以下主題:

sensor/temperature
sensor/bedroom/1/temperature

多層通配符 Multi-level Wildcard

#(U+0023) 是一個通配符,可符合主題中任意數量的等級。使用多層通配符時,它必須佔據整個級別,並且必須是主題的最後一個字符,例如:

"#" is valid, matches all topics
"sensor/#" is valid
"sensor/bedroom#" is invalid (+ or # are only used as a wildcard level)
"sensor/#/temperature" is invalid (# must be the last level)

以 $ 開頭的主題

系統主題

以 開頭的主題$SYS/是系統主題,主要用於取得 MQTT 伺服器的運作狀態、統計資料、客戶端上下線事件等元資料。主題在 MQTT 規格中沒有定義$SYS/然而,大多數MQTT 代理都會遵循此建議

例如,EMQX支援透過以下主題獲取集群狀態。

主題描述
$SYS/brokersEMQX 叢集節點列表
$SYS/brokers/${node}/versionEMQX 經紀商版本
$SYS/brokers/${node}/uptimeEMQX 代理程式啟動時間
$SYS/brokers/${node}/datetimeEMQX 經紀商時間
$SYS/brokers/${node}/sysdescrEMQX 經紀商描述

EMQX 也支援客戶端上下線事件、統計、系統監控和警報等豐富的系統主題。有關更多詳細信息,請參閱EMQX 系統主題文件。

共享訂閱

共享訂閱是MQTT 5.0的特性,是一種實現多個訂閱者之間負載平衡的訂閱方式。共享訂閱的主題以 $share 開頭。

雖然 MQTT 協議在 5.0 中增加了共享訂閱,但 EMQX 從 MQTT 3.1.1 開始支援共享訂閱。

在下圖中,三個訂閱者$share/g/topic使用共享訂閱方法訂閱同一個主題,其中topic是他們訂閱的真實主題名稱,發布者將訊息發佈到topic,但不是$share/g/topic




MQTT 共享訂閱


此外,EMQX 也支援使用$queueMQTT 3.1.1 中的共享訂閱前綴。它是共享訂閱的一種特殊情況,相當於將所有訂閱者歸為一個群組。

有關共享訂閱的更多詳細信息,請參閱EMQX 共享訂閱文件。

不同場景的主題

智慧家庭

例如,我們使用感測器來監測臥室、客廳和廚房的溫度、濕度和空氣品質。我們可以設計以下主題:

  • myhome/bedroom/temperature
  • myhome/bedroom/humidity
  • myhome/bedroom/airquality
  • myhome/livingroom/temperature
  • myhome/livingroom/humidity
  • myhome/livingroom/airquality
  • myhome/kitchen/temperature
  • myhome/kitchen/humidity
  • myhome/kitchen/airquality

接下來,您可以訂閱myhome/bedroom/+獲取臥室溫度、濕度和空氣品質數據的主題、myhome/+/temperature獲取所有三個房間的溫度數據的主題以及myhome/#獲取所有數據的主題。

充電樁

  • ocpp/cp/cp001/notify/bootNotification

    當充電樁上線時,向該主題發佈線上請求。

  • ocpp/cp/cp001/notify/startTransaction

    向該主題發布計費請求。

  • ocpp/cp/cp001/reply/bootNotification

    充電樁上線前,需要訂閱該主題才能接收線上回覆。

  • ocpp/cp/cp001/reply/startTransaction

    充電樁發起充電請求之前,需要訂閱該主題以接收充電請求回應。

即時通訊

  • chat/user/${user_id}/inbox

    一對一聊天:用戶上線後訂閱主題,會收到好友的訊息。回覆好友時,只要將主題的user_id替換為好友的id即可。

  • chat/group/${group_id}/inbox

    群組聊天:用戶成功加入群組後,可以訂閱主題來取得群組的訊息。

  • req/user/${user_id}/add

    新增好友:向該主題發布好友請求(user_id 為好友id)。

    接收好友請求:訂閱此主題(user_id為訂閱者id),接收其他使用者的好友請求。

  • resp/user/${user_id}/add

    接收好友請求回覆:新增好友前,使用者需要訂閱該主題(user_id為訂閱者id)才能接收請求結果。

    回覆好友請求:向該主題(user_id為好友id)發送是否核准好友請求的訊息。

  • user/${user_id}/state

    使用者狀態:訂閱此主題以取得好友的線上狀態。

MQTT 主題常見問題解答

MQTT 主題的最大等級和長度是多少?

MQTT 主題是 UTF-8 編碼的字串,且不得超過 65535 位元組然而在實踐中,使用較短長度的主題名稱和較少的等級意味著較少的資源消耗。

盡量不要「僅僅因為我可以」就使用更多的主題等級。例如,my-home/room1/data是比 更好的選擇my/home/room1/data

主題數量有限制嗎?

不同的訊息伺服器對主題的數量有不同的限制。目前,EMQX 預設配置對主題數量沒有限制,但主題越多,使用的伺服器記憶體就越多。

鑑於連接到 MQTT Broker 的裝置數量較多,我們建議客戶端訂閱的主題不超過 10 個。

通配符訂閱會降低效能嗎?

將訊息路由到通配符訂閱時,代理可能需要比非通配符主題更多的資源。如果可以避免通配符訂閱,這是一個明智的選擇。

這在很大程度上取決於如何為 MQTT 訊息負載建模資料模式。

例如,如果發布者發佈到device-id/stream1/foodevice-id/stream1/bar,並且訂閱者需要訂閱兩者,那麼它可以訂閱device-id/stream1/#一個更好的選擇可能是將命名空間的 foo 和 bar 部分下推到有效負載,這樣它就只發佈到一個主題,device-id/stream1而訂閱者只訂閱這個主題。

如何接收普通主題和通配符主題的重疊訂閱的訊息?

例如,如果客戶端訂閱了 和#主題test,那麼在發佈到 時會收到兩個重複的訊息嗎test這取決於 MQTT 代理的實作。EMQX 將為每個符合的訂閱發送訊息。因此,可能會出現重複。不過,使用者可以利用 MQTT 5.0 訂閱識別碼來區分訊息來源,並根據識別碼在用戶端處理此類重複訊息。

共享訂閱和普通訂閱可以訂閱同一個主題嗎?

可以,但不建議這樣做。

根據 MQTT 規範,多個訂閱將導致多次(重複)訊息傳遞。

MQTT 主題的最佳實踐是什麼?

  • 不要用於#訂閱所有主題。
  • 主題不應以/等開頭或結尾/chatchat/
  • 請勿在主題中使用空格和非 ASCII 字元。
  • 使用_-連接主題層級內的單字(或駝峰式大小寫)。
  • 嘗試使用較少的主題等級。
  • 嘗試對訊息資料模式進行建模,以避免使用通配符主題。
  • 使用通配符時,請嘗試將更獨特的主題層級移至更靠近根的位置。例如device/00000001/command/#是比 更好的選擇device/command/00000001/#

沒有留言:

張貼留言

WOKWI DHT22 & LED , Node-Red + SQLite database

 WOKWI DHT22 & LED , Node-Red + SQLite database Node-Red程式 [{"id":"6f0240353e534bbd","type":"comment&...