Apworks框架中各種倉儲實現的性能基准測試與結果對比


周末抽空簡單地對Apworks框架所支持的三種倉儲實現:Entity Framework、NHibernate以及MongoDB進行了性能基准測試,並對其結果進行對比。從對比的結果來看,MongoDB倉儲的性能要遠勝於其它兩者。基准測試采用的是我在兩年前開發的一個基於Visual Studio Unit Test Framework的基准測試程序(名為:Visual Benchmark),該程序可以設定基准測試引擎,並對測試結果進行圖形化呈現。在本文末尾會簡要地對此軟件進行介紹,有興趣的朋友不妨了解一下。

單體測試的設計

由於Visual Benchmark是基於Visual Studio Unit Test Framework的單體測試用例的,因此,我們只需要在Visual Studio中開發有待測試的單體測試程序即可。在開發單體測試程序之前,首先讓我們了解一下Visual Benchmark所支持的“迭代基准測試”模式。所謂“迭代基准測試”,意思就是Visual Benchmark會循環地調用單體測試方法並在每次調用結束時,統計當前“代”中所消耗的CPU周期或者時間;當Visual Benchmark完成整個測試之后,會將各代的統計結果組織並顯示出來。在這個過程中,單體測試方法可以通過Visual Benchmark所提供的基准測試參數來獲得當前所處的“代”數(也就是循環因子的值),然后就可以基於這個“代”數對測試數據進行模擬,以反映出隨着測試數據的增長,單體測試方法的執行效率。

舉例來說,在測試三種不同的倉儲對於聚合的保存執行效率時,我首先在Visual Studio中新建了一個Unit Test類,並在類中定義了兩個成員變量:

[TestClass]
public class InsertAggregateRootsTest
{
    private int thisIteration;
    private IEnumerable<SalesOrder> mockSalesOrders;
    // 其它部分暫時省略
}

 

第一個成員變量thisIteration用來保存從Visual Benchmark傳入的“代”數;而第二個成員變量mockSalesOrders則是保存了一組即將通過倉儲插入的聚合模擬數據。

接下來,我在這個測試類中加入了Test Initialize的方法,以便在每次測試方法被調用前,執行一些數據初始化的操作。在這個方法中,會對以上兩個成員變量初始化,同時清空后台數據庫,為執行測試做准備。

[TestInitialize()]
public void MyTestInitialize()
{
    thisIteration = (int)BenchmarkRuntimeArgs.Instance.ThisIteration;
    mockSalesOrders = Helper.MockSalesOrders(thisIteration);
    Helper.ClearSQLServerTables();
    Helper.ClearMongoDB();
}

 

在上面的方法中,首先使用BenchmarkRuntimeArgs.Instance.ThisIteration對thisIteration進行初始化,以便獲得當前測試的“代”。BenchmarkRuntimeArgs是一個跨應用程序域的單件(Singleton),在每次執行Benchmark之前都會被初始化。然后根據獲得的“代”數,創建聚合模擬數據。此處mockSalesOrders中所包含的數據量會隨着“代”數的增長而增加,以反映隨着數據量的增長,被測函數的性能趨勢。最后,使用Helper類清空后台數據庫。

由於倉儲的實現是基於不同的應用框架,因此,在所有測試啟動前,需要對這些框架進行初始化。有寫過單體測試的朋友都知道,這部分邏輯應該寫在Class Initialize的方法中:

[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
    Database.SetInitializer<EntityFrameworkDbContext>(new 
        DropCreateDatabaseIfModelChanges<EntityFrameworkDbContext>());
    MongoDBRepositoryContext.RegisterConventions();
    if (!BsonClassMap.IsClassMapRegistered(typeof(SalesLine)))
    {
        BsonClassMap.RegisterClassMap<SalesLine>(p =>
        {
            p.AutoMap();
            p.UnmapProperty<SalesOrder>(q => q.SalesOrder);
        });
    }
}

 

在這里並沒有使用代碼的方式對NHibernate框架進行初始化,因為NHibernate的初始化過程是由Apworks中的NHibernateApplicationConfiguration類型完成的,這個類型依賴應用程序的app/web.config文件。所以我們需要在單體測試項目中添加app.config以及相關的配置節點。篇幅原因,這里就不貼app.config的代碼了,文章末尾我會給出源代碼。Visual Benchmark支持在“客戶應用程序域”(Client AppDomain)中裝載app/web.config文件。

現在,可以開始寫測試方法了,以下是基於三種不同倉儲實現的測試方法。從各方法中我們可以看到,除了所創建的IRepositoryContext、IRepository的具體實現不同之外,其它的操作邏輯完全相同:即通過倉儲對聚合進行保存:

[TestMethod]
public void EntityFramework()
{
    using (IRepositoryContext context = new EntityFrameworkRepositoryContext(new EntityFrameworkDbContext()))
    {
        IRepository<SalesOrder> salesOrderRepository = new EntityFrameworkRepository<SalesOrder>(context);
        foreach (var salesOrder in mockSalesOrders)
            salesOrderRepository.Add(salesOrder);
        context.Commit();
    }
}

[TestMethod]
public void NHibernate()
{
    using (IRepositoryContext context = new NHibernateContext(new NHibernateApplicationConfiguration()))
    {
        IRepository<SalesOrder> salesOrderRepository = new NHibernateRepository<SalesOrder>(context);
        foreach (var salesOrder in mockSalesOrders)
            salesOrderRepository.Add(salesOrder);
        context.Commit();
    }
}

[TestMethod]
public void MongoDB()
{
    using (IRepositoryContext context = new MongoDBRepositoryContext(new MongoDBRepositoryContextSettings()))
    {
        IRepository<SalesOrder> salesOrderRepository = new MongoDBRepository<SalesOrder>(context);
        foreach (var salesOrder in mockSalesOrders)
            salesOrderRepository.Add(salesOrder);
        context.Commit();
    }
}

 

執行測試

首先,我們在Visual Studio中測試這三個方法,以確保每個方法都能夠正確完成。在啟動測試之前,先回到上面的MyTestInitialize方法,將thisIteration設置為一個固定的整數值,比如20,以便測試能夠正常啟動。在完成三個方法的測試之后,我們可以通過Test Results窗口看到測試結果。

image

 

打開Visual Benchmark,新建一個Session,在“打開”對話框中,選擇已經編譯好的DLL文件,此時Visual Benchmark會將其中包含的所有的測試類和測試方法加載到左邊的樹形結構中。在樹形結構中,選中需要測試的方法,然后單擊“開始”按鈕,Visual Benchmark便會針對所選的測試方法進行基准測試。最后,會根據不同的測試引擎的設計,將結果顯示出來。

image

 

測試結果

Visual Benchmark能夠根據設置,采用一些減噪手段以盡量保證測試結果的真實性。通過所測結果不難看出,在我所測試的三個場景中,基於MongoDB實現的倉儲,性能要優於其它兩者。而NHibernate倉儲又要好於Entity Framework倉儲。

測試環境

以下是執行測試的環境配置:

  • CPU:Intel Core i5-540M Cores: 2 Logical: 4
  • Chipset:Intel QM57 (IbexPeak-M DO)
  • Memory:Hynix 666.7MHz (PC3-10600) 2048MB x1, Kingston 666.7MHz (PC3-10600) 4096MB x1. Totally 6144MB
  • OS:Microsoft Windows 7 Enterprise (x64) Build 7601

場景一:聚合保存

Insert

注:上圖中X軸表示的是“代”數,亦即模擬的聚合數量;Y軸表示執行時間(毫秒數)。下同。

場景二:聚合查詢

Retrieve

注:在此場景中,EntityFramework支線所表示的是使用Eager Loading將SalesOrder及其下所有Sales Lines實體讀出所開銷的時間;而EntityFramework_NoEagerLoad支線所表示的是僅讀出SalesOrder(不包括其下所有Sales Lines)所開銷的時間。

場景三:查詢所有並刪除

FindAndDelete

 

關於Visual Benchmark

Visual Benchmark是我在2010年開發的一款基於Visual Studio單體測試框架的性能基准測試程序,從整體上看,Visual Benchmark具有如下架構設計:

image

首先,Visual Benchmark和被測試的程序集都是基於Microsoft .NET Framework的,在Visual Benchmark中,基准測試的執行是以Session為單位的。Engine Management System為Visual Benchmark提供了安全的、可擴展的基准測試引擎管理系統,因此,通過這套管理系統,用戶可以選用各種不同的引擎進行測試,開發人員也可以根據自己的實際需求對引擎進行二次開發與定制,並應用到Visual Benchmark系統中。

其次,當Session被打開時,它會通過Remote Proxy將被測試的程序集裝載到客戶應用程序域(Client AppDomain)中。這樣做的理由是:1、能夠在完成測試后,以AppDomain.Unload的方式卸載被測試程序集;2、能夠在裝載程序集時,同時將app/web.config和resource都裝載到Client AppDomain中,以此模擬真實的執行環境。

功能技術特點

Visual Benchmark具有如下功能技術特點:

  1. 可定制的基准測量標尺:開發人員可以自己開發基准測試的測量標尺。目前僅支持兩種:StopwatchTickRuler和StopwatchMillisecondsRuler。上文的測試采用的是StopwatchMillisecondsRuler
  2. 可定制的測試引擎:開發人員可以根據需求定制開發測試引擎。框架提供了完整的引擎定制功能,這包括:引擎的元數據(例如名稱、作者、描述等)、版本、配置界面、結果顯示界面以及HTML文檔。目前支持Iterated Throughput、Simple、Simple Iteration以及Throughput四種引擎。上文的測試采用了Simple Iteration引擎
  3. 減噪選項:使用減噪選項以獲得更真實的測試數據。Visual Benchmark提供兩個減噪選項:在每次執行測試之前強制垃圾回收、丟棄第一次的測試結果。測試引擎也會根據情況提供獲取平均執行時間的選項
  4. 在客戶應用程序域(Client AppDomain)中執行基准測試:能夠對單體測試環境進行模擬,被測方法能夠正常地訪問配置文件和資源文件
  5. 跨AppDomain的單件(Singleton)實現:能夠方便地在單體測試方法中讀取Visual Benchmark的相關參數信息
  6. 多線程執行:用戶可以隨時停止Benchmark的執行

界面截圖

基於兩種不同引擎的執行結果顯示

image

 

測試引擎的配置界面與文檔界面

image

 

Session信息與客戶應用程序域(Client AppDomain)信息

image

 

總結

本文對Apworks框架中所支持的三種倉儲實現進行了性能上的基准測試,並得出了測試結果。在最開始的時候,我是打算結合Visual Studio的測試框架來完成這些工作的,但后來發現Visual Studio的測試框架所提供的功能並不能達到我的需求,之前也采用了Visual Studio的Load Test來做壓力測試,但是效果並不算太理想。在下才疏學淺,並沒有弄通Visual Studio提供的強大測試功能,所以也只能借用我之前寫的Visual Benchmark程序了。如果有讀者朋友知道如何在Visual Studio中完成類似的測試工作,還煩請告知在下,我會虛心向您學習。

下一步,我將對Apworks框架的線程安全性做一些評估,等到有了滿意的結果,我也會將相關經驗分享出來。

相關下載

【單擊此處】下載本文的單體測試解決方案及源代碼

【單擊此處】下載Visual Benchmark的綠色免安裝程序

【單擊此處】下載Visual Benchmark的源程序代碼(請使用Visual Studio 2010打開,沒有使用任何第三方控件,所以無需安裝其它組件)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM