先畫出資料真正保存的位置
PLC到資料庫中間可能經過閘道記憶體、磁碟佇列、接收服務與資料庫交易。網路恢復只表示可以重新傳送,不表示每一段都保存了資料。先列出每段何時接手責任、何時可以刪除前一段的暫存,再設計補送,才能知道斷電時哪裡會遺失。
教學架構是PLC產生事件,閘道持久保存待送項目,接收服務把事件與明細寫入資料庫,提交成功後回覆接受。這是可供規劃的架構,不代表所有PLC或閘道都支援磁碟佇列;實際容量、寫入壽命與掉電保存能力必須查產品並測試。
先區分即時值與歷史事件。恢復連線後,最新壓力值不能補回斷線期間每一筆壓力;產量累積值也未必能還原每件產品的時間與品質。需求若要完整事件,來源或中介層就必須在斷線期間保留足夠資料,而不是期待資料庫自行推算。
本文以PostgreSQL 18交易與唯一衝突處理為資料庫參考,PLC端只說明介面責任,不提供未核對的三菱指令。資料補送的確認不可等同控制命令完成,歷史資料重送也不能被接收系統誤當成再次驅動設備的命令。
把一件產品的主檔與明細一起提交
假設每件產品事件包含一筆主檔與三筆測量明細,共四列。要求是四列全部成功才算接受;若第三筆明細型別錯誤,整個事件交易回復,不能留下只有主檔的半套資料,也不能對來源回覆完整成功。
事件鍵在第一次保存待送資料時就固定,補送沿用相同鍵。主檔以事件鍵唯一,明細以事件鍵加明細序號唯一,避免重試把三個測量值再加一次。不同產品事件即使數值相同仍是不同事件,不能按內容相同就刪掉。
接收端先驗證格式與必要欄位,再在交易內接受事件及明細。相同鍵且內容相同的重送回覆已接受;相同鍵但明細不同則保留衝突,不能用重試機制偷偷更正歷史。真正更正應有獨立的修訂身分與流程。
完成後可用下列案例驗收:十件產品各三明細,正常提交應得到十主檔、三十明細。把其中一件完整重送五次,兩個表的列數仍不變。再送一件含錯誤明細的產品,正式表不新增半件,失敗紀錄能指出事件與欄位。
資料庫提交前斷線與提交後確認遺失,來源看起來都可能只是逾時。接收端依同一事件鍵分辨未接受或已接受,來源不要改鍵猜測重送。交易能保證資料庫內的整體變更,不會自動保證閘道磁碟、PLC記憶體與外部服務都同時提交。
確認必須對應到正確的責任層
閘道回覆PLC「已保存」時,必須定義是只進入記憶體,還是已到可承受指定故障的持久儲存。若PLC收到回覆就清除來源緩衝,而閘道隨後掉電丟掉記憶體內容,資料仍會遺失。把確認語意寫進介面,不能只看回覆文字叫成功。
資料庫回覆已提交後,閘道才能按約定移除待送項目。刪除過早造成漏資料,刪除較晚則可能重送,後者可由冪等接收處理。持久佇列本身的新增、狀態更新與刪除也要能從中斷恢復,不能只在正常關機時寫檔。
批次補送要決定整批交易或逐事件交易。整批中一件錯誤若會使所有事件回復,就要能分離壞件;逐事件提交則回覆每個事件的結果,不能只有「十件中有錯」而讓來源不知道九件是否已完成。
確認水位只能推進到連續完成的位置。序號一至一百中九十九失敗、一百已成功時,若回覆完成到一百,來源可能刪掉尚未接受的九十九。可以保留缺口清單或逐事件確認,但不能用最大已見序號代替所有前序已完成。
補送與即時資料共用資源時,限制補送速度並觀察待送年齡。假設來源每秒新增二十件,資料庫每秒可接受五十件,理想情況下每秒淨清三十件;九千件積壓約需三百秒,也就是五分鐘。這只是假設容量,仍要量測實際明細、索引與交易成本。
讓失敗佇列成為可處理的工作清單
區分暫時錯誤與永久性資料問題。連線中斷、暫時忙碌可依策略延後重試;欄位型別錯、缺必要識別或內容衝突通常需要修正。設定有上限的重試策略與退避,避免一筆格式錯誤持續占用整條補送通道。
失敗佇列保留原始事件、來源鍵、首次及最近失敗時間、嘗試次數、錯誤分類與處理狀態。修正後重送仍沿用可追溯的事件關係;若內容有變,記錄修訂依據,不能把失敗資料改得面目全非卻仍聲稱是原封不動重試。
失敗時先核對來源產生數、閘道待送數、資料庫唯一接受數及失敗數的守恆關係,再查個別事件。沒有計入尚在傳送中的資料或重複嘗試,總數看起來就會不合;先固定同一截止點,避免比較不同時刻的計數。
驗收分別模擬保存前、持久保存後、資料庫提交前與提交後中斷,並測佇列容量用盡。容量滿時必須明確告警或依已約定政策處理,不可靜默覆蓋尚未送出的事件。這些測試先在隔離環境進行。
練習與常見問題
練習:持久佇列原有一千件,期間新生一百件,資料庫接受九百件,永久失敗隔離十件,尚待送一百九十件,四者可核對為一千加一百等於九百加十加一百九十。重送嘗試次數不直接加入事件總量。
問:資料庫有交易就不需要閘道保存嗎?答:來源斷線期間尚未到資料庫的事件仍需要保存。
問:某筆永遠失敗可以一直重試嗎?答:先分類並隔離可診斷的資料問題,避免阻塞其他事件。
問:收到最大序號就代表前面齊全嗎?答:不代表,要查連續確認範圍與缺口。
問:補送完成就證明沒有遺失嗎?答:還要比對來源事件範圍、唯一接受數、失敗清單與中斷測試證據。
參考:PostgreSQL 18 Transactions:資料庫內的整體提交與回復。
參考:PostgreSQL 18 INSERT:唯一衝突處理的實際能力。