如何"热身"实体框架?什么时候得到"冷"?

时间:2012-11-06 12:05:22

标签: asp.net asp.net-mvc entity-framework asp.net-mvc-4 entity-framework-5

不,我的第二个问题的答案不是冬天。

前言

我最近一直在对Entity Framework进行大量研究,而且一直困扰着我的是它在查询没有预热时的性能,所谓的冷查询。

我浏览了Entity Framework 5.0的performance considerations文章。作者介绍了温暖查询的概念以及它们之间的区别,我也注意到自己并不知道它们的存在。在这里,值得一提的是,我背后只有六个月的经验。

现在我知道如果我想在性能方面更好地理解框架,我还可以研究哪些主题。遗憾的是,互联网上的大部分信息都过时或过于主观,因此我无法找到有关 Warm vs Cold 查询主题的任何其他信息。

基本上我到目前为止注意到的是,每当我需要重新编译或回收点击时,我的初始查询变得非常慢。正如预期的那样,任何后续数据读取都很快(主观)。

我们将迁移到Windows Server 2012,IIS8和SQL Server 2012,作为一名少年,我实际上赢得了在其他人之前测试它们的机会。我很高兴他们推出了一个预热模块,可以让我的应用程序为第一个请求做好准备。但是,我不确定如何继续升温我的实体框架。

我所知道的是值得做的事:

  • 按照建议提前生成我的观点。
  • 最终将我的模型移动到一个单独的程序集中。

我考虑做的是,通过常识,可能是错误的方法

  • 在Application Start中进行虚拟数据读取以便加热 起来,生成并验证模型。

问题:

  • 在我的实体框架上随时获得高可用性的最佳方法是什么?
  • 在什么情况下实体框架再次“冷”? (重新编译,回收,IIS重启等)。

5 个答案:

答案 0 :(得分:55)

  • 在我的实体框架上随时获得高可用性的最佳方法是什么?

您可以混合使用预生成视图和静态编译查询。

静态CompiledQuerys很好,因为它们可以快速轻松地编写并有助于提高性能。但是对于EF5,没有必要编译所有查询,因为EF将自动编译查询本身。唯一的问题是,当扫描缓存时,这些查询可能会丢失。因此,您仍然希望保留对自己编译的查询的引用,这些查询仅发生在非常罕见的情况下,但这些查询很昂贵。如果将这些查询放入静态类中,它们将在首次需要时进行编译。对于某些查询,这可能为时已晚,因此您可能希望在应用程序启动期间强制编译这些查询。

如您所述,预生成视图是另一种可能性。特别是,那些需要很长时间才能编译并且不会更改的查询。这样就可以将性能开销从运行时转移到编译时。这也不会引入任何滞后。但当然这种变化会传递到数据库,因此处理起来并不容易。代码更灵活。

不要使用大量的TPT继承(这是EF中的一般性能问题)。既不构建你的继承层次结构太深也不太宽。某些类特定的2-3个属性可能不足以要求自己的类型,但可以作为现有类型的可选(可空)属性处理。

长时间不要坚持单一的背景。每个上下文实例都有自己的第一级缓存,随着它越来越大,性能会降低。上下文创建很便宜,但是上下文的缓存实体内的状态管理可能变得昂贵。其他缓存(查询计划和元数据)在上下文之间共享,并将与AppDomain一起死亡。

总而言之,您应确保经常分配上下文并仅在短时间内使用它们,您可以快速启动应用程序,编译很少使用的查询,并为性能至关重要的查询提供预生成的视图。经常使用。

  • 在什么情况下实体框架再次“冷”? (重新编译,回收,IIS重启等)。

基本上,每次丢失AppDomain。 IIS每29 hours执行一次重新启动,因此您永远无法保证您的实例可以使用。此外,在没有活动的一段时间后,AppDomain也会关闭。你应该尝试再次快速上来。也许你可以异步进行一些初始化(但要注意多线程问题)。您可以使用在没有请求阻止AppDomain死亡的情况下在您的应用程序中调用虚拟页面的计划任务,但最终会这样做。

我还假设当您更改配置文件或更改程序集时,将重新启动。

答案 1 :(得分:8)

如果您希望在所有通话中获得最佳性能,请仔细考虑您的架构。例如,在应用程序加载时预先缓存服务器RAM中经常使用的查找而不是在每个请求上使用数据库调用可能是有意义的。该技术将确保常用数据的最小应用响应时间。但是,您必须确保具有良好的过期策略,或者在发生影响缓存数据的更改时始终清除缓存以避免并发问题。

通常,您应该努力设计分布式体系结构,以便在本地缓存的信息变得陈旧或需要事务时才需要基于IO的数据请求。任何“线上”数据请求通常需要比内存缓存检索中的本地检索长10-1000倍。与“本地与远程”数据问题相比,仅此一个事实常常使“冷与热数据”的讨论无关紧要。

答案 2 :(得分:7)

一般提示。

  • 执行严格的记录,包括访问的内容请求时间
  • 在将应用程序初始化为热启动非常慢请求时执行虚拟请求,这些请求是您从上一步骤中获取的。
  • 除非是真正的问题,否则不要打扰优化,与应用程序的消费者沟通并询问。如果只是想出需要优化的内容,那么就可以获得持续的反馈循环。

现在解释为什么虚拟请求不是错误的方法

  • 不那么复杂 - 您正在以一种无论框架中的变化如何都能工作的方式来预热应用程序,并且您不需要弄清楚可能有时间的API /框架内部构件正确的方式
  • 更大的覆盖率 - 您正在预热与慢速请求相关的所有缓存层。

解释缓存何时“冷”。

这种情况发生在框架中应用缓存的任何层上,top of the performance page上有一个很好的描述。

  • 如果在使缓存失效的潜在更改之后必须验证缓存,则可能是超时或更智能(即更改缓存项目)。
  • 当驱逐缓存项时,the performance article you linked中的“缓存逐出算法”一节中描述了执行此操作的算法,但简而言之。
    • LFRU(最少使用 - 最近使用)缓存命中数和年龄,限制为800项。

您提到的其他内容,特别是重新编译和重新启动IIS,清除部分或全部内存缓存。

答案 3 :(得分:3)

正如您所说,使用“预先生成的视图”,这是您真正需要做的。

link中提取: “当生成视图时,它们也会得到验证。从性能角度来看,视图生成的绝大部分成本实际上是视图的验证”

这意味着在构建模型装配时会发生性能爆震。然后,您的上下文对象将跳过“冷查询”,并在上下文对象生命周期的持续时间以及后续新对象上下文中保持响应。

执行不相关的查询除了消耗系统资源之外别无其他目的。

捷径......

  1. 略过预生成视图的所有额外工作
  2. 创建对象上下文
  3. 解开那个甜蜜无关的查询
  4. 然后在过程期间保持对对象上下文的引用 (不推荐)。

答案 4 :(得分:2)

我没有这个框架的经验。但在其他情况下,例如Solr,完全虚拟读取将没有多大用处,除非你可以缓存整个数据库(或索引)。

更好的方法是记录查询,从日志中提取最常见的查询并使用它们进行预热。在继续之前,请确保不要记录热身查询或从日志中删除它们。