使用 MQTT 代理程式開發高可用性應用程式
使用 MQTT 代理程式建立高可用性應用程式時,請審慎考量工作階段類型、服務品質 (QoS)、訊息確認、平行訊息處理、訊息保留與共用訂用帳戶。 MQTT 代理程式具有分散式記憶體內部訊息代理程式與存放區,可利用 MQTT 語意保留訊息並管理內建狀態。
下列章節將說明可用於建立可靠且零訊息遺失之分散式應用程式的設定與功能。
服務品質 (QoS)
發行者與訂閱者都應使用 QoS-1,確保至少進行一次訊息傳遞。 MQTT 訊息代理程式會儲存並重新傳輸訊息,直到收到收件者的通知(ACK),確保傳輸期間不會遺失任何訊息。
工作階段類型與清除工作階段旗標
若要確保零訊息遺失,請在連線至 MQTT 代理程式時,將 clean-start 旗標設定為 false。 此設定會通知訊息代理程式維持用戶端的工作階段狀態,保留訂用帳戶與連線之間的未確認訊息。 若用戶端連線中斷,並於稍後重新連線,則會從中斷位置繼續透過重試訊息傳遞接收所有未確認的 QoS-1 訊息。 若已進行設定,且用戶端未於預設為一天的工作階段到期間隔內重新連線,MQTT 代理程式便會認定用戶端工作階段已到期。
多執行緒應用程式的接收上限
多執行緒應用程式應以接收上限 (最大值 65,535) 平行處理訊息,並套用流量控制。 透過此設定,多個執行緒可同時處理訊息,改善訊息處理能力,並避免訊息代理程式以高於應用程式容量的速率處理訊息,導致應用程式多載。 各個執行緒都能獨立處理訊息,並在完成時傳送確認通知。 一般會根據應用程式所使用的執行緒數目按比例設定「接收上限」。
確認訊息
訂閱者應用程式傳送 QoS-1 訊息的確認通知時,其將獲得訊息的所有權。 收到 QoS-1 訊息的確認通知後,MQTT 代理程式便會停止追蹤該應用程式與主題的訊息。 妥善轉讓所有權可確保在處理問題或應用程式當機時保留訊息。 若要避免應用程式當機,則必須確保應用程式在成功完成訊息處理前,不會取得該訊息的所有權。 若應用程式已訂閱 MQTT 代理程式,則應將確認通知訊息延遲至處理完最大值為 65,535 的「接收上限」後。 這可能包括將訊息或其衍生項目轉送至 MQTT 代理程式,以便進一步分派。
訊息保留與訊息代理程式行為
訊息代理程式會保留訊息,直到收到訂閱者的確認通知,確保不會遺失任何訊息。 即使訂閱者應用程式暫時當機或連線中斷,此行為也可確保訊息不會遺失,且應用程式重新連線後即可進行處理。 若以 Message-Expiry-Interval 設定 MQTT 代理程式訊息,且訂閱者未取用訊息,則訊息可能會過期。
已保留的訊息
已保留的訊息會保持暫時性應用程式狀態,例如特定主題的最新狀態或值。 新用戶端訂閱主題時,將會收到上次保留的訊息,藉此取得最新資訊。
保持連線
若要在連線錯誤或卸除時仍確保高可用性,請針對用戶端與伺服器之間的通訊設定適當保持連線間隔。 閒置期間,用戶端會傳送 PINGREQs 並等候 PINGRESP。 若沒有回應,請在用戶端中實作自動重新連線邏輯,以重新建立連線。 Paho 等大多數用戶端已內建重試邏輯。 由於 MQTT 代理程式可容錯,因此若前端與後端至少有兩個狀況良好的代理程式執行個體,便能成功重新連線。
以 QoS-1 訂用帳戶達成最終一致性
使用 QoS-1 的 MQTT 訂用帳戶可藉由訂閱共用主題,確保相同應用程式執行個體達成最終一致性。 發佈訊息時,執行個體會透過至少一次傳遞來接收與複製資料。 執行個體必須處理重複項目,並在資料已同步處理前容許暫時性的資料不一致情況。
共用訂用帳戶
共用訂用帳戶可在高可用性應用程式的多個執行個體上實現負載平衡。 各個訂閱者將能接收平均分配的訊息,而非每個訊息的複本。 MQTT 代理程式目前僅支援循環配置資源演算法,用於散發允許應用程式擴增的訊息。典型的使用案例為使用 Kubernetes ReplicaSet 部署多個 Pod,而 Pod 全都使用共用訂用帳戶中的相同主題篩選來訂閱 MQTT 代理程式。
狀態存放區
狀態存放區是復寫的記憶體 內部 HashMap ,用於管理應用程式處理狀態。 例如,不同於 etcd,狀態存放區會透過記憶體內部資料結構、資料分割和鏈結複寫,設定高速輸送量、水平調整和低延遲的優先順序。 它可讓應用程式使用狀態存放區分散式本質和容錯,同時快速跨實例存取一致的狀態。 若要使用分散式訊息代理程式提供的內建索引鍵值存放區:
以訊息代理程式索引鍵值存放區 API 執行暫時性儲存與擷取作業,進行妥善的錯誤處理,並保持資料一致性。 暫時性狀態是用於具狀態處理過程中的短期資料儲存體,以在即時計算期間快速存取中繼結果或中繼資料。 在 HA 應用程式中,暫時性狀態可在發生當機時協助復原應用程式狀態。 此狀態與用於長期儲存不常存取之資料的冷儲存體不同,雖可寫入磁碟,卻仍僅用於暫存資料。
使用狀態存放區在應用程式的多個實例之間共享狀態、快取、組態或其他基本數據,讓他們能夠保持數據的一致檢視。
使用 MQTT 代理程式內建的 Dapr 整合
在較簡易的使用案例中,應用程式可使用 Dapr (分散式應用程式執行階段)。 Dapr 是可攜式的開源事件驅動執行階段,可簡化微服務與分散式應用程式的建置流程。 其提供一系列建置組塊,例如服務對服務調用、狀態管理與發佈-訂閱傳訊。
Dapr 為 MQTT 代理程式的供應項目,抽象化 MQTT 工作階段管理、訊息 QoS 與確認通知,以及內建索引鍵值存放區的細節,可透過以下方式,針對簡單的使用案例開發高可用性應用程式:
使用 Dapr 的建置組塊設計應用程式,例如以狀態管理處理索引鍵值存放區,以及利用發佈-訂閱傳訊與 MQTT 代理互動。 若使用案例須使用 Dapr 不支援的建置組塊與抽象概念,請考慮使用先前所述的 MQTT 代理程式功能。
以偏好的程式設計語言與架構實作應用程式,利用 Dapr SDK 或 API 無縫整合訊息代理程式與索引鍵值存放區。
開發高可用性應用程式的檢查清單
- 選擇適合您的程式設計語言的 MQTT 用戶端程式庫。 用戶端應可支援 MQTT v5。 若您的應用程式容易受延遲影響,請使用 C 或 Rust 型程式庫。
- 設定客戶端連結庫以連線到 MQTT 訊息代理程式,並將 清除會話 旗標設定為
false
和所需的 QoS 層級 (QoS-1)。 - 針對工作階段到期、訊息到期與保持連線間隔決定適合的值。
- 實作訂閱者應用程式的訊息處理邏輯,包括在已成功傳遞或處理訊息時傳送確認通知。
- 設定多執行緒應用程式的「接收上限」參數,以進行平行訊息處理。
- 使用已保留的訊息以保持暫時性應用程式狀態。
- 利用分散式狀態存放區來管理暫時的應用程式狀態。
- 若使用案例較簡單,且不須針對 MQTT 連線或訊息處理進行詳細控制,請考慮利用 Dapr 來開發應用程式。
- 實作共用訂用帳戶以將訊息平均分配給應用程式的多個執行個體,藉此高效進行調整。