[2014-09-18]Entity Framework 6 預熱、啓動優化


很久沒寫博客了,終於憋出了一個大招,如今總結下。
雖然文章題目是針對EF的,但涉及的內容不只僅是EF。html

場景介紹

目前在作的一個項目,行業門戶,項目部分站點按域名劃分以下:程序員

  1. user.xxx.com:用戶登錄註冊
  2. owner.xxx.com:我的用戶後臺
  3. company.xxx.com:企業後臺
  4. manage.xxx.com:網站管理

其中user.xxx.com爲我的用戶及企業用戶登錄入口,
manage.xxx.com/login爲網站管理後臺登錄入口。數據庫

四個項目都是mvc4+ef6+autofac+automapper。服務器

補充信息:架構

  • .net framework 4.0
  • asp.net mvc4
  • Entity Framework 6
  • 服務器:阿里雲ECS win2008 r2 雙核 4G內存 IIS7.5

因而,用過ef的都知道,ef首次訪問數據庫的時候,耗費的時間很長。
若是四個項目都是首次訪問,那麼我的用戶首次登錄的時候,會經歷兩次ef首次訪問(user站和owner站)。mvc

暫不論項目自己是否有更好的架構方案,或者配合集羣加一層進行可用性緩衝等。
本文的目標就是要儘量的下降用戶在上述狀況下遇到的等待時間。app

如下全部測試前提:asp.net

  1. 站點代碼有添加優化手段的狀況下,回收程序池,並重啓站點;
  2. 站點代碼未變化的狀況下,回收程序池,並重啓站點。

初始狀態

貼圖不太方便,只給蒐集的數據做爲展現
無任何優化措施的初始狀態,更新各站點後:less

  1. 首次打開user:5.47s (注意,此時未使用到EF,僅一個空的登錄表單);
  2. 登錄owner後臺:user處理登錄過程(9.37s,涉及用EF訪問數據庫),owner響應(14.54s,首次訪問站點耗時+EF訪問數據庫耗時,僅涉及用戶驗證,後臺首頁爲空);
  3. 註銷owner後臺,回到user,登錄company後臺,company後臺響應(15.19s,首次訪問站點耗時+EF訪問數據庫耗時,僅涉及企業驗證,後臺首頁爲空);
  4. 註銷company後臺,打開manage,manage響應並跳轉到登錄頁(2.96s,首次訪問);
  5. 登錄manage,耗時(8.23s,處理登錄過程涉及EF)

簡單概括下就是:ide

1. owner登錄體驗到的延遲共計(5.47s + 9.37s + 14.54s)
2. company登錄體驗到的延遲共計(15.19s,要感謝登錄owner的時候已經"激活"了user以及user的EF)
3. manage登錄體驗到的延遲共計(2.96s + 8.23s)

第一個問題,站點首次訪問的耗時大約5秒

這時候還沒EF什麼事,只是一個空的登錄表單

首次訪問,通常分兩塊:

  1. 站點更新後從新加載程序文件;
  2. iis程序池回收後也會須要從新加載(程序池默認是按需觸發運行的,沒人訪問它就不啓動了)

不少.net程序員會忽略這個問題。
(這真的是許多年的無奈經驗之談,大多會說,第一次訪問原本就會很慢。)
或者經過腳本定時訪問,以規避這個問題(不讓用戶遇到就好了)

這裏我倒想真的試試解決這個問題。

第一個問題的解決方案:Application Initialization

這是在iis8出來後纔有的,iis8內置的功能,而對於iis7.5也提供了一個擴展以支持這個功能。

Application Initialization Module for IIS 7.5

在頁面接近底部的地方,找到適合本身架構的安裝連接

  • x86 for Windows 7
  • x64 for Windows 7 or Windows Server 2008 R2

安裝這個iis模塊後,在iis界面中並無模塊圖標和配置界面,還須要安裝:

http://files.dotblogs.com.tw/jaigi/1306/2013619347830.zip

具體配置方法見:

讓IIS 7 如同IIS 8 第一次請求不變慢

若是僅配置程序池StartMode爲AlwaysRunning還不放心的話,
也能夠同時針對站點開啓preload和DoAppInitAfterRestart。

配置好後,測試了下,效果十分不錯。
回收程序池後首次打開各站點,延遲都很低。
其實這個模塊的思路和定時從外部觸發一個訪問是同樣的,只是,更好的地方在於,它自己在程序池回收重啓的時候就完成了這件事,而不會讓外部訪問有機會遇到首次訪問的狀況。

好了,完成這一步,解開了多年心結,省了5秒!

第二個優化點:EF Pre-Generated Mapping Views,大概節省4秒

這個優化點,通常仔細去EF的網站找找仍是容易找到的。
具體緣由原理不說了,這裏引用下博客園dudu大神的文章。

來,給Entity Framework熱熱身

搬一下代碼:

using (var dbcontext = new CnblogsDbContext())
{
var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;
var mappingCollection = (StorageMappingItemCollection)objectContext
.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
mappingCollection.GenerateViews(new List ());
}
//對程序中定義的全部DbContext逐一進行這個操做

我把它配置在每一個站點的Application_Start中了,個人項目使用了Autofac和Repository+UnitOfWork模式,沒有異常。

通過這一環節,又砍掉了剩下延遲中的50%時間,大概4秒多點。
概括下測試數據:(結合以上兩種優化後的成果)

1. owner登錄體驗到的延遲共計( <1s + 4.68 + 4.99)
2. company登錄體驗到的延遲共計(5.5,一樣要感謝登錄owner的時候已經"激活"了user的EF)
3. manage登錄體驗到的延遲共計(4.23)

第三個優化點(殺手鐗):使用Ngen建立EntityFramework的本地代碼鏡像(EF版本6以上)

EF的文檔要認真看啊!這個真是不當心挖出來的解決方案,主要是被我看到了一句話:

The .NET Framework supports the generation of native images for managed applications and libraries as a way to help applications start faster and also in some cases use less memory.

具體參考:Improving Startup Performance with NGen (EF6 Onwards)

Ngen使用方法:

//%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\ngen
安裝命令:[path to ngen]/ngen.exe install "[path to dll]"
查詢命令:[path to ngen]/ngen.exe display System.Xaml /verbose|findstr "EntityFramework"
卸載命令:[path to ngen]/ngen.exe uninstall "[DisplayName in System.Xaml]"

具體原理就不解釋了。這裏就記一下使用經驗:

  1. ngen 安裝後,不用試圖去尋找生成的.ni.dll文件在哪,這是系統自己起做用的,就至關於已經安裝好了
  2. 卸載時候用的標識名是查詢命令中查到的包含版本信息和PublicToken的完整dll名
  3. path to dll 不必指向你部署的站點中的bin目錄,你能夠建個目錄(好比系統盤根目錄下建個NgenTargets目錄),把目標dll拷出來放進去。
  4. ngen安裝後,站點中的dll文件不能夠刪除,仍是保持原樣,刪掉會500的。這個做用機制是系統級別的,和站點沒啥關係,並且一次ngen安裝後,全部站點都能享受到這個提速。
  5. EF的provider等相關dll也能夠試試,這個我還沒試。

這一步以後,概括下測試數據:

1. owner登錄體驗到的延遲共計(45ms+1.02s+1.06s)
2. company登錄體驗到的延遲共計(1.42s,一樣要感謝登錄owner的時候已經"激活"了user的EF)
3. manage登錄體驗到的延遲共計(925ms+197ms)

哇咔咔,暢快!

至此,心願已了~
Ngen這種工具,不知道mono有沒有,但願vnext正式版出來後,還能再見。

參考

讓IIS 7 如同IIS 8 第一次請求不變慢
Pre-Generated Mapping Views
來,給Entity Framework熱熱身
Performance Considerations for Entity Framework 4, 5, and 6
Improving Startup Performance with NGen (EF6 Onwards)

相關文章
相關標籤/搜索