zoukankan      html  css  js  c++  java
  • MVC5中EF6 Code First启动慢及间隙变慢的一些优化处理

    问题描述:
    第一次访问的时候很慢,后面再次打开页面很快,过了一段时间不访问页面然后再次打开页面又像第一次那样很慢。
    采用的技术和环境:
    使用技术:EF6+MVC5
    服务器环境:Windows 2012,Windows 2008 都是64位 + IIS7.5
     

    第一、问题原因分析

    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界面中并没有模块图标和配置界面,还需要安装:

    https://yunpan.cn/OcMvrRKi3a8Wbu  访问密码 ce02

    安装成功之后会多了一个配置如下图:

    如果仅配置程序池StartMode为AlwaysRunning还不放心的话,
    也可以同时针对站点开启preload和DoAppInitAfterRestart。

    设置应用程序池如下图:

    设置网站如下图

    配置好后,测试了下,效果十分不错。
    回收程序池后首次打开各站点,延迟都很低。
    其实这个模块的思路和定时从外部触发一个访问是一样的,只是,更好的地方在于,它本身在程序池回收重启的时候就完成了这件事,而不会让外部访问有机会遇到首次访问的情况。

    二、用Ngen安装生成EF的本地镜像

    1、打开cmd窗口
    2、定位到dll所在的目录,如:cd d:website1in,切换到程序的bin目录。
    3、运行ngen命令
    For 32 bit run:
    %WINDIR%Microsoft.NETFrameworkv4.0.30319
    gen install EntityFramework.SqlServer.dll

    For 64 bit run:

    %WINDIR%Microsoft.NETFramework64v4.0.30319
    gen install 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<Magicodes.WeiChat.Data.AppDbContext>(null);
    Magicodes.WeiChat.Data.AppDbContext这是我项目的EF上下方类,你要根据你的项目替换成自己的EF上下方类。 

    四、Model和DAl单独的分层的

    为了减少model和DAL导致重新编译dll带来的性能影响。把Model和DAL都单独的分层,编译成单独的dll。 

    五、EF Pre-Generated Mapping Views(预生成映射视图)

    Application_Start加入下面代码:
    using (var dbcontext = newAppDbContext()) 
    {
    var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;
    var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
    mappingCollection.GenerateViews(
    new List<EdmSchemaError>()); //对程序中定义的所有DbContext逐一进行这个操作
    }

    六、补充

    如果你觉得这还没有解决”过了一段时间不访问页面然后再次打开页面变慢“的问题,而且不能忍受第一次访问还是有点慢,可以设置应用程序池的”闲时超时“和回收”固定时间间隔“长一些或者建一个计划任务定时去访问使用了EF的页面,这样给ef热身,让EF不变冷,这样可以防止长时间不请求网站,应用程序进程停止再次访问变慢的问题。设置应用程序池的时间如下图:

    闲时超时默认是20分钟,如果在超过20分钟都没有请求这个应用程序池工作进程就要关闭。这里你可以设置根据自己需要设置长一些。

    备注:以上内容参考了http://www.lanhusoft.com

  • 相关阅读:
    97. Interleaving String
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    94. Binary Tree Inorder Traversal
    odoo many2many字段 指定打开的form视图
    docker sentry 配置文件位置
    postgres 计算时差
    postgres 字符操作补位,字符切割
    postgres判断字符串是否为时间,数字
    odoo fields_view_get
  • 原文地址:https://www.cnblogs.com/smileyearn/p/5819676.html
Copyright © 2011-2022 走看看