持久化策略探索)
EAP狀態(tài)持久化策略探索在之前的優(yōu)化中我們將EAP啟動狀態(tài)section/zone是否已啟動從Dictionarystring, bool升級為線程安全的EapSectionStateManager基于HashSetstring lock。當前實現(xiàn)是純內(nèi)存in-memory程序重啟后所有狀態(tài)重置為“未啟動”。現(xiàn)在我們系統(tǒng)性地探索持久化Persistence策略目標是讓EAP狀態(tài)在應用崩潰、重啟、服務器重啟等場景下可恢復同時兼顧工業(yè)控制系統(tǒng)的安全性、實時性、簡潔性。1. 為什么需要持久化業(yè)務場景分析當前痛點如果EAP主機Host異常重啟正在“已啟動”狀態(tài)的section會被重置導致下次S2F41 START消息可能重復觸發(fā)RemoteCallStartFlow或丟失流程狀態(tài)。GEM/SECS標準參考SEMI E30GEM明確要求Control StateOnline/Offline/Remote/Local等關鍵狀態(tài)必須保存在非易失性存儲non-volatile storage中重啟后狀態(tài)應保持一致。EAP特有場景您的EapSectionStateManager是自定義的“遠程啟動標記”并非標準GEM狀態(tài)。因此持久化不是強制但能顯著提升系統(tǒng)魯棒性尤其在24×7產(chǎn)線環(huán)境中。潛在風險持久化后需考慮“狀態(tài)過期”e.g. 產(chǎn)線重啟后是否強制清零、數(shù)據(jù)一致性、文件/DB損壞恢復。結(jié)論推薦輕量級持久化而不是完全不持久化。優(yōu)先確保“安全重啟”。2. 常見持久化策略對比適合工業(yè)EAP/.NET環(huán)境策略實現(xiàn)復雜度性能/實時性可靠性適用場景優(yōu)缺點總結(jié)1. 純內(nèi)存當前★☆☆☆☆極高低重啟丟失測試/簡單場景簡單但不滿足產(chǎn)線高可用要求2. JSON文件持久化最推薦★★☆☆☆高1ms中高原子寫備份多數(shù)EAP系統(tǒng)10~100個section輕量、無依賴、易部署。工業(yè)中最常用3. SQLite單文件數(shù)據(jù)庫★★★☆☆高高事務ACID需要審計/歷史記錄支持并發(fā)、查詢靈活。體積稍大4. 企業(yè)級數(shù)據(jù)庫SQL Server/PostgreSQL★★★★☆中極高已集成MES/CIM的大廠強大但運維成本高5. Event Sourcing事件溯源★★★★★中極高需要完整審計軌跡高級方案可回放任意時刻狀態(tài)6. Redis/分布式緩存★★★☆☆極高高需集群多主機/分布式EAP適合云化/多實例成本較高工業(yè)控制最佳實踐基于SECS/GEM社區(qū)經(jīng)驗優(yōu)先JSON文件無需額外服務部署簡單符合半導體EAP“輕量化”原則。必須原子寫寫臨時文件 → 重命名防止半途崩潰導致文件損壞。啟動時加載 校驗損壞時自動回退為空狀態(tài)安全優(yōu)先。周期性或變更時 程序退出時保存。3. 推薦方案JSON文件持久化完整實現(xiàn)3.1 核心設計文件路徑AppDomain.CurrentDomain.BaseDirectory Config\\EapSectionState.json或固定路徑便于備份。序列化使用System.Text.Json.NET 6內(nèi)置高性能。擴展性未來可存儲更多信息如StartedAt時間戳、啟動者。3.2 優(yōu)化后的EapSectionStateManager完整代碼usingSystem.Text.Json;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Threading;publicstaticclassEapSectionStateManager{privatestaticreadonlyHashSetstring_startedSectionsnewHashSetstring(StringComparer.OrdinalIgnoreCase);privatestaticreadonlyobject_locknewobject();privatestaticreadonlystring_stateFilePathPath.Combine(AppDomain.CurrentDomain.BaseDirectory,Config,EapSectionState.json);// 靜態(tài)構造函數(shù)程序啟動時自動加載staticEapSectionStateManager(){LoadFromFile();}privatestaticvoidLoadFromFile(){try{if(!File.Exists(_stateFilePath))return;stringjsonFile.ReadAllText(_stateFilePath);varlistJsonSerializer.DeserializeListstring(json);if(list!null){lock(_lock){_startedSections.Clear();foreach(varsectioninlist)_startedSections.Add(section);}m_Log.Info($EAP狀態(tài)已從文件恢復共{list.Count}個section);}}catch(Exceptionex){m_Log.Error($EAP狀態(tài)文件加載失敗使用空狀態(tài):{ex.Message},ex);// 安全回退不拋異常}}privatestaticvoidSaveToFile(){try{Directory.CreateDirectory(Path.GetDirectoryName(_stateFilePath)!);Liststringlist;lock(_lock){listnewListstring(_startedSections);}stringjsonJsonSerializer.Serialize(list,newJsonSerializerOptions{WriteIndentedtrue});// 原子寫先寫臨時文件stringtempFile_stateFilePath.tmp;File.WriteAllText(tempFile,json);File.Move(tempFile,_stateFilePath,overwrite:true);m_Log.Debug($EAP狀態(tài)已持久化到文件 ({list.Count}個section));}catch(Exceptionex){m_Log.Error($EAP狀態(tài)保存失敗:{ex.Message},ex);}}publicstaticvoidMarkAsStarted(stringsectionId){if(string.IsNullOrWhiteSpace(sectionId))return;lock(_lock){if(_startedSections.Add(sectionId)){m_Log.Info($EAP 啟動標記成功 section:{sectionId});SaveToFile();// 立即持久化}else{m_Log.Warn($EAP 重復啟動嘗試 section:{sectionId});}}}publicstaticvoidMarkAsEnded(stringsectionId){if(string.IsNullOrWhiteSpace(sectionId))return;lock(_lock){if(_startedSections.Remove(sectionId)){m_Log.Info($EAP 結(jié)束標記成功 section:{sectionId});SaveToFile();// 立即持久化}}}publicstaticboolIsStarted(stringsectionId){if(string.IsNullOrWhiteSpace(sectionId))returnfalse;lock(_lock){return_startedSections.Contains(sectionId);}}/// summary/// 系統(tǒng)初始化/產(chǎn)線重啟時強制清零可選調(diào)用/// /summarypublicstaticvoidClearAll(boolsaveImmediatelytrue){lock(_lock){_startedSections.Clear();if(saveImmediately)SaveToFile();}m_Log.Warn(EAP所有section狀態(tài)已被清零);}}3.3 使用方式無需改動原有START/Ending邏輯啟動時自動加載。每次MarkAsStarted/MarkAsEnded自動保存。程序退出時AppDomain.ProcessExit 或 手動調(diào)用可額外調(diào)用一次SaveToFile()。4. 進階建議定時備份每天備份一次JSON文件到Backup\目錄。版本控制JSON中增加Version: 1字段未來升級結(jié)構時自動遷移。SQLite替代方案如果section數(shù)量1000或需要查詢歷史使用Microsoft.Data.Sqlite單文件數(shù)據(jù)庫建表EapStates (SectionId TEXT PRIMARY KEY, IsStarted INTEGER, UpdatedAt DATETIME)。優(yōu)點事務保證一致性。監(jiān)控與告警文件保存失敗時觸發(fā)SystemNotifEvent。安全考慮產(chǎn)線重啟時是否調(diào)用ClearAll()建議增加配置開關RuntimeConfiguration.ResetEapStateOnStartup。5. 總結(jié)與實施路線立即實施采用JSON文件方案最優(yōu)性價比。測試驗證模擬程序崩潰、重啟確認狀態(tài)是否正確恢復。監(jiān)控指標新增日志“EAP狀態(tài)恢復成功/失敗”便于運維。未來擴展若系統(tǒng)演進到分布式可無縫切換到Redis 事件溯源。這種持久化策略既符合SECS/GEM非易失性要求又保持了代碼簡潔性和工業(yè)級可靠性。如果您需要SQLite完整實現(xiàn)、配置化路徑、或結(jié)合現(xiàn)有CIM/MES數(shù)據(jù)庫的方案請?zhí)峁└嘞到y(tǒng)架構細節(jié)我可以繼續(xù)細化代碼。