多層分佈式設計模式

  原來就想寫一些關於分佈式的設計。正好目前開發的GIX4項目中,需要對客戶端的許多操作進行記錄。這個功能的設計或多或少能說明,一般情況下,多層的分佈式系統應該如何設計。現在我就對這個功能進行描述。

 

功能描述

    GIX4項目中有個審覈日誌記錄功能,它需要以下功能:

    需要把客戶的所有操作記錄下來,以便支持審計。如,當用戶進行:登錄、打開模塊、查看數據、點擊按鈕……等操作時,把相關的數據全部在服務器的數據庫中記錄下來,這些數據有:操作類型、操作時間、操作內容、操作者、客戶端機器名等。

    在服務端對某些特定的事件進行記錄,如:計算出錯。

 

設計目標

    這個模塊需要支持以下目標:

    *爲客戶端代碼、服務器端代碼都提供簡單統一的接口。

    *需要異步記錄。

    *如果擴展爲多級物理層時,也需要使用相同的接口。

 

設計

    先把設計完成的圖貼出來,然後再逐一描述:

image

圖1 全部類圖

通用部分

    首先,API設計之初,先根據需求,定出使用的接口。它們包含兩個類:一個是貧血數據類AuditLogItem,一個是對AuditLogItem進行操作的靜態類AuditLogService。AuditLogService暫時公佈兩個靜態方法,一個記錄日誌方法Log(),另一個方法是異步記錄LogAsync()。如下:

image

    由於各物理層都使用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);
    }
}

 

整個過程

    整個過程其實很簡單,一圖勝千言:

image

 

後記

    其實本次設計過程的思路很簡單:分析要提供的API(場景驅動)、分析分佈式實現的差異、編寫基礎部分、編碼與重構。

    其實熟悉CSLA的人應該知道,它裏面的通信機制也是採用了類似的方式實現的。所以這應該算是一種分佈式的設計模式吧。 :)