很久沒寫博客了,終於憋出了一個大招,如今總結下。
雖然文章題目是針對EF的,但涉及的內容不只僅是EF。html
目前在作的一個項目,行業門戶,項目部分站點按域名劃分以下:程序員
其中user.xxx.com爲我的用戶及企業用戶登錄入口,
manage.xxx.com/login爲網站管理後臺登錄入口。數據庫
四個項目都是mvc4+ef6+autofac+automapper。服務器
補充信息:架構
因而,用過ef的都知道,ef首次訪問數據庫的時候,耗費的時間很長。
若是四個項目都是首次訪問,那麼我的用戶首次登錄的時候,會經歷兩次ef首次訪問(user站和owner站)。mvc
暫不論項目自己是否有更好的架構方案,或者配合集羣加一層進行可用性緩衝等。
本文的目標就是要儘量的下降用戶在上述狀況下遇到的等待時間。
app
如下全部測試前提:
asp.net
貼圖不太方便,只給蒐集的數據做爲展現
無任何優化措施的初始狀態,更新各站點後:less
簡單概括下就是:ide
1. owner登錄體驗到的延遲共計(5.47s + 9.37s + 14.54s) 2. company登錄體驗到的延遲共計(15.19s,要感謝登錄owner的時候已經"激活"了user以及user的EF) 3. manage登錄體驗到的延遲共計(2.96s + 8.23s)
這時候還沒EF什麼事,只是一個空的登錄表單
首次訪問,通常分兩塊:
不少.net程序員會忽略這個問題。
(這真的是許多年的無奈經驗之談,大多會說,第一次訪問原本就會很慢。)
或者經過腳本定時訪問,以規避這個問題(不讓用戶遇到就好了)
這裏我倒想真的試試解決這個問題。
這是在iis8出來後纔有的,iis8內置的功能,而對於iis7.5也提供了一個擴展以支持這個功能。
Application Initialization Module for IIS 7.5
在頁面接近底部的地方,找到適合本身架構的安裝連接
安裝這個iis模塊後,在iis界面中並無模塊圖標和配置界面,還須要安裝:
http://files.dotblogs.com.tw/jaigi/1306/2013619347830.zip
具體配置方法見:
若是僅配置程序池StartMode爲AlwaysRunning還不放心的話,
也能夠同時針對站點開啓preload和DoAppInitAfterRestart。
配置好後,測試了下,效果十分不錯。
回收程序池後首次打開各站點,延遲都很低。
其實這個模塊的思路和定時從外部觸發一個訪問是同樣的,只是,更好的地方在於,它自己在程序池回收重啓的時候就完成了這件事,而不會讓外部訪問有機會遇到首次訪問的狀況。
好了,完成這一步,解開了多年心結,省了5秒!
這個優化點,通常仔細去EF的網站找找仍是容易找到的。
具體緣由原理不說了,這裏引用下博客園dudu大神的文章。
搬一下代碼:
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)
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. 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)