關於.net MVC5+EF6 網站部署的問題


  創建mvc web application,采用code first 的方式,MVC5,EF6.0 整了一個網站。開發完之后。直接publish。就這樣部署到服務器上了。

在使用過程中發現,網站打開的速度有點慢。而且每隔一段時間不使用,網站的打開速度就變慢。

問題分析:

一開始首先想到的是IIS的應用程序池釋放的問題。

后來配置了iis還是過一段時間訪問變慢。

后來為了快速解決這個問題,只能先做了一個bat文件,在服務器端模擬一段時間內訪問這個網站一下。這樣用戶在訪問的時候不會體會到網站的訪問速度變慢的問題。

@echo  正在關掉所有的IE進程(需要設置默認瀏覽器是IE)
taskkill   /im iexplore.exe /f /t
@echo 正在通過ping來延遲80秒鍾,以方便IE打開頁面
ping 127.0.0.1 -n 10 
@echo 正在訪問 http://localhost
start "C:\Program Files\Internet Explorer\iexplore.exe"  http://localhost 

 這樣隔一段時間變慢的問題已經解決了,但是還沒有查找到這是什么原因。

后來看到一篇文章說 是因為EF 的原因。

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了,所以每次啟動都要重寫編譯本地代碼有比較明顯的性能影響。
 

第二、優化方案

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

一、安裝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

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

如果僅配置程序池StartMode為AlwaysRunning還不放心的話, 也可以同時針對站點開啟preload和DoAppInitAfterRestart。

設置應用程序池如下圖:

設置網站如下圖

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

二、用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\ngen install EntityFramework.SqlServer.dll
注意:這里根據你自己機器(是32還是64)和.net版本,選擇相應的命令,只需要安裝EntityFramework.SqlServer.dll,因為安依賴EntityFramework.dll,會自動安裝生成EntityFramework.dll的本地鏡像。

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

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

 

  1. SELECT
  2. [GroupBy1].[A1] AS [C1]
  3. FROM ( SELECT
  4. COUNT(1) AS [A1]
  5. FROM [dbo].[__MigrationHistory] AS [Extent1]
  6. ) AS [GroupBy1]
  7. GO
  8. SELECT TOP (1)
  9. [Extent1].[Id] AS [Id],
  10. [Extent1].[ModelHash] AS [ModelHash]
  11. FROM [dbo].[EdmMetadata] AS [Extent1]
  12. ORDER BY [Extent1].[Id] DESC
  13. GO

 

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

Application_Start加代碼
  1. 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加入下面代碼:
  1. using (var dbcontext = new EFDbContext())
  2. {
  3. var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;
  4. var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
  5. mappingCollection.GenerateViews(new List<EdmSchemaError>());
  6. //對程序中定義的所有DbContext逐一進行這個操作
  7. }

六、補充

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

閑時超時默認是20分鍾,如果在超過20分鍾都沒有請求這個應用程序池工作進程就要關閉。這里你可以設置根據自己需要設置長一些。

 


免責聲明!

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



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