J'entends constamment parler d'une personne qui avait un problème de performance qu'elle a résolu par la mise en cache.
Ou encore, comment x, y, z dans le code de vos programmes peut nuire à votre capacité de mise en cache.
Même dans l'un des derniers podcasts, Jeff Atwood explique comment ils mettent en cache certaines valeurs pour une récupération rapide.
Il semble y avoir une certaine ambiguïté dans les termes "cache" et "cache" et cela m'a amené à être confus quant à sa signification dans différents cas. Que vous parliez de la mise en cache d'applications ou de bases de données, d'un processeur, etc., et de ce que cela signifie.
Qu'est-ce que la mise en cache et quels sont les différents types?
À partir du contexte, je peux en avoir une idée. pour stocker une valeur souvent récupérée dans la mémoire principale et ont quicklook up l'accès à celui-ci. Cependant, qu'est-ce que c'est vraiment?
Ce mot semble être utilisé dans de nombreux contextes avec une signification légèrement différente (unité centrale de traitement, base de données, application, etc.) et je cherche vraiment à le clarifier.
Existe-t-il une distinction entre le fonctionnement de la mise en cache dans vos applications et celui de votre base de données?
Quand quelqu'un dit qu'il a trouvé un morceau de code qui ferait mal la mise en cache et après qu'ils l'aient corrigé, cela s'est amélioré la vitesse de leur application, quels sont-ils parler de?
Le programme cache-t-il quelque chose? cela se fait automatiquement? Comment faire vous autorisez la mise en cache de valeurs dans votre fichier programmes? J'ai souvent lu les utilisateurs sur ce site dit qu'ils ont mis en cache une valeur dans leur application, je suis assis ici et Je me demande ce qu'ils veulent dire.
Aussi, qu'est-ce que cela signifie vraiment quand quelqu'un parle de base de données la mise en cache? Est-ce simplement une fonctionnalité ils allument dans leur base de données? Faire vous devez explicitement mettre en cache les valeurs ou la base de données choisit-elle celles à cache pour vous?
Comment puis-je commencer à mettre en cache des éléments moi-même pour améliorer les performances?
Pouvez-vous me donner quelques exemples de la façon dont je peux commencer à mettre en cache des valeurs dans mes applications ? Ou encore, est-ce quelque chose qui est déjà fait, sous le capot et je dois simplement écrire mon code d'une manière particulière pour permettre la "mise en cache"?
Qu'en est-il de la mise en cache de la base de données, comment puis-je commencer? J'ai entendu parler de choses comme Memcache. Ce type d’utilitaire est-il requis pour la mise en cache dans les bases de données?
Je cherche à faire une bonne distinction entre la mise en cache dans les applications et les bases de données, comment elles sont utilisées et comment elle est mise en œuvre dans les deux cas.
La mise en cache consiste simplement à stocker des données dans un magasin hautes performances (généralement de la mémoire) et à les extraire de manière explicite ou implicite.
Laisse-moi expliquer. L'accès à la mémoire est plus rapide qu'un fichier, une URL distante (généralement), une base de données ou tout autre magasin d'informations externe que vous aimez. Par conséquent, si le fait d'utiliser l'une de ces ressources externes est significatif , vous pouvez tirer parti de la mise en cache pour améliorer les performances.
Knuth a dit une fois que l'optimisation prématurée est la racine de tout mal. Eh bien, la mise en cache prématurée est la source de tous les maux de tête en ce qui me concerne. Ne résolvez pas un problème tant que vous n'avez pas un problème. Chaque décision que vous prendrez a un coût que vous devrez payer pour la mettre en œuvre maintenant et la redemander pour la changer plus tard. Ainsi, plus vous pourrez retarder la création d'une déion et améliorer votre système, mieux ce sera.
Donc, d’abord, identifiez que vous avez réellement un problème et où il se trouve . Le profilage, la journalisation et d'autres formes de tests de performance vous aideront ici. Je ne saurais trop insister sur l’importance de cette étape. Le nombre de fois où j'ai vu des gens "optimiser" quelque chose qui ne pose pas de problème est renversant.
Ok, donc vous avez un problème de performance. Supposons que vos pages exécutent une requête qui prend beaucoup de temps. Si c'est une lecture, vous avez plusieurs options:
S'il s'agit d'une mise à jour (ou si des mises à jour doivent être reflétées dans votre cache de lecture), c'est un peu plus compliqué car il n'est pas bon d'avoir une ancienne valeur dans le cache et une valeur plus récente dans la base de données, de sorte que vous fournissez ensuite vos pages. avec une vue incohérente des données. Mais grosso modo, il existe quatre approches:
Laquelle des méthodologies ci-dessus que vous choisirez dépendra beaucoup de vos exigences, des technologies que vous utilisez et de tout un ensemble d'autres facteurs (par exemple, la prise en charge du clustering et du basculement est-elle nécessaire?).
Il est difficile d’être plus précis que cela et de vous donner des conseils sur ce qu’il faut faire sans connaître beaucoup plus de détails sur votre problème (comme si vous aviez ou non un problème).
Vous en apprendrez probablement sur la mise en cache dans le contexte d'applications Web. En raison de la nature du Web, la mise en cache peut faire une grande différence en termes de performances.
Considérer ce qui suit:
Une demande de page Web parvient au serveur Web, qui la transmet au serveur d'applications, qui exécute du code qui restitue la page, qui doit ensuite se tourner vers la base de données pour récupérer les données de manière dynamique.
Ce modèle ne s'adapte pas bien, car à mesure que le nombre de requêtes pour la page augmente, le serveur doit refaire la même chose encore et encore, pour chaque requête.
Cela devient encore plus problématique si le serveur Web, le serveur d'applications et la base de données utilisent un matériel différent et communiquent via le réseau.
Si vous avez un grand nombre d'utilisateurs qui consultent cette page, il est logique de ne pas accéder à la base de données pour chaque demande. Au lieu de cela, vous recourez à la mise en cache à différents niveaux.
Cache de résultats
La mise en cache du jeu de résultats stocke les résultats d'une requête de base de données avec la requête dans l'application. Chaque fois qu'une page Web génère une requête, les applications vérifient si les résultats sont déjà mis en cache et, le cas échéant, les extraient d'un ensemble de données en mémoire. L'application doit encore rendre la page.
Cache de composants
Une page Web est composée de différents composants - des pagelets ou ce que vous souhaitez appeler. Une stratégie de mise en cache de composant doit savoir quels paramètres ont été utilisés pour demander le composant. Par exemple, une petite barre "Dernières nouvelles" sur le site utilise la localisation géographique ou les préférences de l'utilisateur pour afficher les informations locales. Par conséquent, si les nouvelles pour un emplacement sont mises en cache, le composant n'a pas besoin d'être rendu et peut être extrait d'un cache.
Cache de page
Une stratégie de mise en cache de pages entières consiste à stocker la chaîne de requête et/ou les paramètres d’en-tête avec le code HTML entièrement restitué. Le système de fichiers est assez rapide pour cela. Pour un serveur Web, la lecture d'un fichier est toujours beaucoup moins coûteuse que d'appeler le serveur d'applications pour obtenir le rendu de la page. Dans ce cas, chaque utilisateur qui envoie la même chaîne de requête obtiendra le même contenu mis en cache.
La combinaison intelligente de ces stratégies de mise en cache est le seul moyen de créer des applications Web réellement évolutives pour un grand nombre d'utilisateurs simultanés. Comme vous pouvez facilement le constater, le risque potentiel est que si un élément du contenu du cache ne peut pas être identifié de manière unique par sa clé, les utilisateurs commenceront à voir le mauvais contenu. Cela peut devenir assez compliqué, en particulier lorsque les utilisateurs ont des sessions et qu'il existe un contexte de sécurité.
Je connais deux significations.
Le premier est application en cache. À ce moment-là, si les données sont lentes à obtenir quelque part (par exemple sur le réseau) ou à calculer, l’application met en cache une copie des données (de sorte qu’elle n’a pas besoin de les récupérer ou de recalculer: c’est déjà mis en cache). L'implémentation d'un cache nécessite un peu de logiciel d'application supplémentaire (la logique d'utilisation du cache) et une mémoire supplémentaire (dans laquelle stocker les données mises en cache).
C'est la "mise en cache" utilisée lorsque vous citez ici:
À partir du contexte, je peux en avoir une idée, stocker une valeur souvent extraite dans la mémoire principale et y accéder rapidement.
Un autre exemple est CPU Cache, décrit dans cet article de Wikipedia . La mise en cache de la CPU se fait automatiquement. Si vous lisez beaucoup à partir d'une petite quantité de mémoire, le processeur peut alors effectuer la plupart de ces lectures à partir de son cache. OTOH Si vous lisez une grande quantité de mémoire, celle-ci ne peut pas tenir dans le cache et le processeur doit passer plus de temps à travailler avec la mémoire plus lente.
C'est la "mise en cache" utilisée lorsque vous citez ici:
Quand quelqu'un dit avoir trouvé un morceau de code qui ferait du mal à la mise en cache et après l'avoir corrigé, la vitesse de son application s'est améliorée, de quoi parle-t-elle?
Cela signifie qu'ils ont trouvé un moyen de réorganiser leur code afin de causer moins de manquements de cache .
En ce qui concerne la mise en cache de la base de données, je ne sais pas.
Il y a quelques problèmes.
L'un est la granularité. Votre application peut avoir des niveaux de mise en cache très fins, en plus de ce que fait la base de données. Par exemple, la base de données est susceptible de simplement mettre en cache des pages de données, pas nécessairement des lignes spécifiques.
Une autre chose est que l'application peut stocker des données dans son format "natif", alors que la base de données ne met évidemment en cache que dans son format interne.
Exemple simple.
Supposons que vous ayez un utilisateur dans la base de données, constitué des colonnes suivantes: USERID
, FIRSTNAME
, LASTNAME
. Très simple.
Vous souhaitez charger un utilisateur, USERID=123
, dans votre application. Quelles sont les étapes à suivre?
SELECT * FROM USER WHERE USERID = ?
)USERID
en un entier, par exemple, les noms en chaînes).Il est probable que le cache de la base de données mette en cache les étapes 2 et 3 (c’est-à-dire un cache d’instructions, afin d’analyser ou de replanifier la requête) et met en cache les blocs de disque réels.
Alors, voici la clé. Votre utilisateur, USER ID 123
, nom JESSE JAMES
. Vous pouvez voir que ce n'est pas beaucoup de données. Mais la base de données met en cache des blocs de disque. Vous avez le bloc d'indexation (avec le 123
dessus), puis le bloc de données (avec les données réelles et toutes les autres lignes qui tiennent sur ce bloc). Ainsi, ce qui est nominalement, disons, 60 à 70 octets de données a en réalité un effet de mise en cache et de données sur le DB de, probablement, de 4 à 16 Ko (dépend de la taille du bloc).
Le bon côté? Si vous avez besoin d'une autre ligne à proximité (par exemple, USER ID = 124
), les cotes sont élevées, l'index et les données sont déjà mises en cache.
Mais même avec cette mise en cache, vous devez toujours payer le coût pour déplacer les données sur le fil (et c'est toujours le cas sur le fil à moins que vous n'utilisiez une base de données locale, alors c'est du bouclage), et vous «décomposez» les données . En d’autres termes, il convertit les bits de la base de données en bits de langage, en bits d’application.
Maintenant, une fois que l'application obtient son USER ID 123
, elle insère la valeur dans une carte de hachage de longue durée.
Si l'application le souhaite à nouveau, elle recherche dans la carte locale, dans le cache de l'application, et enregistre les coûts de recherche, de transport de fil et de marshalling.
Le côté obscur de la mise en cache des applications est la synchronisation. Si quelqu'un entre et fait un UPDATE USER SET LASTNAME="SMITH" WHERE USERID=123
, votre application ne le "sait pas" et le cache est donc sale.
Il y a donc beaucoup de détails dans la gestion de cette relation pour que l'application reste synchronisée avec la base de données.
Avoir beaucoup de cache de base de données est très pratique pour les requêtes volumineuses sur un ensemble de données "à chaud". Plus vous avez de mémoire, plus vous avez de données "chaudes". Jusqu'au point où vous pouvez mettre en cache l'intégralité de la base de données dans la RAM, vous éliminez le délai d'E/S (au moins pour les lectures) du déplacement des données du disque vers une mémoire tampon RAM. Mais vous avez encore les coûts de transport et de préparation.
L'application peut être beaucoup plus sélective, par exemple mettre en cache des sous-ensembles de données plus limités (les DB ne mettent que des blocs en cache) et avoir les données "plus proches" de l'application pour obtenir de bien meilleures performances.
L'inconvénient est que tout n'est pas mis en cache dans l'application. La base de données a tendance à stocker les données plus efficacement, globalement, que l'application. Il vous manque également un langage de "requête" sur les données mises en cache de votre application. La plupart des gens se cachent simplement via une simple clé et partent de là. Facile à trouver USER ID 123
, plus difficile pour "TOUS LES UTILISATEURS NOMMÉS JESSE".
La mise en cache de la base de données a tendance à être "libre", vous définissez un numéro de tampon et le SGBD gère le reste. Faible impact, réduit les délais d'E/S et de disque globaux.
La mise en cache d'application est, bien, spécifique à l'application.
Cela fonctionne très bien pour les données "statiques" isolées. C'est très facile. Chargez un tas de choses dans les tables de recherche au démarrage et redémarrez l'application si elles changent. C'est facile à faire.
Après cette complexité commence à augmenter à mesure que vous ajoutez dans la logique "sale", etc.
Mais tout se résume à ce que, tant que vous avez une API de données, vous pouvez mettre en cache de manière incrémentielle.
Ainsi, tant que vous appelez getUser(123)
partout plutôt que d'appuyer sur la base de données, vous pourrez revenir ultérieurement et ajouter la mise en cache à getUser
sans impacter votre code.
Donc, je suggère toujours une sorte de couche d'accès aux données dans le code de chacun, afin de fournir cette couche d'abstraction et d'interception.
la mise en cache prend le résultat d'un algorithme long ou intensif en CPU et enregistre la réponse afin que vous n'ayez pas à réexécuter l'algorithme, vous réutilisez simplement le résultat.
Le concept de cache est un terme surchargé ici. Je ne connais pas les détails de la mise en cache de bases de données.
Dans les applications, il existe deux utilisations du terme.
Quand quelqu'un dit qu'il a trouvé un morceau de code qui ferait mal la mise en cache et après qu'ils l'aient corrigé, cela s'est amélioré la vitesse de leur application, quels sont-ils parler de?
Dans ce cas, ils font référence au cache du processeur.
Le cache du processeur est une mémoire sur le processeur beaucoup plus rapide que la RAM, mais elle ne dispose pas d'un accès aléatoire. Ce que le processeur décide de charger dans le cache peut devenir un peu compliqué. Voir Ulrich Dreppers Ce que tout programmeur devrait savoir sur la mémoire pour de nombreux détails.
Faire attention au cache du processeur peut très bien accélérer les choses - vous devez juste accorder un peu plus d'attention à l'endroit où les objets vont être placés les uns par rapport aux autres dans la mémoire physique et à quel moment ils seront probablement utilisés.
Un exemple (probablement aussi un anti-motif pour la maintenabilité) est que si vous avez un tableau de structures et que vous faites beaucoup de bouclage sur les membres de la structure, vous serez peut-être mieux servi avec une structure où les champs sont tous des tableaux. Si les données en boucle sont contiguës en mémoire, vous avez plus de chances de ne pas bouleverser le cache.
Toutes sortes d'effets peuvent affecter l'efficacité de l'utilisation de votre cache: prédiction de branche pour le code chargé dans le cache, taille et alignement des structures de données et des modèles d'accès, où et quand déclarer les variables locales à placer dans la pile.
L'autre utilisation courante du terme pour la programmation d'applications peut être réalisée par quelque chose appelé memoization . L'exemple factoriel sur cette page wikipedia explique les choses mieux que ce que j'aurais fait.
La mise en cache dans les bases de données est généralement une fonction de la base de données et elle est gérée automatiquement par la base de données. La mise en cache dans les applications va varier d’une plate-forme à l’autre.
Un cache d'objets est un mécanisme que vous pouvez utiliser pour mettre en mémoire les objets couramment utilisés, de sorte que vous n'avez pas à payer le coût pour récupérer les données et les recréer. Ceci est généralement géré via du code et varie en fonction de la solution de mise en cache que vous utilisez.
Il existe des solutions de cache distribué qui impliquent la configuration de services sur plusieurs serveurs pour vous donner une sorte de batterie de cache. Cela offre une évolutivité et une redondance. Les clients peuvent demander les informations mises en cache sur le réseau. Encore une fois c'est une procédure manuelle dans votre code. Memcached est un exemple de fournisseur de cache distribué:
http://www.danga.com/memcached/
Un exemple d'un type spécifique de mise en cache serait la mise en cache asp.net. Asp.net prend en charge plusieurs types de cache. Il y a le cache d'objets traditionnel (qui peut être utilisé dans tous les types d'applications .net, pas seulement les sites Web). Il existe également des fonctionnalités de mise en cache qui vous permettent de configurer des pages et des contrôles utilisateur pour mettre automatiquement en cache leur sortie. Cela ne met pas en cache les données, il met en cache le résultat final (le HTML de la page) et le sert lorsque l'utilisateur demande la même page avec les mêmes paramètres de chaîne de requête qu'un utilisateur précédent.
C'est probablement plus facile que vous ne pouvez l'imaginer - et c'est pourquoi les gens essaient de le fermer.
Cela signifie simplement de stocker les valeurs dans votre mémoire plutôt que de revenir à la base de données à chaque fois.
Il y a beaucoup de façons de le faire, mais le concept lui-même est trivial.
Edit: Cela peut être fait à TOUT niveau aussi - tout ce qui prend du temps peut être mis en cache quelque part que vous pouvez obtenir plus rapidement.
La mise en cache ne s'applique pas nécessairement uniquement aux valeurs «souvent récupérées», mais à tout ce sur quoi vous pouvez gagner du temps en réduisant le nombre de fois que vous le recalculez. Un exemple simple qui me vient à l’esprit est le calcul de la séquence fibonacci . L'implémentation récursive la plus simple ressemble à ceci (en code psuedo):
function f(n)
if n < 2 then
return n;
return f(n - 1) + f(n - 2)
Cela peut être amélioré avec la mise en cache pour empêcher le recalcul des valeurs déjà connues:
fib_cache = {}
function f(n)
if n < 2 then
return n;
if fib_cache.contains(n) then
return fib_cache[n]
fib_cache[n] = f(n - 1) + f(n - 2)
return fib_cache[n]