← 所有文章

FIELD NOTES / PLC 程式與控制

統計重置如何保存前段結算

PLC 程式與控制作者:站長預估 6 分鐘閱讀

按batch或segment切段,以一次受控snapshot與新段初始化保存前段結算,示範10、20、30與5、15案例及失敗恢復、容量與冪等策略。

本文目錄

把重置定義成切段而不是刪除

統計重置若只是把累計器寫成零,前一段的產量、時間或能耗就可能失去結算依據。較清楚的模型是按batch或segment切段:封存目前段的結算快照,再初始化新段。重置是一次受控的邊界交易,不是刪除歷史資料,也不是讓畫面瞬間把所有欄位改成零。

每段至少有batch_id、segment_id、開始與結束邊界、累計值、品質狀態和保存狀態。新資料只能歸屬一個segment。請求要有request_id,重複提交同一請求時回傳原結果;同一request_id若內容不同,應拒絕並記錄衝突。

快照與新段初始化必須有受控順序和一致狀態。可以由中央交易、鎖或單一寫入流程保證;不能先清零再想辦法找回舊段。若系統無法提供真正原子交易,就要明確設計pending、重試、恢復和人工補帳狀態,不能假裝已經exactly once。

邊界規則先寫成一句可測試的契約:本篇以已處理序號3為舊段最後一筆,序號4起歸新段。每筆事件只歸屬一段;不重不漏是必須驗收的設計目標,並非宣稱現場已達成的保證。

用數字走過一次切段

舊段收到三筆增量10、20、30,結算後count=3、total=60、average=20。這三筆封存為舊段快照;重置成功後建立新段,計數器和總和從零開始。新段再收到5、15,得到count=2、total=20、average=10。舊段的60與新段的20都保留,不能只留下最後的20。

若重置請求的邊界序號位於30之後,10、20、30全歸舊段,新段只接收後續5、15。若邊界事件尚未決定歸屬,先把請求留在pending,不要清零。驗收時除了總數,也要檢查事件序號集合沒有重複和缺口。

正常結果可列old_segment count=3,total=60,average=20,status=archived,以及new_segment count=2,total=20,average=10,status=active。失敗結果則保留active舊段與pending snapshot,控制統計不應因存檔失敗而消失。顯示零只能代表新段尚未有資料,不代表歷史不存在。

平均值要以保存的count與total重新計算,並記錄小數規則與單位。若有最大值、最小值、良率或時間加權平均,也要在快照契約中列出各自的聚合方式;不能只保存一個總數再宣稱所有統計都可恢復。

處理保存失敗 容量滿與重啟

存檔失敗時,重置交易不能把前段標成已封存。保留舊段累計與一份待存snapshot,記錄失敗原因、重試次數和邊界序號;待保存成功後才提交新段。若設備必須繼續收集,要有明確的暫存容量和滿載政策,例如停止接受重置、告警並保留統計,不能默默覆蓋最早待存快照。

本例選定的等待政策是凍結序號3以前的舊段快照,序號4以後先進有界待處理佇列,不繼續加到舊段,也不提早發布新段統計。確認封存成功後,建立新段並依序處理佇列;佇列容量滿時回報無法無損接收,依專案策略處理。重啟仍要保證事件可重放或暫存已持久化。

容量滿的政策要提前決定:拒絕新切段、進入安全停機、轉移到已驗證的外部儲存,或經人工批准淘汰已歸檔資料。每種政策都要報出狀態和可恢復性。本文不替特定設備選擇停機或繼續生產,因為那屬製程與安全規格。

重啟恢復時,先讀取最後一致的active段、已封存段和pending snapshot,再以request_id與邊界序號去重。若發現快照已存但新段初始化未完成,依交易狀態補做或回滾到可證明狀態;不能看到計數器是零就直接開始,否則可能丟掉舊段。

介面須在第一次按下時建立request_id,處理未完成期間的再次按下沿用它或忽略;雙擊不會天然具有同一識別。通訊重送沿用原request_id。第一次成功後,第二次只回傳已完成結果,不再切出空的新段。若第二次帶不同batch、邊界或payload,回報IdempotencyConflict並保留原請求,供人工排查。

驗收切段與適用限制

離線驗收至少測:無資料重置、10/20/30後重置、重置邊界事件、存檔失敗、待存容量將滿、容量已滿、重啟恢復、同request_id重送、不同request_id重複邊界,以及部分寫入後恢復。每列核對舊段、新段、事件序號、保存狀態和總和。

exactly once是整個事件與保存流程的性質,不是把某個計數器清零就能取得的保證。若輸入事件本身沒有唯一序號,無法可靠去重;若快照和事件流沒有一致的提交點,也不能宣稱不重不漏。必要時增加中央日誌、交易識別與人工對帳。

快照資料要包含計算所用的規則版本、單位與四捨五入策略,否則重啟後雖能讀回總和,卻可能算出不同平均。封存檔也應有校驗摘要與保存時間,讓後續對帳能分辨資料未變與檔案根本沒有寫成功。

對帳畫面應同時顯示段識別、邊界序號、封存狀態和目前累計,讓人員分辨新段尚未有資料與舊段尚未保存。若發現缺口,先凍結再次重置,保存原始事件與錯誤紀錄,再由核准人員決定補帳或恢復。

保存成功還要確認檔案可讀與校驗一致,不能只看寫入呼叫回傳成功。若驗證失敗,維持pending並告警,讓重試不會覆蓋唯一的前段資料。

快照檔名應包含batch、segment與邊界識別,避免不同段落互相覆蓋;查詢歷史時也要依識別排序,不依檔案到達時間推測先後順序紀錄。

若統計來源同時有事件流和現場累計器,先決定哪一個是權威,再用另一個做交叉檢查。兩者不一致時建立reconcile狀態,不要在重置邊界自動挑較大的數字,避免把重複計數當成真實產量。

本文的count=3、total=60、average=20與count=2、total=20、average=10是數學案例。實際Q系列PLC的保持記憶體、通訊緩衝、檔案儲存、掃描時序和掉電行為必須查目標手冊與現場設計。

排查時先找最後一個已知邊界,對照快照、事件序號和request_id,再查清零或初始化是否先於存檔。若總和正確但平均錯,查聚合重算;若歷史少一段,查容量與提交狀態;若重送多一段,查冪等索引,而不是直接手動改顯示數字。

空的新段只有count=0與total=0;平均、最小、最大尚未定義,不顯示為有效零。若不同request_id指向已完成的同一邊界,應回覆邊界已處理,避免另一個識別碼繞過去重而再切出空段。

常見問題

問:重置就是把count和total寫零嗎?答:本篇把它定義成先保存前段結算、再建立新段,歷史不能因重置刪除。

問:10、20、30後重置的結果怎麼算?答:舊段是count=3、total=60、average=20;新段收到5、15後是count=2、total=20、average=10。

問:存檔失敗可以照常清零嗎?答:不應直接清零;保留舊段和pending snapshot,依容量與製程政策處理,避免歷史遺失。

問:雙擊重置會不會多切一段?答:相同request_id必須冪等,第二次回傳原結果;內容不同則報衝突。

參考:Apache Kafka官方文件的exactly-once語義說明,可作為事件處理與提交邊界的參考;本文切段模型不代表PLC原生具備該語義。

參考:PostgreSQL官方文件的交易與故障恢復說明,可作為受控snapshot、提交與重啟恢復的資料設計參考;實際儲存層需另行驗證。

延伸閱讀