原來就想寫一些關於分佈式的設計。正好目前開發的GIX4項目中,需要對客戶端的許多操作進行記錄。這個功能的設計或多或少能說明,一般情況下,多層的分佈式系統應該如何設計。現在我就對這個功能進行描述。
功能描述
GIX4項目中有個審覈日誌記錄功能,它需要以下功能:
需要把客戶的所有操作記錄下來,以便支持審計。如,當用戶進行:登錄、打開模塊、查看數據、點擊按鈕……等操作時,把相關的數據全部在服務器的數據庫中記錄下來,這些數據有:操作類型、操作時間、操作內容、操作者、客戶端機器名等。
在服務端對某些特定的事件進行記錄,如:計算出錯。
設計目標
這個模塊需要支持以下目標:
*爲客戶端代碼、服務器端代碼都提供簡單統一的接口。
*需要異步記錄。
*如果擴展爲多級物理層時,也需要使用相同的接口。
設計
先把設計完成的圖貼出來,然後再逐一描述:
圖1 全部類圖
通用部分
首先,API設計之初,先根據需求,定出使用的接口。它們包含兩個類:一個是貧血數據類AuditLogItem,一個是對AuditLogItem進行操作的靜態類AuditLogService。AuditLogService暫時公佈兩個靜態方法,一個記錄日誌方法Log(),另一個方法是異步記錄LogAsync()。如下:
由於各物理層都使用AuditLogService的方法,而實現不同。這裏把使用了Provider模式,提取接口IAuditLogProvider,這裏就不再需要異步方法了:
/// <summary> /// 審計功能提供程序 /// </summary> public interface IAuditLogProvider { /// <summary> /// 記錄指定的日誌 /// </summary> /// <param name="log"></param> void Log(AuditLogItem log); }
除了最終與數據庫通信的服務器外,其它節點都默認使用ClientAuditLogProvider作爲提供程序。此提供程序使用了ICommunication,而ICommunication則是負責向「下一節點」通信並提交日誌記錄功能。
GIX4實現部分
這部分主要是兩個類:ServerAuditLogProvider 和 CSLACommandCommunication。
ServerAuditLogProvider 使用CSLA的類庫把AuditLogItem轉換爲相應的數據庫模型存入數據庫中:
public class ServerAuditLogProvider : IAuditLogProvider { public void Log(AuditLogItem log) { var dbItem = AuditItem.New(); dbItem.Title = log.Title; dbItem.Content = log.Content; dbItem.User = log.User; dbItem.MachineName = log.MachineName; dbItem.Type = log.Type; dbItem.LogTime = log.LogTime; dbItem.Save(); } }
CSLACommandCommunication 則是使用WCF和CSLA命令模式作爲基礎框架,讓當前節點把請求發送給下一節點,下一節點接到請求後,使用本節點的提供程序Provider來處理請求。其中重要的代碼在內部類AuditServerCommand中,如下:
[Serializable] public class AuditServerCommand : Csla.CommandBase { private AuditLogItem _logItem; public AuditServerCommand(AuditLogItem logItem) { if (logItem == null) throw new ArgumentNullException("logItem"); this._logItem = logItem; } protected override void DataPortal_Execute() { //server log AuditLogService.Log(this._logItem); } }
整個過程
整個過程其實很簡單,一圖勝千言:
後記
其實本次設計過程的思路很簡單:分析要提供的API(場景驅動)、分析分佈式實現的差異、編寫基礎部分、編碼與重構。
其實熟悉CSLA的人應該知道,它裏面的通信機制也是採用了類似的方式實現的。所以這應該算是一種分佈式的設計模式吧。 :)