天天看點

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

最近項目在使用EF了,mvc使用EF确實友善,因為添加功能的時候可以使用vs自動生成用ef的增、删、查、改的模闆,大的提高的工作效率。但是很多人都遇到過用EF開發的程式在第一次通路的時候會比用ADO純sql慢很多,過一段時間不通路又會變慢。我最近的兩個項目分别是藍狐軟體工作室和一個商城系統都是用MVC5+EF6Code First開發的,都遇到過這樣的問題。下面我就分享一下我們藍狐在這個優化的過程中使用的解決辦法。

問題描述:第一次通路的時候很慢,後面再次打開頁面很快,過了一段時間不通路頁面然後再次打開頁面又像第一次那樣很慢。

采用的技術和環境:

windows 2008 64位+IIS7.5

vs2013+mvc5

entity framework6 Code First

我使用MiniProfiler.EF來監控來診斷到底是什麼導緻頁面第一次通路為什麼這麼慢。監控到的結果如下圖:

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

可以看到這個頁面第一次通路總共花了37643毫秒,也就是37.6秒,這樣大的影響了使用者體驗,讓人無法忍受。有會人說.net的程式第一次本身就很慢,但是這也太慢了。提升ASP.NET的程式性能解決方案有很多,比如解決第一次通路就可以預編譯代碼,但是這個不屬于本文的讨論範疇,本文主要讨論EF和程式池初始化慢的問題。我們第一想到的是不是EF導緻的太慢,按理說EF已經是6了不會性能這麼差吧,而且sql部分隻占1.6%的時間,也就是597.8毫秒的時間。

藍狐軟體工作室通過了一些優化方法,終于把這個”第一次通路慢,再打開其它頁面就很快,隔一段時間不通路再通路又變慢的問題“解決了。優化之後效果有了比較大的提升。停止應用程式池之後的第一次通路結果:

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

再次通路結果:

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

隔很久不通路再次通路頁面響應時間也能保持4-8秒内

第一、問題原因分析

Ø  EF方面的原因:

1、Code First第一次啟動會對比程式中的Model與資料庫表(database initializer ),生成Model與資料庫的映射視圖

2、随着EF的開源,EF從6開始就不會包含在.net Framework中,安裝.net Framework預設是不會安裝EF的。是以EF程式集就沒有生成本地鏡像,這樣每次程式啟動,EF的代碼都會通過just-in-time (JIT) compiler(即時編譯器)把MSIL中間代碼編譯成本機能識别的本地代碼。因為這個生成的本地代碼存在程式運作的程序裡面的記憶體中,它将回收當程式程序被終止(例如:iis程式池回收,程式池預設是按需觸發運作的,沒人通路它就不啟動了)。由于EF架構還是比較大的,EF6檔案大小到4-5M了,是以每次啟動都要重寫編譯本地代碼有比較明顯的性能影響。

Ø  抛開EF架構程式啟動慢的問題主要有以下兩方面的原因:

1、站點更新後重新加載程式檔案;

2、iis程式池回收後也會需要重新加載(程式池預設是按需觸發運作的,沒人通路它就不啟動了)

MVC的程式第一次通路比較慢的的問題由于第一次是要處理視圖檔案.cshtml(生成為.cs檔案)、加載引用的dll程式檔案和初始化程式池等等。

第二、優化方案

我主要是通過以下幾方面來優化

一、安裝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://pan.baidu.com/s/1c091WxM

安裝成功之後會多了一個配置如下圖:

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

如果僅配置程式池StartMode為AlwaysRunning還不放心的話,

也可以同時針對站點開啟preload和DoAppInitAfterRestart。

設定應用程式池如下圖:

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

設定網站如下圖

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

配置好後,測試了下,效果十分不錯。

回收程式池後首次打開各站點,延遲都很低。

其實這個子產品的思路和定時從外部觸發一個通路是一樣的,隻是,更好的地方在于,它本身在程式池回收重新開機的時候就完成了這件事,而不會讓外部通路有機會遇到首次通路的情況。

二、用Ngen安裝生成EF的本地鏡像

1、打開cmd視窗

2、定位到dll所在的目錄,如:cd d:\website1\bin,切換到程式的bin目錄。

3、運作ngen指令

For 32 bit run:

%WINDIR%\Microsoft.NET\Framework\v4.0.30319\ngen install EntityFramework.SqlServer.dll

For 64 bit run:

%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\ngeninstall EntityFramework.SqlServer.dll

注意:這裡根據你自己機器(是32還是64)和.net版本,選擇相應的指令,隻需要安裝EntityFramework.SqlServer.dll,因為安依賴EntityFramework.dll,會自動安裝生成EntityFramework.dll的本地鏡像。

三、禁用第一次ef查詢對表__MigrationHistory的問題

使用了ef的Code first會在第一次ef查詢的時候會對__MigrationHistory通路,是為了檢查資料庫和model是否比對,以保證ef能正常運作。通過監測會先執行下面的sql:

SELECT

[GroupBy1].[A1] AS [C1]

FROM ( SELECT

   COUNT(1) AS [A1]

    FROM[dbo].[__MigrationHistory] AS [Extent1]

)  AS[GroupBy1]

GO

SELECT TOP (1)

[Extent1].[Id] AS [Id],

[Extent1].[ModelHash] AS [ModelHash]

FROM [dbo].[EdmMetadata] AS [Extent1]

ORDER BY [Extent1].[Id] DESC

GO

這段sql語句其實中隻是在開發的時候有用,釋出到生産環境,可以把這個給禁用了以提高性能。解決辦法:

Application_Start加代碼

Database.SetInitializer<lanhuBlog.DAL.BlogContext>(null);

lanhuBlog.DAL.BlogContext這是我項目的EF上下方類,你要根據你的項目替換成自己的EF上下方類。

四、Model和DAl單獨的分層的

用vs建一個mvc項目,Model、DAL、Controller、View都在Web項目裡面。為了減少model和DAL導緻重新編譯dll帶來的性能影響。我把Model和DAL都單獨的分層,編譯成單獨的dll了。

五、EF Pre-Generated Mapping Views(預生成映射視圖)

Application_Start加入下面代碼:

using (var dbcontext = new EFDbContext())

{

var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;

var mappingCollection =(StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);

mappingCollection.GenerateViews(newList<EdmSchemaError>());

//對程式中定義的所有DbContext逐一進行這個操作

}

六、補充

如果你覺得這還沒有解決”過了一段時間不通路頁面然後再次打開頁面變慢“的問題,而且不能忍受第一次通路還是有點慢,可以設定應用程式池的”閑時逾時“和回收”固定時間間隔“長一些或者建一個計劃任務定時去通路使用了ef的頁面,這樣給ef熱身,讓ef不變冷,這樣可以防止長時間不請求網站,應用程式程序停止再次通路變慢的問題。設定應用程式池的時間如下圖:

MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

閑時逾時預設是20分鐘,如果在超過20分鐘都沒有請求這個應用程式池工作程序就要關閉。這裡你可以設定根據自己需要設定長一些。

本站文章除注明轉載外,均為本站原創或翻譯,歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動,共創和諧網絡環境。

轉載請注明:文章轉載自:藍狐軟體工作室 » 親授MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

本文标題:親授MVC5中EF6 Code First啟動慢及間隙變慢優化的實踐經驗

本文位址:http://www.lanhusoft.com/Article/127.html

繼續閱讀