【问题标题】:How to "warm-up" Entity Framework? When does it get "cold"?如何“热身”实体框架?什么时候“冷”?
【发布时间】:2012-10-26 09:14:31
【问题描述】:

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

前言:

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

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

现在我知道如果我想在性能方面更好地理解框架,我还可以研究哪些主题。不幸的是,Internet 上的大多数信息都已过时或带有主观性,因此我无法找到有关 WarmCold 查询主题的任何其他信息。

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

我们将迁移到 Windows Server 2012、IIS8 和 SQL Server 2012,作为一名初中生,我实际上为自己赢得了先于其他人测试它们的机会。我很高兴他们引入了一个预热模块,可以让我的应用程序为第一个请求做好准备。但是,我不确定如何继续预热我的实体框架。

我已经知道值得去做的事情:

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

按照常识,我认为可能是错误的做法

  • 在应用程序启动时读取虚拟数据以加热事物 建立、生成和验证模型。

问题:

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

【问题讨论】:

  • 弄清楚这是视图生成还是查询编译对您影响最大。如果这是视图生成,则使用预编译视图。如果这是查询 - 你有一个很大的复杂层次结构吗?请注意,昂贵的事情通常会在每个应用程序域发生一次并被缓存,因此在卸载应用程序域并创建新的应用程序域时会出现此类问题。
  • 我已经提到了视图生成@Pawel,层次结构并不复杂,甚至一点也不复杂。但问题也是主要的。按照您所说的,我将研究何时卸载应用程序域。但是,这仍然无助于另一个问题,即加热实体框架,以防万一,就像你说的那样,应用程序域被卸载。在这一点上,似乎应用程序域被卸载了,我不知道为什么,回收只在晚上,idling 设置为 0。
  • 为什么您认为读取虚拟数据是错误的方法?
  • 感觉不太对劲,我想可能有更优雅的东西我不知道。但是,如果这是唯一的解决方案,并且知识渊博的人可以确认没有其他方法,我会选择它。
  • 我遇到的一个问题是应用程序池在一段时间不活动后关闭(由于流量低)是创建一个服务,该服务以设定的时间间隔发出请求到一个您的网页。这可以防止在第一次请求时重新启动应用程序池之前的长时间延迟。或者您可以使用 www.pingalive.com 之类的免费服务来 ping 您的域/IP。这也有助于防止您的缓存对象在过期之前被清除。

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


【解决方案1】:
  • 在我的 Entity Framework 上随时实现高可用性的最佳方法是什么?

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

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

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

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

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

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

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

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

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

【讨论】:

  • 谢谢安德烈,这正是我所需要的。
  • @Andreas 实际上即使使用静态编译查询,第一次运行也太长了。除了:在应用程序启动时读取虚拟数据以预热、生成和验证模型之外,还有什么方法可以预热。
  • @Andreas 所以Entity framework5需要它还是不需要它?如果在 ef5 上使用它有什么不同(我的意思是仍然很慢或很少击球手或没有不同?)
  • "静态 CompiledQuery 很好,因为它们快速且易于编写并有助于降低性能。"性能下降?
【解决方案2】:

一般提示。

  • 执行严格的日志记录,包括访问的内容请求时间
  • 在初始化您的应用程序以热启动非常慢您从上一步中提取的请求时执行虚拟请求。
  • 除非是真正的问题,否则不要费心优化,与应用程序的使用者沟通并询问。如果只是为了弄清楚需要优化的内容,就可以轻松地拥有一个持续的反馈循环。

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

  • 复杂性较低 - 您正在以一种无论框架发生变化如何都可以正常工作的方式来预热应用程序,并且您不需要找出可能时髦的 API/框架内部来做到这一点正确的方式
  • 更大的覆盖范围 - 您正在同时预热与慢速请求相关的所有缓存层。

解释缓存何时“冷”。

这发生在框架中应用缓存的任何层top of the performance page 中有很好的描述。

  • 如果在发生导致缓存失效的潜在更改后必须验证缓存时,这可能是超时或更智能(即缓存项中的更改)。
  • 当缓存项被驱逐时,执行此操作的算法在the performance article you linked 的“缓存驱逐算法”一节中进行了描述,但很简短。
    • LFRU(最不常用 - 最近使用)缓存命中计数和期限,限制为 800 项。

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

【讨论】:

  • 这是另一个有用的答案,非常感谢。
【解决方案3】:

正如您所说,使用“预先生成的视图”确实是您需要做的所有事情。

从您的link 中提取: “生成视图时,也会对其进行验证。从性能的角度来看,视图生成的绝大部分成本实际上是视图的验证”

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

执行不相关的查询只会消耗系统资源。

快捷方式...

  1. 跳过所有预先生成的视图的额外工作
  2. 创建您的对象上下文
  3. 触发那个甜蜜的无关查询
  4. 然后在整个过程中保留对对象上下文的引用 (不推荐)。

【讨论】:

【解决方案4】:

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

一般来说,您应该努力将分布式架构设计为仅在本地缓存的信息变得陈旧或需要进行事务处理时才需要基于 IO 的数据请求。任何“在线”数据请求的检索时间通常比本地内存缓存检索长 10-1000 倍。与“本地与远程”数据问题相比,仅这一事实就经常使关于“冷数据与热数据”的讨论变得无关紧要。

【讨论】:

  • 这是一个很好的观点,我经常忽略,同时对实体框架的原始性能大肆宣传。我将进一步研究这一点,并更多地研究缓存的原理。但是,我仍然想更好地理解 EF 方面的“冷与暖”。
  • “与“本地与远程”数据问题相比,仅这一事实就经常使关于“冷数据与热数据”的讨论变得无关紧要。”并不真地。如果您没有在本地缓存它(最初不会),您仍然需要点击 EF 并遭受初始化痛苦以准备缓存。在缓存未初始化的相同位置,EF 将未初始化。因此,如果唯一的问题是 EF 初始化时间,添加一层缓存可能无济于事,但它会增加另一层复杂性......
【解决方案5】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多