Pratique d'architecture de mise en cache multicouche dans le projet VODK
Comment le site d'agrégation de vidéos tv.odkkk.com a transformé plusieurs sources de données instables en un site fluide - parlons de l'idée de mise en cache multicouche qui se cache derrière.
À quoi sert ce site ?
tv.odkkk.com est un petit site que j’ai créé. En termes simples, il s’agit d’un portail d’agrégation vidéo. Il ne stocke pas lui-même les sources de films, mais collecte le contenu de plusieurs sites de ressources sur Internet, afin que les utilisateurs n’aient plus à faire des allers-retours pour trouver des films.
Il fait principalement trois choses :
- Recherchez sur tout le réseau à la fois : saisissez le titre d’un film, accédez à plusieurs sites de ressources en arrière-plan et demandez à nouveau, fusionnez les résultats, supprimez les doublons, triez-les et revenez. Les utilisateurs voient une liste propre, plutôt que de voir des titres collés entre cinq ou six sites.
- Informations complètes : Les données renvoyées par la station de ressources sont généralement très approximatives, souvent uniquement le titre et l’adresse de lecture. Je les apporterai à Douban pour vérifier les notes, les présentations, les affiches et compléter les informations sur Bangumi afin que chaque résultat soit correct.
- N’oubliez pas où vous avez vu : la progression de la lecture, l’historique de recherche et les favoris suivent tous le compte et ne seront pas perdus lors du changement de page.
Cela ne semble pas compliqué, mais lorsque vous le faites, vous constatez que le problème ne vient pas de la fonction elle-même, mais du fait que la source de données est trop peu fiable. Le site de ressources expire fréquemment et est bloqué. Douban obtient 403 lorsqu’il navigue trop, mais les recommandations de la page d’accueil ne peuvent pas toujours afficher le contenu de la semaine dernière. Si vous accédez directement à la source pour extraire des données à chaque fois que vous cliquez dessus, l’expérience sera très mauvaise - parfois elle s’ouvre en quelques secondes, parfois elle prend beaucoup de temps à tourner et parfois elle signale directement une erreur.
Par conséquent, la clé pour savoir si ce site Web peut être utilisé n’est pas à quoi ressemble le front-end, mais si le « vent » en amont peut être caché dans la couche de données, afin que les utilisateurs aient toujours le sentiment qu’il est fluide. C’est le problème que l’architecture de cache suivante va résoudre.
Idée de base : plus les données sont proches de l’utilisateur, mieux c’est
L’ensemble de la couche de données emprunte l’idée du cache CPU - du plus rapide au plus lent, couche par couche :
请求 → 边缘缓存 → 热数据缓存 → 持久存储 → 上游源站
Chaque niveau ne pose des questions que lorsqu’il manque et revient directement lorsqu’il atteint. Cela maximise non seulement la réponse, mais minimise également la pression sur l’amont. Parlons-en couche par couche.
Première couche : cache périphérique
Le plus externe est le nœud périphérique CDN. Pour une même requête, tant que quelqu’un l’a demandée récemment, le nœud Edge vous renverra directement la dernière réponse telle quelle, sans atteindre du tout mon serveur. C’est comme s’approvisionner en produits les plus vendus à la cantine du rez-de-chaussée, sans avoir à se rendre à chaque fois à l’entrepôt principal.
Voici une petite astuce : laissez les réponses expirées être renvoyées en premier et mises à jour silencieusement en arrière-plan. Ce que l’utilisateur obtient, ce sont les “anciennes données de la seconde précédente”, mais elles seront actualisées la seconde suivante - elles démarrent toujours en quelques secondes, il n’est donc pas nécessaire d’attendre que la source soit renvoyée.
Deuxième couche : cache de données chaudes
Le cache Edge manque et la requête atteint la couche application. Il existe ici un cache rapide au niveau de la mémoire, dédié aux données fréquemment consultées récemment.
Le plus intelligent, c’est qu’il jugera de sa propre popularité : plus une donnée est consultée, plus elle sera conservée longtemps. Les données froides qui viennent d’arriver ne sont conservées qu’une minute, mais si elles commencent à être cliquées à plusieurs reprises, elles seront automatiquement étendues à quelques minutes, dix minutes ou une demi-heure. À son tour, le contenu que personne ne lit expirera rapidement et prendra de la place.
Le résultat est le suivant : plus le contenu est populaire, plus il sera permanent, et le contenu impopulaire sera naturellement éliminé. Inutile de deviner « lesquels conserver », les visiteurs voteront eux-mêmes.
Il y a un autre détail : lors de l’écriture des données, je sauvegarderai une “copie de sauvegarde”, et la durée de validité est cinq fois supérieure à celle de l’original. Si la copie originale est expirée et est renvoyée à la source, l’utilisateur peut au moins récupérer les anciennes données dans leur intégralité au lieu de regarder le cercle de chargement.
La troisième couche : le stockage persistant
Les données du cache chaud ne disparaîtront pas vraiment après leur expiration - elles seront “réchauffées” à partir d’une couche de stockage persistant. Cette couche est sauvegardée pendant une longue période, ce qui équivaut à un instantané hors ligne : même si le site en amont est complètement indisponible aujourd’hui, j’ai toujours les données capturées la dernière fois pour le compléter. Tout au plus, l’utilisateur verra un contenu légèrement plus ancien au lieu d’une page d’erreur.
Ici, j’ai fait deux petites choses pour éviter les lancers inutiles :
Premièrement, il ne sera écrasé que si le contenu a réellement changé. Avant chaque écriture, une « empreinte digitale » est calculée et comparée. Si le contenu ne change pas, seuls le temps d’accès et le décompte sont mis à jour, sans réécrire les données elles-mêmes. De cette façon, les films populaires consultés à plusieurs reprises mais dont le contenu n’a pas changé ne seront pas inutilement écrits dans la base de données chaque jour.
Deuxièmement, les nouvelles données doivent être mises à jour. La couche de persistance est conservée en permanence, mais certaines choses ne peuvent pas être alimentées en permanence avec d’anciennes données - comme les recommandations de la page d’accueil, il serait ennuyeux de toujours afficher la liste d’il y a une semaine. Par conséquent, une durée de conservation est fixée pour chaque type de données. Par exemple, les recommandations de la page d’accueil doivent être actualisées une fois par jour et les résultats de recherche peuvent être stockés plus longtemps. Une fois la durée de conservation écoulée, même s’il existe une couche persistante, il est obligé d’aller à la source pour en extraire une autre.
La quatrième couche : station d’origine en amont
Si vous en arrivez vraiment à ce point, cela signifie que les trois premiers niveaux ont tous raté. C’est le moment de vraiment frapper à la porte de la station ressource. Les nouvelles données extraites seront placées simultanément dans le cache chaud et la couche de persistance - et répondront à l’utilisateur avant la fin de l’écriture. La prochaine fois que la même requête sera effectuée, elle sera exécutée directement depuis le cache.
Écrivez la bibliothèque à l’écart
L’écriture de données sur la couche de persistance est la méthode la plus susceptible de ralentir la réponse. J’ai donc fait l’écriture “post-asynchrone” : renvoyez d’abord les données à l’utilisateur, puis déposez-les lentement dans la base de données en arrière-plan. Même si l’écriture de la base de données échoue, cet accès ne sera pas affecté. Tout au plus, la source sera renvoyée la prochaine fois.
Si l’on sépare “si l’utilisateur estime qu’elle est rapide” et “si les données sont stockées en toute sécurité”, ce compromis en vaut la peine - si la base de données est plus lente, l’utilisateur sera indifférent, mais si la réponse est une demi-seconde plus lente, l’utilisateur sera immédiatement ennuyé.
Effet
Après avoir exécuté cette architecture, les deux points les plus intuitifs sont :
L’un est rapide. La page d’accueil s’ouvre en quelques secondes et les recherches prennent moins de cent millisecondes. La grande majorité des demandes n’atteignent jamais l’amont.
La seconde est la stabilité. Un certain site de ressources a aujourd’hui un problème, et l’utilisateur n’en a aucune idée - car il se trouve soit dans le cache chaud, soit dans la couche de persistance, mais les données sont légèrement plus anciennes. Une fois récupéré, il sera naturellement mis à jour lors de la prochaine exploration.
Écrivez à la fin
Après avoir terminé ce projet, ma vision de la « mise en cache » a beaucoup changé. Avant, je pensais que la mise en cache consistait simplement à “stocker les résultats plus rapidement la prochaine fois”, mais maintenant je pense que cela revient plutôt à digérer l’incertitude en amont pour les utilisateurs - la vitesse n’est qu’un sous-produit, la stabilité est le véritable problème à résoudre.
Une bonne stratégie de mise en cache ne consiste pas à stocker toutes les données de manière permanente, mais à permettre aux données chaudes d’être permanentes, aux données froides d’être restaurées et aux données expirées d’être actualisées.