La mise en cache est l'un des moyens les plus courants d'optimiser les performances du système. En ajoutant du cache avant les composants chronophages (tels que les bases de données), vous pouvez réduire le nombre d'appels réels et le temps de réponse. Mais réfléchissez-y à deux fois avant d’introduire la mise en cache.
L'obtention de ressources via Internet est lente et coûteuse. À cette fin, le protocole HTTP comprend une partie de contrôle du cache afin que le client HTTP puisse mettre en cache et réutiliser les ressources précédemment obtenues, optimisant ainsi les performances et améliorant l'expérience. Bien que la partie contrôle du cache de HTTP subisse quelques changements à mesure que le protocole évolue. Mais je pense qu'en tant que programmeur back-end, lors du développement de services Web, vous devez uniquement prêter attention à l'en-tête de requête If-None-Match, à l'en-tête de réponse ETag et à l'en-tête de réponse Cache-Control. Parce que ces trois en-têtes HTTP peuvent répondre à vos besoins et que la plupart des navigateurs actuels prennent en charge ces trois en-têtes HTTP. Tout ce que nous avons à faire est de nous assurer que chaque réponse du serveur fournit les directives d'en-tête HTTP correctes pour indiquer au navigateur quand et pendant combien de temps il peut mettre la réponse en cache.
Où est la cache ?
Il existe trois rôles dans la figure ci-dessus : navigateur, proxy Web et serveur. Comme le montre la figure, le cache HTTP existe dans le navigateur et le proxy Web. Bien sûr, il existe également divers caches à l'intérieur du serveur, mais il ne s'agit plus du cache HTTP dont il sera question dans cet article. Le contrôle de cache Http est un accord visant à contrôler les politiques d'utilisation du cache des navigateurs et des proxys Web en définissant différents en-têtes de réponse Cache-Control, et à contrôler le cache en définissant l'en-tête de requête If-None-Match et l'en-tête de réponse ETag. .Vérifiez l'efficacité.
En-tête de réponse ETag
Le nom complet d'ETag est Entity Tag, qui est utilisé pour identifier une ressource. Dans l'implémentation spécifique, l'ETag peut être la valeur de hachage de la ressource ou un numéro de version géré en interne. Quoi qu’il en soit, ETag devrait être capable de refléter les changements dans le contenu des ressources, ce qui constitue la base du bon fonctionnement de la mise en cache HTTP.
Comme le montre l'exemple ci-dessus, lorsque le serveur renvoie une réponse, il inclut généralement des informations de métadonnées sur la réponse dans l'en-tête Http, dont ETag est l'une d'entre elles. . Dans cet exemple, l'ETag avec la valeur x1323ddx est renvoyé. Lorsque le contenu de la ressource/du fichier change, le serveur doit renvoyer un ETag différent.
En-tête de requête If-None-Match
Pour la même ressource, comme /file dans l'exemple précédent, après avoir effectué une requête, le navigateur dispose déjà d'une version du contenu de /file, et cette version d'ETag lorsque l'utilisateur aura besoin de cette ressource la prochaine fois et que le navigateur demandera à nouveau au serveur, l'en-tête de requête If-None-Match peut être utilisé pour indiquer au serveur qu'il dispose déjà d'un fichier / avec un ETag de x1323ddx, donc , si /file sur le serveur n'a pas changé, c'est-à-dire si l'ETag de /file sur le serveur est également x1323ddx, le serveur ne renverra pas le contenu de /file, mais renverra une réponse 304, indiquant au navigateur que la ressource n'a pas changé, le cache est valide.
Comme le montre l'exemple ci-dessus, après avoir utilisé If-None-Match, le serveur n'a besoin que d'une petite réponse pour obtenir le même résultat, optimisant ainsi les performances.
En-tête de réponse Cache-Control
Chaque ressource peut définir sa propre stratégie de mise en cache via l'en-tête Http Cache-Control contrôle qui peut mettre en cache la réponse et dans quelles conditions combien de temps. Les requêtes les plus rapides sont celles qui n'ont pas besoin de communiquer avec le serveur : avec une copie locale de la réponse, on évite toute latence du réseau et le coût des transferts de données. À cette fin, la spécification HTTP permet aux serveurs de renvoyer une série de directives Cache-Control différentes qui contrôlent la manière dont les navigateurs ou autres caches relais mettent en cache une réponse et pendant combien de temps.
L'en-tête Cache-Control est défini dans la spécification HTTP/1.1, remplaçant les en-têtes précédemment utilisés pour définir les politiques de mise en cache des réponses (telles que Expires). Tous les navigateurs actuels prennent en charge Cache-Control, son utilisation est donc suffisante.
Ici, je vais présenter les instructions courantes qui peuvent être définies dans Cache-Control.
max-age
Cette directive spécifie la durée maximale (en secondes) pendant laquelle la réponse obtenue peut être réutilisée à partir de la requête en cours. Par exemple : Cache-Control:max-age. =60 signifie que la réponse peut être mise en cache et réutilisée pendant 60 secondes supplémentaires. Il convient de noter que dans le délai spécifié par max-age, le navigateur n'enverra aucune requête au serveur, y compris les demandes pour vérifier si le cache est valide, c'est-à-dire que si pendant cette période, les ressources sur le serveur changent pendant cette période, le navigateur ne sera pas averti et utilisera l'ancienne version des ressources. Par conséquent, vous devez être prudent lors de la définition de la durée du cache.
public et privé
Si public est défini, cela signifie que la réponse peut être mise en cache dans le navigateur ou dans n'importe quel proxy Web relayé. Public est la valeur par défaut, c'est-à-dire Cache-Control. :max-age=60 est équivalent à Cache-Control:public, max -age=60 Lorsque le serveur est défini sur privé comme Cache-Control: private, max-age=60, cela signifie que seul le navigateur de l'utilisateur peut mettre en cache les réponses privées et qu'aucun proxy Web relais n'est autorisé à le mettre en cache – Par exemple, le navigateur d'un utilisateur peut mettre en cache une page HTML contenant les informations privées de l'utilisateur, mais un CDN ne peut pas la mettre en cache si le serveur ne définit aucun paramètre. cache dans la réponse, c'est-à-dire Cache-Control: no-cache, le navigateur doit d'abord confirmer auprès du serveur si la réponse renvoyée a été modifiée avant d'utiliser la ressource mise en cache. Si la ressource n'a pas été modifiée, cela peut éviter le téléchargement. la réponse précédente. Ceci est obtenu grâce à l'en-tête de requête If-None-match et à l'en-tête de réponse ETag introduit ci-dessus Il convient de noter que le nom no-cache est un peu trompeur. après avoir défini l'absence de cache, le navigateur ne met plus les données en cache, mais lors de l'utilisation des données mises en cache, le navigateur doit d'abord confirmer si les données sont toujours cohérentes avec le serveur si l'absence de cache est définie et que l'implémentation d'ETag ne reflète pas. les ressources changent, cela se produira. Cela fera que les données mises en cache du navigateur ne seront jamais mises à jour no-storeSi le serveur définit le no-store, c'est-à-dire Cache-Control:no-. stocker, dans la réponse, puis le navigateur Le serveur et tout proxy Web relayé ne stockeront pas les données correspondantes cette fois-ci. Lorsque la ressource sera demandée la prochaine fois, le navigateur ne pourra que demander à nouveau au serveur et lire à nouveau la ressource sur le serveur. Comment déterminer une ressource. Qu'en est-il de la stratégie Cache-Control des ressources L'organigramme suivant peut vous aider. Erreurs courantesMise en cache au démarrageParfois, nous constaterons que l'application démarre très lentement, Il a finalement été découvert que l'un des services dépendants mettait beaucoup de temps à répondre. Que dois-je faire ?
D'une manière générale, lorsqu'on rencontre ce genre de problème, cela signifie que le service dépendant ne peut pas répondre à la demande. S'il s'agit d'un service tiers et que le contrôle n'est pas entre nos mains, nous pouvons introduire la mise en cache à ce moment-là. Le problème avec l'introduction de la mise en cache à l'heure actuelle est que la stratégie d'invalidation du cache est difficile à mettre en œuvre, car l'intention initiale de la conception du cache est de demander le moins de services dépendants possible. Mise en cache prématuréeLe "précoce" évoqué ici n'est pas le cycle de vie de l'application, mais le cycle de développement. Parfois, nous verrons que certains développeurs ont estimé les goulots d'étranglement du système dès les premiers stades de développement et ont introduit la mise en cache. En fait, cette approche masque d’éventuels points d’optimisation des performances. Quoi qu'il en soit, la valeur de retour de ce service sera alors mise en cache. Pourquoi devrais-je passer du temps à optimiser cette partie du code ? Mise en cache intégréeLe "S" dans le principe SOLID signifie - Principe de responsabilité unique. Lorsque l'application intègre le module de cache, le module de cache et la couche de service sont fortement couplés et ne peuvent pas fonctionner indépendamment sans la participation du module de cache. Mettre en cache tout le contenuParfois, afin de réduire le délai de réponse, vous pouvez ajouter aveuglément une mise en cache aux appels externes. En fait, un tel comportement peut facilement empêcher les développeurs et les responsables de se rendre compte de l'existence du module de cache, et finalement faire une mauvaise évaluation de la fiabilité des modules dépendants sous-jacents. Cache en cascadeLa mise en cache de tout, ou seulement de la majeure partie du contenu, peut entraîner la mise en cache de données contenant d'autres données mises en cache. Si l'application contient cette structure de cache en cascade, cela peut conduire à une situation où le délai d'expiration du cache est incontrôlable. Le cache de niveau supérieur doit attendre que chaque niveau de cache soit invalidé et mis à jour avant que les données finales renvoyées ne soient complètement mises à jour. Le cache ne peut pas être actualiséNormalement, le middleware de cache fournira un outil pour actualiser le cache. Par exemple, avec Redis, les responsables peuvent supprimer certaines données ou même actualiser l'intégralité du cache grâce aux outils qu'il fournit.Cependant, certains caches temporaires peuvent ne pas contenir de tels outils. Par exemple, les caches qui stockent simplement des données dans le contenu ne permettent généralement pas aux outils externes de modifier ou de supprimer le contenu mis en cache. À l'heure actuelle, si des données de cache anormales sont détectées, le personnel de maintenance ne peut que redémarrer le service, ce qui augmentera considérablement les coûts d'exploitation et de maintenance ainsi que le temps de réponse. De plus, certains caches peuvent écrire le contenu du cache dans le système de fichiers à des fins de sauvegarde. À ce stade, en plus de redémarrer le service, vous devez également vous assurer que la sauvegarde du cache sur le système de fichiers est supprimée avant le démarrage de l'application.
L'impact de la mise en cache
Les erreurs courantes mentionnées ci-dessus pouvant résulter de l'introduction de la mise en cache, ces problèmes ne seront pas pris en compte dans un système sans cache.
Le déploiement d'un système qui s'appuie fortement sur le cache peut passer beaucoup de temps à attendre l'expiration du cache. Par exemple, si vous mettez du contenu en cache via un CDN, l'actualisation de la configuration du CDN et du contenu mis en cache par le CDN peut prendre plusieurs heures après la publication du système.
De plus, donner la priorité au cache lorsque des goulots d'étranglement de performances surviennent entraînera la dissimulation des problèmes de performances et leur non-résolution véritable. En fait, le temps passé à régler le code n’est souvent pas très différent de l’introduction de composants de mise en cache.
Enfin, pour les systèmes qui incluent des composants de mise en cache, le coût du débogage augmente considérablement. Il arrive souvent que le code soit tracé pendant une demi-journée et que les données résultantes proviennent du cache et n'ont rien à voir avec les composants dont devrait dépendre la logique réelle. Le même problème peut également survenir une fois que tous les scénarios de test pertinents ont été exécutés, mais que le code modifié n'a pas réellement été testé.
Comment faire bon usage du cache ?
Abandonnez la mise en cache !
Eh bien, la mise en cache est souvent inévitable. Dans les systèmes basés sur Internet, il est difficile d'éviter complètement l'utilisation du cache. Même l'en-tête du protocole http contient la configuration du cache : Cache-Control : max-age=xxx.
Comprendre les données
Si vous souhaitez mettre en cache des données, vous devez d'abord comprendre la stratégie de mise à jour des données. Ce n'est qu'en comprenant clairement quand les données doivent être mises à jour que nous pouvons utiliser l'en-tête If-Modified-Since pour déterminer si les données demandées par le client doivent être mises à jour. Devons-nous simplement renvoyer une réponse 304 Not Modified et laisser le client les réutiliser. données locales mises en cache précédentes, ou devrions-nous renvoyer les dernières données ? De plus, afin de mieux utiliser le cache dans le protocole http, il est recommandé de distinguer les versions des données, ou d'utiliser eTag pour marquer la version des données mises en cache.
Optimisez les performances au lieu d'utiliser la mise en cache
Comme mentionné précédemment, l'utilisation de la mise en cache masque souvent des problèmes de performances potentiels. Utilisez des outils d'analyse des performances autant que possible pour trouver la véritable cause de la lenteur de réponse de votre application et y remédier. Par exemple, réduisez les appels de code invalides, optimisez SQL selon le plan d'exécution SQL, etc.
Ci-dessous le code pour vider tous les caches de l'application
/* * 文 件 名: DataCleanManager.java * 描 述: 主要功能有清除内/外缓存,清除数据库,清除sharedPreference,清除files和清除自定义目录 */ package com.test.DataClean; import java.io.File; import android.content.Context; import android.os.Environment; /** * 本应用数据清除管理器 */ public class DataCleanManager { /** * 清除本应用内部缓存(/data/data/com.xxx.xxx/cache) * * @param context */ public static void cleanInternalCache(Context context) { deleteFilesByDirectory(context.getCacheDir()); } /** * 清除本应用所有数据库(/data/data/com.xxx.xxx/databases) * * @param context */ public static void cleanDatabases(Context context) { deleteFilesByDirectory(new File("/data/data/" + context.getPackageName() + "/databases")); } /** * 清除本应用SharedPreference(/data/data/com.xxx.xxx/shared_prefs) * * @param context */ public static void cleanSharedPreference(Context context) { deleteFilesByDirectory(new File("/data/data/" + context.getPackageName() + "/shared_prefs")); } /** * 按名字清除本应用数据库 * * @param context * @param dbName */ public static void cleanDatabaseByName(Context context, String dbName) { context.deleteDatabase(dbName); } /** * 清除/data/data/com.xxx.xxx/files下的内容 * * @param context */ public static void cleanFiles(Context context) { deleteFilesByDirectory(context.getFilesDir()); } /** * 清除外部cache下的内容(/mnt/sdcard/android/data/com.xxx.xxx/cache) * * @param context */ public static void cleanExternalCache(Context context) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { deleteFilesByDirectory(context.getExternalCacheDir()); } } /** * 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除 * * @param filePath */ public static void cleanCustomCache(String filePath) { deleteFilesByDirectory(new File(filePath)); } /** * 清除本应用所有的数据 * * @param context * @param filepath */ public static void cleanApplicationData(Context context, String... filepath) { cleanInternalCache(context); cleanExternalCache(context); cleanDatabases(context); cleanSharedPreference(context); cleanFiles(context); for (String filePath : filepath) { cleanCustomCache(filePath); } } /** * 删除方法 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理 * * @param directory */ private static void deleteFilesByDirectory(File directory) { if (directory != null && directory.exists() && directory.isDirectory()) { for (File item : directory.listFiles()) { item.delete(); } } } }
Résumé
La mise en cache est un outil très utile, mais on peut facilement en abuser. N'utilisez pas la mise en cache jusqu'à la dernière minute et donnez la priorité à d'autres moyens d'optimiser les performances des applications.