Entity Framework 6 预热、启动优化
虽然文章题目是针对EF的,但涉及的内容不仅仅是EF。
场景介绍
目前在做的一个项目,行业门户,项目部分站点按域名划分如下:
- user.xxx.com:用户登陆注册
- owner.xxx.com:个人用户后台
- company.xxx.com:企业后台
- 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站)。
暂不论项目本身是否有更好的架构方案,或者配合集群加一层进行可用性缓冲等。本文的目标就是要尽可能的降低用户在上述情况下遇到的等待时间。
以下所有测试前提:
- 站点代码有添加优化手段的情况下,回收程序池,并重启站点;
- 站点代码未变化的情况下,回收程序池,并重启站点。
初始状态
贴图不太方便,只给搜集的数据作为展示
无任何优化措施的初始状态,更新各站点后:
- 首次打开user:5.47s (注意,此时未使用到EF,仅一个空的登陆表单);
- 登陆owner后台:user处理登陆过程(9.37s,涉及用EF访问数据库),owner响应(14.54s,首次访问站点耗时+EF访问数据库耗时,仅涉及用户验证,后台首页为空);
- 注销owner后台,回到user,登陆company后台,company后台响应(15.19s,首次访问站点耗时+EF访问数据库耗时,仅涉及企业验证,后台首页为空);
- 注销company后台,打开manage,manage响应并跳转到登陆页(2.96s,首次访问);
- 登陆manage,耗时(8.23s,处理登陆过程涉及EF)
简单归纳下就是:
1. owner登陆体验到的延迟共计(5.47s + 9.37s + 14.54s) 2. company登陆体验到的延迟共计(15.19s,要感谢登陆owner的时候已经"激活"了user以及user的EF) 3. manage登陆体验到的延迟共计(2.96s + 8.23s)
第一个问题,站点首次访问的耗时大约5秒
这时候还没EF什么事,只是一个空的登陆表单
首次访问,一般分两块:
- 站点更新后重新加载程序文件;
- 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
具体配置方法见:
如果仅配置程序池StartMode为AlwaysRunning还不放心的话,也可以同时针对站点开启preload和DoAppInitAfterRestart。
配置好后,测试了下,效果十分不错。
回收程序池后首次打开各站点,延迟都很低。
其实这个模块的思路和定时从外部触发一个访问是一样的,只是,更好的地方在于,它本身在程序池回收重启的时候就完成了这件事,而不会让外部访问有机会遇到首次访问的情况。
好了,完成这一步,解开了多年心结,省了5秒!
第二个优化点:EF Pre-Generated Mapping Views,大概节省4秒
这个优化点,一般仔细去EF的网站找找还是容易找到的。
具体原因原理不说了,这里引用下博客园dudu大神的文章。
搬一下代码:
using (var dbcontext = new CnblogsDbContext()) { var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext; var mappingCollection = (StorageMappingItemCollection)objectContext .MetadataWorkspace.GetItemCollection(DataSpace.CSSpace); mappingCollection.GenerateViews(new List<EdmSchemaError>()); } //对程序中定义的所有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使用方法:
安装命令:[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]"
具体原理就不解释了。这里就记一下使用经验:
- ngen 安装后,不用试图去寻找生成的.ni.dll文件在哪,这是系统本身起作用的,就相当于已经安装好了
- 卸载时候用的标识名是查询命令中查到的包含版本信息和PublicToken的完整dll名
- path to dll 没必要指向你部署的站点中的bin目录,你可以建个目录(比如系统盘根目录下建个NgenTargets目录),把目标dll拷出来放进去。
- ngen安装后,站点中的dll文件不可以删除,还是保持原样,删掉会500的。这个作用机制是系统级别的,和站点没啥关系,而且一次ngen安装后,所有站点都能享受到这个提速。
- 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)
Entity Framework 6 预热、启动优化的更多相关文章
- Lazy<T>在Entity Framework中的性能优化实践
Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...
- [2014-09-18]Entity Framework 6 预热、启动优化
好久没写博客了,终于憋出了一个大招,现在总结下. 虽然文章题目是针对EF的,但涉及的内容不仅仅是EF. 场景介绍 目前在做的一个项目,行业门户,项目部分站点按域名划分如下: user.xxx.com: ...
- Lazy<T>在Entity Framework中的性能优化实践(附源码)
在使用EF的过程中,导航属性的lazy load机制,能够减少对数据库的不必要的访问.只有当你使用到导航属性的时候,才会访问数据库.但是这个只是对于单个实体而言,而不适用于显示列表数据的情况. 这篇文 ...
- Entity Framework 第四篇 优化SQL查询
Expression<Func<TEntity, bool>>与Func<TEntity, bool>的异同 public IList<TEntity> ...
- Entity Framework学习笔记(六)----使用Lambda查询Entity Framework(1)
请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,老魏一直使用Linq来查询Entity Framework.但是老魏感觉,如果使用Linq的话,那么Linq的返回 ...
- Entity Framework的启动速度优化
最近开发的服务放到IIS上寄宿之后,遇到一些现象,比如刚部署之后,第一次启动很慢:程序放置一会儿,再次请求也会比较慢.比如第一个问题,可以解释为初次请求某一个服务的时候,需要把程序集加载到内存中可能比 ...
- 开发 ASP.NET vNext 续篇:云优化的概念、Entity Framework 7.0、简单吞吐量压力测试
继续上一篇<开发 ASP.NET vNext 初步总结(使用Visual Studio 2014 CTP1)>之后, 关于云优化和版本控制: 我本想做一下MAC和LINUX的self-ho ...
- 云优化的概念、Entity Framework 7.0、简单吞吐量压力测试
云优化的概念.Entity Framework 7.0.简单吞吐量压力测试 继续上一篇<开发 ASP.NET vNext 初步总结(使用Visual Studio 2014 CTP1)>之 ...
- Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)
在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...
随机推荐
- finereport---FineReport入门常见疑难点
一.入门介绍 二.入门需知 注意:开发人员可以设置DEBUG级别,有助于测试 三.数据准备 数据集sql中可以使用参数宏${}动态地生成过滤条件,${}中的语句在FineReport报表中执行,将${ ...
- Unicode 和 UTF-8 是什么关系?
2015-10-14 10:08 评论: 9 收藏: 4 转载自: http://huoding.com/2015/10/13/472作者: 火丁笔记本文地址:https://linux.cn/ ...
- 利用python实现TCP和UDP服务器
利用python的socket模块可以实现基本的网络编程,并且只限于一对一的连接.当然,也可以在其基础上实现一个网络服务器,但由于太底层这种做法不被推荐.其实如果要实现一个网络服务器很简单,调用pyt ...
- Type Java compiler level does not match the version of the installed Java project facet.项目内容没错但是项目上报错,不影响运行
1.Window->Show View->Problems 2.在项目上右键properties->project Facets->修改右侧的version 保持一致 3.w ...
- 目标检测之R-FCN
R-FCN:Object Detection via Region-based Fully Convolutional Networks R-FCN的网络结构 一个Base的convolutional ...
- Linux学习笔记(11)linux网络管理与配置之一——配置路由与默认网关,双网卡绑定(5-6)
Linux学习笔记(11)linux网络管理与配置之一——配置路由与默认网关,双网卡绑定(5-6) 大纲目录 0.常用linux基础网络命令 1.配置主机名 2.配置网卡信息与IP地址 3.配置DNS ...
- springboot接口 接收参数为实体对象跟MultipartFile对象报错。
要把文件和普通数据类型分开接口传输,不可以兼容多个类型参数, 建议是传文件一个接口,返回url路径,再和普通数据一起提交,就是两次 企业上的做法都是这样,先用文件服务器保存文件,返回文件路径 http ...
- centos安装桌面和远程连接
centos安装桌面 安装 MATE 桌面环境为例: 登录服务器,执行命令 yum groups install "X Window System" 安装 X Window Sys ...
- [intellij]create gradle project
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206806425/comments/206797339
- MySQL 数据类型(Day41)
一.介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的高度,但宽度是可选的. mysql数据类型概览 #1.数字:(默认都是有符号,宽度指的是显示宽度,与存储无关) ...