Comment «réchauffer» Entity Framework? Quand fait-il «froid»?


118

Non, la réponse à ma deuxième question n'est pas l'hiver.

Préface:

J'ai récemment fait beaucoup de recherches sur Entity Framework et ce qui me dérange, ce sont ses performances lorsque les requêtes ne sont pas préchauffées, appelées requêtes froides.

J'ai parcouru l' article sur les considérations de performances pour Entity Framework 5.0. Les auteurs ont introduit le concept de requêtes chaudes et froides et en quoi elles diffèrent, ce que j'ai également remarqué moi-même sans connaître leur existence. Ici, il vaut probablement la peine de mentionner que je n'ai que six mois d'expérience derrière mon dos.

Maintenant, je sais sur quels sujets je peux effectuer des recherches supplémentaires si je veux mieux comprendre le cadre en termes de performances. Malheureusement, la plupart des informations sur Internet sont obsolètes ou surchargées de subjectivité, d'où mon incapacité à trouver des informations supplémentaires sur le sujet des requêtes Warm vs Cold .

Fondamentalement, ce que j'ai remarqué jusqu'à présent, c'est que chaque fois que je dois recompiler ou que le recyclage se produit, mes requêtes initiales deviennent très lentes. Toute lecture ultérieure des données est rapide ( subjective ), comme prévu.

Nous allons migrer vers Windows Server 2012, IIS8 et SQL Server 2012 et en tant que Junior, je me suis en fait mérité l'opportunité de les tester avant les autres. Je suis très heureux qu'ils aient introduit un module de préchauffage qui préparera mon application pour cette première demande. Cependant, je ne sais pas comment procéder avec le préchauffage de mon Entity Framework.

Ce que je sais déjà vaut la peine:

  • Générez mes vues à l'avance comme suggéré.
  • Déplacez éventuellement mes modèles dans un assemblage séparé.

Ce que je considère faire, en allant avec le bon sens, est probablement une mauvaise approche :

  • Faire des lectures de données factices au démarrage de l'application afin de réchauffer, générer et valider les modèles.

Des questions:

  • Quelle serait la meilleure approche pour avoir une haute disponibilité sur mon Entity Framework à tout moment?
  • Dans quels cas Entity Framework redevient-il "froid"? (Recompilation, recyclage, redémarrage IIS, etc.)

Déterminez si c'est la génération de vues ou la compilation de requêtes qui vous frappe le plus. S'il s'agit de view gen, utilisez des vues précompilées. Si ce sont les requêtes - avez-vous une grande hiérarchie compliquée? Notez que les choses coûteuses se produisent généralement une fois par domaine d'application et sont mises en cache.Par conséquent, vous voyez ce type de problèmes lorsque le domaine d'application est déchargé et qu'un nouveau est créé.
Pawel

J'ai déjà mentionné la génération de vues @Pawel, la hiérarchie n'est pas compliquée, même pas un peu. Mais le problème est également principal. Suite à ce que vous avez dit, je vais rechercher quand le domaine de l'application est en cours de déchargement. Cependant, cela n'aide toujours pas l'autre problème qui réchauffe l'Entity Framework au cas où, comme vous l'avez dit, le domaine de l'application serait déchargé. À ce stade, il semble que le domaine de l'application soit déchargé plus qu'il ne le devrait et je ne sais pas pourquoi, le recyclage se fait uniquement la nuit, la marche au ralenti est définie sur 0.
Peter

4
Pourquoi pensez-vous que faire des lectures de données factices n'est pas la bonne approche?
Josh Heitzman

5
Cela ne me semble pas juste, j'ai pensé qu'il y avait peut-être quelque chose de plus élégant dont je ne suis pas au courant. Mais si c'est la seule solution et que quelqu'un avec de bonnes connaissances peut confirmer qu'il n'y a pas d'autre moyen, je vais simplement y aller.
Peter

1
Un problème que j'ai rencontré avec l'arrêt du pool d'applications après une période de non-activité (en raison du faible trafic) est de créer un service qui fait une demande à un intervalle de temps défini à l'une de vos pages. Cela évite le long délai avant le redémarrage du pool d'applications à la première demande. Ou vous pouvez utiliser un service gratuit comme www.pingalive.com pour envoyer une requête ping à votre domaine / adresse IP. Cela permet également d'éviter que vos objets mis en cache ne soient effacés avant leur expiration.
hatsrumandcode

Réponses:


55
  • Quelle serait la meilleure approche pour avoir une haute disponibilité sur mon Entity Framework à tout moment?

Vous pouvez opter pour un mélange de vues prégénérées et de requêtes compilées statiques.

Les requêtes compilées statiques sont bonnes car elles sont rapides et faciles à écrire et contribuent à améliorer les performances. Cependant, avec EF5, il n'est pas nécessaire de compiler toutes vos requêtes car EF compilera automatiquement les requêtes. Le seul problème est que ces requêtes peuvent être perdues lorsque le cache est balayé. Vous souhaitez donc toujours conserver des références à vos propres requêtes compilées pour celles qui ne se produisent que très rarement, mais qui coûtent cher. Si vous placez ces requêtes dans des classes statiques, elles seront compilées lors de leur première utilisation. Cela peut être trop tard pour certaines requêtes, vous souhaiterez peut-être forcer la compilation de ces requêtes au démarrage de l'application.

Les vues prégénérantes sont l'autre possibilité que vous mentionnez. Surtout pour les requêtes qui prennent très longtemps à se compiler et qui ne changent pas. De cette façon, vous déplacez la surcharge de performances du runtime au moment de la compilation. De plus, cela n'introduira aucun décalage. Mais bien sûr, ce changement passe par la base de données, donc ce n'est pas si facile à gérer. Le code est plus flexible.

N'utilisez pas beaucoup d'héritage TPT (c'est un problème de performances général dans EF). Ne construisez pas vos hiérarchies d'héritage trop profondes ni trop larges. Seules 2-3 propriétés spécifiques à une classe peuvent ne pas être suffisantes pour exiger un propre type, mais pourraient être gérées comme des propriétés facultatives (nullables) pour un type existant.

Ne vous accrochez pas longtemps à un seul contexte. Chaque instance de contexte possède son propre cache de premier niveau qui ralentit les performances à mesure qu'elle augmente. La création de contexte est bon marché, mais la gestion de l'état à l'intérieur des entités mises en cache du contexte peut devenir coûteuse. Les autres caches (plan de requête et métadonnées) sont partagés entre les contextes et mourront avec l'AppDomain.

Dans l'ensemble, vous devez vous assurer d'allouer des contextes fréquemment et de ne les utiliser que pendant une courte période, de pouvoir démarrer votre application rapidement, de compiler des requêtes rarement utilisées et de fournir des vues prégénérées pour les requêtes qui sont essentielles pour les performances et souvent utilisées.

  • Dans quels cas Entity Framework redevient-il "froid"? (Recompilation, recyclage, redémarrage IIS, etc.)

En gros, chaque fois que vous perdez votre AppDomain. IIS redémarre toutes les 29 heures , vous ne pouvez donc jamais garantir que vous disposerez de vos instances. Aussi après un certain temps sans activité, AppDomain est également arrêté. Vous devriez essayer de revenir rapidement. Vous pouvez peut-être effectuer une partie de l'initialisation de manière asynchrone (mais méfiez-vous des problèmes de multi-threading). Vous pouvez utiliser des tâches planifiées qui appellent des pages factices dans votre application pendant les périodes où il n'y a aucune demande pour empêcher l'AppDomain de mourir, mais cela finira par le faire.

Je suppose également que lorsque vous modifiez votre fichier de configuration ou que vous modifiez les assemblages, il y aura un redémarrage.


Merci André, c'était ce dont j'avais besoin.
Peter

@Andreas En fait, même avec des requêtes compilées statiques, la première exécution est trop longue. Existe-t-il un moyen de réchauffer ceux-ci en dehors de: Faire des lectures de données factices au démarrage de l'application afin de réchauffer les choses, générer et valider les modèles.
manishKungwani

@Andreas So Entity Framework5 en a-t-il besoin ou non? Qu'est-ce qui est différent si vous l'utilisez sur ef5 (je veux dire encore lent ou peu batteur ou pas différent?)
qakmak

«Les requêtes compilées statiques sont bonnes car elles sont rapides et faciles à écrire et contribuent à réduire les performances. Performances réduites?
Mathemats

9

Si vous recherchez des performances maximales pour tous les appels, vous devez considérer attentivement votre architecture. Par exemple, il peut être judicieux de pré-mettre en cache les recherches souvent utilisées dans la RAM du serveur lorsque l'application se charge au lieu d'utiliser des appels de base de données à chaque demande. Cette technique garantira des temps de réponse d'application minimaux pour les données couramment utilisées. Cependant, vous devez vous assurer d'avoir une politique d'expiration bien conduite ou toujours vider votre cache chaque fois que des modifications sont apportées qui affectent les données mises en cache pour éviter les problèmes de concurrence.

En général, vous devez vous efforcer de concevoir des architectures distribuées pour ne nécessiter des demandes de données basées sur les E / S que lorsque les informations mises en cache localement deviennent obsolètes ou doivent être transactionnelles. Toute demande de données "over the wire" prendra normalement 10 à 1000 fois plus de temps à récupérer qu'une recherche locale, en mémoire cache. Ce seul fait rend souvent les discussions sur les «données froides contre chaudes» sans importance par rapport à la question des données «locales contre distantes».


C'est un bon point que j'ignore souvent, tout en étant hypnotisé sur les performances brutes du framework d'entité. Je vais approfondir cette question et approfondir mes recherches sur les principes de la mise en cache. Cependant, «froid vs chaud» en termes d'EF est toujours quelque chose que je veux mieux comprendre.
Peter

2
«Ce seul fait rend souvent les discussions sur les« données froides contre chaudes »sans importance par rapport à la question des données« locales contre distantes »». Pas vraiment. Si vous ne l'avez pas mis en cache localement (ce que vous ne ferez pas au départ), vous devrez toujours frapper EF et souffrir de la douleur d'initialisation afin d'amorcer votre cache. Les mêmes endroits où votre cache n'est pas initialisé, EF sera non initialisé. Donc, l'ajout d'une couche de mise en cache peut ne pas aider si le seul problème est le temps d'initialisation EF, mais cela ajoutera une autre couche de complexité ...
MikeJansen

8

Conseils généraux.

  • Effectuer l' enregistrement rigoureux , y compris ce qui est accessible et le temps de demande .
  • Exécutez des requêtes factices lors de l'initialisation de votre application pour démarrer à chaud les requêtes très lentes que vous avez récupérées à l'étape précédente.
  • Ne vous embêtez pas à optimiser sauf si c'est un vrai problème, communiquez avec le consommateur de l'application et demandez. Soyez à l'aise avec une boucle de rétroaction continue, ne serait-ce que pour déterminer ce qui doit être optimisé .

Maintenant, pour expliquer pourquoi les demandes factices ne sont pas la mauvaise approche .

  • Moins de complexité - Vous préchauffez l'application d'une manière qui fonctionnera indépendamment des changements dans le framework, et vous n'avez pas besoin de trouver des API / composants internes du framework éventuellement géniaux pour le faire de la bonne manière .
  • Une plus grande couverture - Vous réchauffez toutes les couches de mise en cache à la fois liées à la demande lente.

Pour expliquer quand un cache devient "froid".

Cela se produit à n'importe quelle couche de votre framework qui applique un cache, il y a une bonne description en haut de la page de performances .

  • Chaque fois qu'un cache doit être validé après un changement potentiel qui le rend obsolète, cela peut être un délai d'expiration ou plus intelligent (c'est-à-dire un changement dans l'élément mis en cache).
  • Lorsqu'un élément du cache est expulsé, l'algorithme pour cela est décrit dans la section "Algorithme d'éviction du cache" de l'article sur les performances que vous avez lié , mais en bref.
    • Cache LFRU (le moins fréquemment utilisé - récemment) sur le nombre de succès et l'âge avec une limite de 800 éléments.

Les autres choses que vous avez mentionnées, en particulier la recompilation et le redémarrage d'IIS, effacent une partie ou la totalité des caches en mémoire.


C'est une autre réponse utile, très appréciée.
Peter

3

Comme vous l'avez dit, utilisez des "vues pré-générées", c'est vraiment tout ce que vous avez à faire.

Extrait de votre lien : "Lorsque les vues sont générées, elles sont également validées. Du point de vue des performances, la grande majorité du coût de génération de vues est en fait la validation des vues"

Cela signifie que le coup de performance aura lieu lorsque vous construirez votre assemblage de modèle. Votre objet de contexte ignorera alors la "requête à froid" et restera réactif pendant la durée du cycle de vie de l'objet de contexte ainsi que les nouveaux contextes d'objet suivants.

L'exécution de requêtes non pertinentes ne servira à aucun autre objectif que de consommer des ressources système.

Le raccourci ...

  1. Évitez tout ce travail supplémentaire des vues pré-générées
  2. Créez votre contexte d'objet
  3. Lancez cette douce requête non pertinente
  4. Ensuite, gardez simplement une référence à votre contexte d'objet pendant toute la durée de votre processus (non recommandé).


2

Je n'ai aucune expérience dans ce cadre. Mais dans d'autres contextes, par exemple Solr, des lectures complètement factices ne seront pas d'une grande utilité à moins que vous ne puissiez mettre en cache toute la base de données (ou index).

Une meilleure approche serait de consigner les requêtes, d'extraire les plus courantes des journaux et de les utiliser pour se réchauffer. Assurez-vous simplement de ne pas enregistrer les requêtes de préchauffage ou de ne pas les supprimer des journaux avant de continuer.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.