三個時間與去重鍵
Store-and-forward要同時保存來源採樣時間、閘道入列時間與平台送達時間。來源時間回答設備何時取樣,入列時間回答閘道何時接收並寫入queue,送達時間回答平台何時收到;只留一個timestamp,恢復補送後就無法判斷延遲或錯序。
本文提供可整理成CSV的離線樣本。斷線在t=0採樣前開始,於t=600秒採樣完成後恢復;採樣點為0、10、20直到600秒,含兩端共600/10+1=61筆。每列保存sourceID、bootEpoch、sequence、sampleTime、enqueueTime與deliveryTime,這是案例契約,不代表所有產品內建。
| 欄位 | 示例 | 用途 |
|---|---|---|
| sourceID | Line1.SensorA | 辨識來源設備與通道 |
| bootEpoch | boot-7 | 序號重啟後分開世代 |
| sequence | 1842 | 來源順序與去重 |
| sampleTime | 12:09:50Z | 設備取樣時刻 |
| enqueueTime | 12:09:51Z | 閘道入列時刻 |
| deliveryTime | 12:10:20Z | 平台收到時刻 |
去重鍵定義為sourceID+bootEpoch+sequence。時間戳不能取代序號,因為兩筆可能同秒,時鐘也可能回撥。bootEpoch如何產生、保存與跨重啟恢復,要由來源與gateway文件確認。
例如設備12:00:10取樣、閘道12:00:11入列,外網12:10:01恢復,該筆於12:10:25送達。保留三個時間,才能分開分析採樣到入列的一秒,以及入列後的等待和補送。不要把恢復時刻填進每筆sampleTime,否則十分鐘歷史會全部擠到同一個時間。
容量與溢位算式
十分鐘斷線的61筆只是事件數,還要把每筆序列化大小、索引與檔案開銷算入容量。假設payload 320 bytes、索引與狀態80 bytes,單筆預算400 bytes,需求是61×400=24,400 bytes。另加標頭、校驗、檔案系統與安全餘量後,才是應配置的容量。
| 假設 | 算式 | 結果 |
|---|---|---|
| 10秒週期含兩端 | 600/10+1 | 61筆 |
| 單筆佇列預算 | 320+80 bytes | 400 bytes |
| 十分鐘純資料 | 61×400 | 24,400 bytes |
| 容量20,000 bytes | 20,000/400 | 50筆,少11筆 |
| 無新事件且2筆/秒 | 61/2 | 至少30.5秒 |
容量只有20,000 bytes時,不能靜默覆蓋。產品必須明定丟最舊、丟最新、阻塞採樣或降採樣,並增加overflow事件;哪一種策略可用要查官方手冊。RAM、磁碟或SD是否持久化也不是由store-and-forward名稱保證。
恢復期間若仍每十秒新增一筆,新增率是0.1筆/秒。理想處理率2筆/秒扣除新增後,淨清空率為1.9筆/秒,61/1.9約32.1秒;這是連續流量近似,實際還受整筆排程、ACK與重試影響。表中的30.5秒只適用不再新增且不重試的理想下限。
每筆最大bytes也要限制。若一筆異常payload膨脹到800 bytes,原本400 bytes的容量估算會失真;解析器應拒收超長列或將其標記,而不是讓一列吃掉整個queue。
容量預算還要考慮事件索引、校驗碼、檔案分段與加密包裝。案例的400 bytes是離線合成估算,不是硬體量測;正式配置應以產品文件的實際序列化格式與上限取較大值,並安排滿載前告警。
恢復後若補送與新資料並行,平台應以事件ID去重並按契約排序;若消費者只能按到達順序處理,閘道必須限制並行或提供序號範圍,這是產品能力限制,不能用一般TCP順序推定應用順序。
clockChanged不等於資料無效。來源時間仍可作歷史證據,但報表可依品質政策排除錯序區間;契約要把保存原值與分析是否採用分開,不能為了畫面順序修改原始時間。
ACK遺失與重送去重
最容易重複的是平台已提交事件,業務確認在回程遺失。Line1.SensorA、boot-7、sequence1842於12:10:20Z送達並提交;12:10:25Z重送相同事件鍵時,本例平台回duplicate而不新增第二筆。MQTT的協定確認與這裡的資料庫提交確認要分開看。
| 事件 | sample | enqueue | delivery | 結果 |
|---|---|---|---|---|
| 1842首次 | 12:09:50Z | 12:09:51Z | 12:10:20Z | commit、ACK遺失 |
| 1842重送 | 12:09:50Z | 12:09:51Z | 12:10:25Z | duplicate |
| 1843首次 | 12:10:00Z | 12:10:01Z | 12:10:26Z | 單次commit |
| boot-8/1 | 12:10:05Z | 12:10:06Z | 12:10:27Z | 新世代 |
消費者不可用deliveryTime排序製程事件,應保留sampleTime、sequence與bootEpoch。若sampleTime回撥,平台仍先用事件ID去重,再依政策標記out-of-order;不要用閘道補送時間覆蓋設備時間。
MQTT QoS描述協定訊息的交付語意,不能自動保證業務資料庫與累加操作冪等。以sourceID、bootEpoch、sequence建立唯一約束,並把去重與業務更新放入同一持久化交易。同一鍵卻有不同payload時要報衝突,不能直接當正常重送吞掉。
離線練習可把表格轉成CSV,模擬1842的業務確認遺失後再送一次,應看到一筆正式事件與兩筆送達紀錄。再送boot-8的sequence1,應新增事件;不同開機世代不能混為同一次採樣。這些是預期結果,並非本文已執行資料庫測試。
若採樣週期在運轉中由10秒改成1秒,十分鐘筆數會變成601筆,純資料預算升到601×400=240400 bytes。變更週期時必須同步重新計算queue與補送時間,不能沿用原本24400 bytes的設定。
驗收報告列出斷線開始與結束、採樣週期、總筆數、入列筆數、overflow、重送筆數、duplicate數、遺失數與時鐘事件,數量應能互相核對。
時鐘 順序與故障排查
來源時鐘可能被校正。若sequence1850時間為12:20:00Z,1851卻是12:19:40Z,先保存原值並標clockUncertain。只有校時日誌等證據支持,才確認clockChanged;時間倒退不能證明事件遺失。先用同一世代的序號檢查缺口,再分析時間是否可信。
| 狀況 | 先查證據 | 預期處理 |
|---|---|---|
| 時鐘前跳 | sample、校時紀錄 | 標時間不連續,不能推論缺筆 |
| 時鐘回撥 | sequence、bootEpoch | 去重後標錯序 |
| 重啟 | bootEpoch、queue索引 | 按文件恢復或標遺失 |
| ACK遺失 | commit與delivery記錄 | 同ID只commit一次 |
入列順序也要明確。若產品保證按最舊sequence補送,消費者可按序處理;若產品採最新優先,契約要允許先看到新事件。閘道不能同時宣稱嚴格順序與最新優先,除非它提供兩種不同佇列。
queue滿載先查目前筆數、最早與最新sequence、overflow計數、持久化錯誤與時鐘狀態。網路恢復慢不能靠增加重試解決容量不足;檔案寫入失敗也不能用清空queue假裝修復。保存CSV、索引與送達回應,才能重建缺口。
版本化設定包含採樣週期、每筆最大bytes、容量、溢位策略、重送順序、去重保留時間、時鐘來源與告警。哪些欄位可設、哪些固定,均需以目標gateway官方手冊確認。
若queue持久化採檔案,寫入成功與索引commit也可能是兩個步驟。重啟後要檢查最後一筆是否已commit、是否可能重送,消費者仍以sourceID、bootEpoch、sequence冪等處理,不靠閘道畫面顯示的筆數。
若事件檔案被截斷,先保存原檔與索引,再決定是否重建,不能直接刪除半筆資料。
去重記錄保留時間至少涵蓋可重送的最長期間,還要考慮備份還原帶回舊事件。若閘道可補送七天,而平台只記住一天的事件鍵,第兩天重送就可能再次計數。這是兩端共同的保留契約,不能只調大閘道queue就算完成。
FAQ與來源
FAQ1:十分鐘斷線一定60筆嗎?不一定;本例0與600秒兩端都採樣,所以61筆。如果600秒恢復先於該次採樣,計數就可能是60筆,先定義邊界。
FAQ2:MQTT重送會自動避免重複嗎?不能假設,平台仍需事件ID去重。
FAQ3:可以用送達時間取代來源時間嗎?不行,三個時間各自描述不同事件。
FAQ4:queue滿了能直接丟最舊嗎?只能在契約明定並產生overflow證據後執行。
重送測試同時保存首次與重送的deliveryTime。本例應用回覆區分committed與duplicate;這是自行設計的業務回覆,不是MQTT PUBACK的欄位。如果平台只回冪等成功,也可以由資料庫唯一鍵與送達紀錄證明未新增第二筆,不能要求所有產品一定回duplicate字串。
被丟棄事件要保存來源、sequence、原因與時間範圍。丟最舊與丟最新對報表意義不同;若產品只提供一種策略,契約應明示並把overflow告警送到獨立通道,避免正常資料topic掩蓋遺失。
Ignition的Store and Forward文件以資料庫寫入為場景,區分記憶體緩衝、磁碟快取及送往資料庫的階段。這能幫你理解產品如何實作暫存,但不代表任何MQTT閘道都具備相同持久化與重啟恢復能力。採購或設定時,把斷電後保留量和損壞復原方式列為需要核對的項目。
本篇數字、CSV、去重與時鐘情境為教學案例,持久化、重啟恢復、QoS、順序與去重功能須查目標產品文件。
參考:OASIS MQTT Version 5.0:PUBLISH、QoS與傳輸語意;不替應用資料定義去重鍵。
參考:Ignition 8.3 Store and Forward,資料庫暫存階段的產品實例。